Radikant-TrailBase-C

database 🗃️ driver

Device Screen

Trailbase is a promising high-performance, single-binary backend written in RUST that provides a managed SQLite database with Auth, Realtime, and file storage. This library is a lightweight C driver designed for  straightforward API, making it easy to port Trailbase integration to microcontrollers and embedded systems.

⚠️ Trailbase is currently unstable (DB corruption) therefore developing this client is paused. The Admin Gui for example show. Certain columns exist, but in the underlying database the collumns appear to be absent. Restarting the server helps but it makes development impractical.

Firebase_Logo

TrailBase

Introduction

This library enables C-based clients to authenticate against a Trailbase backend using its built-in Auth system. By verifying existing user credentials, you can log in directly from C to interact with your TrailBase database. The driver provides a streamlined way to read, write, and subscribe to updates from database, offering sub-millisecond ex. network response times.

Auth

FileEditViewProject
main.c — TB_Auth_Module
int main(int argc, char *argv[]) {
// 1. Init
TB_Client_t *tb = tb_init(BASE_URL);
if (!tb) return 1;
// 2. Auth
printf("[1] Authenticating...\n");
if (tb_auth_login(tb, EMAIL, PASSWORD) != 0) {
fprintf(stderr, "Authentication failed.\n");
tb_free(tb);
return 1;
}
printf(" Token acquired.\n");
printf("Token: %s \n", tb->token);
return 0;
}
[1] Authenticating... Token acquired. Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9. eyJzdWIiOiJOb211QVU2UVNJeUp5dm55UzZIMFZnPT0iL CJpYXQiOjE3NzA4NDk3NTIsImV4cCI6MTc3MDg1MzM1Mi wiZW1haWwiOiJjaGFybGllQHJhZGlrYW50Lm5sIiwiY3N yZl90b2tlbiI6ImR5NmZta3JmRmFpdk0yWW1UcVJZIiwi YWRtaW4iOnRydWV9.nKtSdTiXGDENF20NGy2r6TP_DLcN Dojqi2OI4VqGwc_DVTnBEf-Bwf8wwsFp2tigJ_dkijhZM 3v_RcfXhOFtBg

Initially the user will log in with a username and a password beloging tot he TrailBase user and requests a JWT id token TrailBase will subequently return a response in json format containing; an id token and a refresh token. 

SSE

FileEditViewProject
listener.c — SSE Real-time Feed
int main(int argc, char *argv[]) {
// 1. Init
TB_Client_t *tb = tb_init(BASE_URL);
// 2. Auth
printf("[1] Authenticating...\n");
if (tb_auth_login(tb, EMAIL, PASSWORD) != 0) {
fprintf(stderr, "Authentication failed.\n");
tb_free(tb);
return 1;
}
printf("authenticated!\n");
// 3. Listen
printf("[2] Listening for SSE events on '%s'...\n", TABLE);
tb_error_t err = tb_sse_listen(tb, TABLE, "*", on_sse_event, NULL);
printf("SSE Listener exited with code: %d\n", err);
tb_free(tb);
return 0;
}
charrlie@Charlies-Laptop test % /Users/charrlie/Desktop/Radikant-TrailBase-C/build/test/TRAILBASE-TST-SSE [1] Authenticating... autenticated! [2] Listening for SSE events on 'Medewerkers' (Press Ctrl+C to stop)... [SSE Event CB] Type: message Data: {"Update":{"City":"Amsterdam","Name":"Jamie Korstuit","Resume":"empty file","Salary":2343,"Sex":"male","email":"jamie@radikant.nl","id":4}} [SSE Event CB] Type: message Data: {"Update":{"City":"Rotterdam","Name":"Tessa Beedveld","Resume":"empty file","Salary":52123,"Sex":"female","email":"tessa2004@radikant.nl","id":3}} [SSE Event CB] Type: message Data: {"Insert":{"City":"Tel Aviv","Name":"Levi Goldstein","Resume":"empty file","Salary":88000,"Sex":"Male","email":"levi@goldstein.com","id":6}}

An Authenticated user can listen for changes inside a database; insert, update, create, delete etc. In order to use this functionality you need to enable this functionality inside the Table, inside that admin ui of TrailBase Click on API inside the table view, en click enable Subscriptions.

Record

FileEditViewProject
db_ops.c — Record Creation
// JSON body based on the Employees table schema
const char *new_record_json =
"{"
" \"Age\": 22,"
" \"City\": \"Boston\","
" \"Sex\": \"Male\","
" \"Salary\": 46000,"
" \"Name\": \"Jim Besfield\","
" \"mail\": \"Jim@Besfield.nl\""
"}";
rjson_value *create_resp = tb_create_record(tb, TABLE, new_record_json);
if (create_resp) {
printf(" [Success] Record created.\n");
rjson_print(create_resp, 5);
rjson_free(create_resp);
} else {
fprintf(stderr, " [Error] Failed to create record.\n");
}
[Success] Record created. { "ids": [ "9" ]

You can insert a record with a json string. Obiously it be better to map a struct and generate a json from this struct before uploading it. If the insert was succesfull TrailBase will return a record ID for the record in that table.

Query

FileEditViewProject
query_engine.c — Filter & Sort
char *filter = NULL;
tb_query_add_filter(&filter, "Age", TB_OP_GTE, "25");
tb_query_add_filter(&filter, "Age", TB_OP_LTE, "30");
TB_Query_t q = {
.collection = TABLE,
.filter = filter,
.sort = "Age",
.limit = 10
};
rjson_value *result = tb_query_execute(tb, &q);
if (result) {
rjson_print(result, 2);
rjson_free(result);
}
Executing query: http://localhost:4000/api/records/v1/Medewerkers?filter%5BAge%5D%5B%24gte%5D=25&filter%5BAge%5D%5B%24lte%5D=30&order=Age&limit=10 { "records": [ { "Age": 25, "City": "Amsterdam", "Leeftijd": 31, "Name": "Jamie Korstuit", "Resume": "empty file", "Salary": 2343, "Sex": "male", "email": "jamie@radikant.nl", "id": 4 }, { "Age": 25, "City": "Tel Aviv", "Leeftijd": 23, "Name": "Levi Goldstein", "Resume": "empty file", "Salary": 88000, "Sex": "Male", "email": "levi@goldstein.com", "id": 6 }, ] }%

Currently there is a very simply query protoype that allows you to select from a table and get values between within a certain range.