A library that allows easy handling of various types of data in tabular form and easy manipulation and automation of the data. It supports int (32 and 64 bit), float (at least 32 bit and 64 bit), string, boolean, date and date+time.
This allows creating table with columns of different data types at run time. Each column will have a column name (column-id), display name (a description of the column) and a data type. Table can have multiple rows and columns.
Features of table
- Supports multiple columns of different data types.
- Very light weight on memory, data are stored in original form. Variants are used only for data exchange.
- Can add new column as per need.
- Supports various ways for populating newly create columns for existing rows.
- Allows transformation of existing column using smart Formula
To create a table Person with name, age, date of birth and address.
using dt = km::DataType;
km::Table person("Person",{
{"name", "Name", dt::STRING},
{"dob", "Date of birth", dt::DATE},
{"address", "Address", dt::STRING}
}, km::SortingOrder::ASCENDING);
Inserting data in the table
person.insertRow({"Keshav Sahu", {1997, 9, 25}, "Raipur, Chhattisgarh"});
person.insertRow({"Yash Sanap", {2000, 9, 22}, "Mumbai, Maharashtra"});
person.insertRow({"Bishal Bhattacharya", {2004, 1, 21}, "Kathmandu, Nepal"});
person.insertRow({"Nitesh Giri", {2003, 2, 24}, "Kathmandu, Nepal"});
Now say we forgot to add a column, let say we want to add a colum age, but it already has rows should we add it manually? or should we fill it with a fixed value for all?
Well all these options are allowed but is there a way to automatically fill them according to its dob (date of birth) columns? Answer is yes, there is two way. First one (using a compile time function):
person.addColumnF({"age", "Age", km::DataType::INT32}, [&person](auto row_index){
return km::KInt32(2022 - person.getDataWC(row_index, 1 /* dob column index*/).asDate().year)
});
Second one (using formula, so not bound with compile time)
// notice the $ sign before dob, $ is used to denote a column
person.addColumnE({"age", "Age", km::DataType::INT32}, "sub(2022, year($dob))");
If we print the data we would get
name dob address age
Bishal Bhattacharya 21/01/2004 Kathmandu, Nepal 18
Keshav Sahu 25/09/1997 Raipur, Chhattisgarh 25
Nitesh Giri 24/02/2003 Kathmandu, Nepal 19
Yash Sanap 22/09/2000 Mumbai, Maharashtra 22
Some drawbacks
- Columns can not be deleted due to dependency reason.
- No built in support for NULL values (will add later).
All tables and views can be automated with formulae. Formulae are case sensitive, type strict and compromises of only functions. It has some certain syntax, any integer number is treated as int32
, but if followed with l
or L
then it is treated as int64
. Any real number is treated as float64
, but if it is followed by f
then it is treated as float32
. Any string between ""
are treated as string while True
and False
are treated as boolean
. There is no such literals for date
and date_time
.
It follows functional practices that means function must not have any side effects. It is type strict that's why it is too fast. But for convenience function overloading is supported.
add(10,20) // gives 30 (int32)
add(10.0f, 20.343389f) // gives 20.343389 (float32)
add(10, 20.f); //error as there is no add(int32, float32) function defined!
No operators are supported so even for basic works (such as basic arithmetic) we need to use functions. See functions directory.
To refer a column in formula a $ sign before column name is used
. It is safe as it can not access the data
which is not in the current row (e.g. data from different row).
Syntax of the formula is easy
function_name(arg1, arg2, ...)
where arguments can be a literal value or a $column_name or a function itself.
Note : You must call km::initAllFnc() to load the built in functions.
Formula can also be used to create Views and for running queries See BookLibrary Example.
There's a number of functions categorized as:
- Arithmetic such as add, sub, mul, div
- Comparison such as isEqual, isGreater, isLess
- Date and DateTime such as day month year isLeapYear
- Logical such as IF AND OR
- String such as length toLower toUpper contains
- Type conversion such as toInt32, toString, toDate, toDateTime
A view is just a virtual table so it doesn't consume extra space, it doesn't copy the actual data. We can create table of any view using a filter formula.
Features of a view :
-
A virtual table that means no extra space to copy the data.
-
Always up to date (auto refresh when source table is changed!)
-
Allows modification in sorting column and order.
-
Nested view is also possible.
Let's say we want to create a view of the previous "Person" table that watches for only persons who live in Chhattisgarh (whatever city) with only "name" and "address" columns.
km::BasicView view("view name", &person, {"name","address"}, "contains(toLower($address), \"chhattisgarh\")");
//view.rowCount() == 1
std::cout << view.getDataWC(/*row index = */ 0, /* column index = */ 0).asString();
//prints : Keshav Sahu
//insert a new row in the table
person.insertRow({"Tikeshwar Sahu", 26, {1996, 2, 23}, "Kurud Chhattisgarh"});
//view is auto refreshed
std::cout << "After new insertion in the table `Person`, view holds " << view.rowCount() << " rows." << std::endl;
//prints : After new insertion in the table `Person`, view holds 2 rows.
// changing address of "Keshav Sahu"
person.setData(1,3, "Bangalore, Karnataka");
std::cout << "After data update view holds " << view.rowCount() << "row." << std::endl;
//prints : After data update view holds 1 row.
You need to create function and then register it with the FunctionStore instance.
#include <kmt/Core.hpp> // for km::Variant
#include <kmt/FunctionStore.hpp> // for km::FunctionStore
// formula equivalent of boolean isEvenNumber(KInt32 num)
km::Variant isEvenNumber(const km::Variant *args)
{
return km::KBoolean(args[0].asInt32() % 2 == 0 ? true : false);
}
// registering the function (typically in main cpp file)
km::FunctionStore::store().addEntry("isEvenNumber_i", {
/*function_ptr = */ isEvenNumber,
/*return_type = */ km::DataType::KBoolean,
/*number of arguments */ = 1});
Notice the isEvenNumber_i
, the _i
denotes that it takes a single int32 arguments. If it was isEvenNumber_iI, it would be treated as isEvenNumber(int32, int64), i denotes int32, I denotes int64, f denotes float32, F denotes float64, s denotes string, b denotes boolean, d denotes date and D denotes date_time.
See FunctionStore.hpp for more info.
For building the project visit How to build KMTableLib