This is to announce we opensourced our TeeBI Delphi library some weeks ago. Main purpose of TeeBI is to make easier to create TeeCharts, with less coding, and using in-memory queries to speed up dynamic chart repaints, which is “slow” when using server databases.
The core of TeeBI is a data structure called TDataItem, which is a simple class like TList or TDictionary, adding hierarchical support and using simple arrays internally for speed.
There are classes to import and export TDataItems from/to text, json, xml, html, files, databases, AI, web urls etc.
A sql-like engine class that performs queries with unique features like histograms and hooks to Delphi functions and events.
It works with “dimensions and measures” model and sql-like language. Output is multidimensional (like pivot tables), not only as flat tables like “select” does.
The visual part has a grid and chart controls that given a TDataItem, automatically displays it trying the “best” output analyzing the data content.
BIChart1.Data := DataItem1
If you are interested, full free sources and demos are available at Github:
That sounds interesting and is topical for us so we will take a look at some stage. One of our apps has lots of charts on-screen, containing lots of series, with lots of data points and refreshes can be slow (sometimes a data update requires refreshing many series across these charts).
uses BI.DataItem, BI.CSV, BI.Db, BI.Xml, BI.Json;
var Data1 : TDataItem;
Data1 := TBICSV.FromFile( 'mydata.csv' ); // also From TStrings, String etc
// other importing methods:
Data1 := TBIDB.From( SQLConnection1 ); // loads all tables in one line of code
Data1 := TBIJson.From ...
Data1 := TBIXML.From ... // import different formats
// import from Artificial Intelligence AI agents, like Google Gemini:
Data1 := TBIAI.From('Give me the list of the highest 10 mountains by elevation in csv format, just the list');
// from arrays, TCollection, custom Records (via RTTI):
Data1 : TTypeProvider<TCustomer>.Create(Self, MyArrayOfCustomers).Data;
// import from components with automatic detection:
Data1 := TComponentImporter.From(Self, Memo1.Lines);
Data1 := TComponentImporter.From(Self, DataSource1);
// importing from any URL, automatic detection of content format:
Data1 := TBIURLSource.From('https://www.mysite.com/get/mydata?param=123');
// queries, including group by, sort, expressions, having, sub-select, distinct, date operators etc
Data1 := TBISQL.From( Data2, 'sum(Amount) where (Customer=123) and (Product<456) group by Country, Year');
Data1 := TBISQL.From( Data2, 'ProductName, UnitPrice where UnitPrice > select Average(UnitPrice)');
Data1 := TBISQL.From( Movies, 'top 100 offset 15000 year, length');
// visualizing
BIGrid1.Data := Data1;
BIChart1.Data:= Data1;
BIGrid2.Data := Data1['Products']; // sub-tables
// importing data from a standard TeeChart Series:
Data1 := TChartData.From(Series1);
Once your Data1, Data2 etc are imported/loaded/created, they are indistinguishable, and you can mix and link them (master–>detail relationships) regardless of their origin. They live in-memory and share the same (simple) structure. When importing complex data, some type kinds aren’t supported (ie blobs) because the main purpose is to query and visualize quick. Its not a database in the traditional sense.
Do you miss any source class? (work in progress !)
Hi Paul, I can zoom monday 21st 6pm, its 10am here so its fine for me !
Strong advise, my spoken english is horrible (I never talk with anyone, just read and write). TeeBI basics are quick to explain, its old school
Thank you very much for giving me the opportunity to talk about TeeBI in your meeting !
In the meeting I talked about sub-tables in both horizontal and vertical dimensions of a grid (or chart), like pivot-tables, which can be seen here in this pic, collapsible rows and columns:
About the simple structure TDataItem, a pseudocode is:
type
TDataItem = class
Items : collection of TDataItem
Name : String <--- the "field" name
Values : array of ? (? = string, datetime, integer, double, boolean...)
end;
So a TDataItem can be a simple “field”, a “table” (array of fields), a “database” (array of tables) and so on. There is no internal discern.
Dataitem variables can then appear at many places, like in expression filters of a “where” query, as sources of grids and charts, in groupby aggregations, sorting code, exporting, etc, etc.
And about speed, typical code is 20x times faster than a Firedac memory TDataset: