Database Skill
Local NoSQL embedded database: schema design, CRUD operations, expiry, change callbacks, and pagination.
Invoke with: /database
Key APIs
c
/* Open / close */
Db *dbOpen(cchar *path, cchar *schema, int flags);
void dbClose(Db *db);
/* CRUD */
const DbItem *dbCreate(Db *db, cchar *model, Json *props, DbParams *params);
const DbItem *dbGet(Db *db, cchar *model, Json *props, DbParams *params);
const DbItem *dbFindOne(Db *db, cchar *model, Json *props, DbParams *params);
RList *dbFind(Db *db, cchar *model, Json *props, DbParams *params);
const DbItem *dbUpdate(Db *db, cchar *model, Json *props, DbParams *params);
int dbRemove(Db *db, cchar *model, Json *props, DbParams *params);
/* Field access */
cchar *dbField(const DbItem *item, cchar *fieldName);
int64 dbFieldNumber(const DbItem *item, cchar *fieldName);
bool dbFieldBool(const DbItem *item, cchar *fieldName);CRUD Pattern
c
const DbItem *item;
RList *items;
int index;
/* Create */
dbCreate(db, "Sensor", DB_PROPS("id", "sensor1", "value", "23.5"), DB_PARAMS());
/* Read one */
item = dbGet(db, "Sensor", DB_PROPS("id", "sensor1"), DB_PARAMS());
if (item) {
rInfo("sensor", "Value: %s", dbField(item, "value"));
}
/* Find all with limit */
items = dbFind(db, "Sensor", NULL, DB_PARAMS(.limit = 100));
for (ITERATE_ITEMS(items, item, index)) {
rTrace("scan", "id=%s val=%s", dbField(item, "id"), dbField(item, "value"));
}
rFreeList(items);
/* Update */
dbUpdate(db, "Sensor", DB_PROPS("id", "sensor1", "value", "24.1"), DB_PARAMS());
/* Delete */
dbRemove(db, "Sensor", DB_PROPS("id", "sensor1"), DB_PARAMS());Schema Definition
Each app has a schema.json5 in state/config/:
json5
{
version: '1.0.0',
models: {
Sensor: {
id: { type: 'string', required: true },
value: { type: 'string' },
ts: { type: 'date', ttl: 86400 }
}
}
}Field types: string, number, boolean, date, object, array. The ttl property (seconds) enables automatic item expiration.
Change Callbacks
c
static void onSensorChange(void *arg, Db *db, DbModel *model, DbItem *item,
DbParams *params, cchar *cmd, int events)
{
cchar *value = dbField(item, "value");
rInfo("sensor", "Change: %s %s = %s", cmd, dbField(item, "id"), value);
}
/* In ioStart(): register callback */
dbAddCallback(ioto->db, onSensorChange, "Sensor", NULL, DB_ON_CHANGE);
/* In ioStop(): remove callback */
dbRemoveCallback(ioto->db, onSensorChange, "Sensor", NULL);Event Types
| Event | Description |
|---|---|
DB_ON_CHANGE | Fired immediately on create, update, or remove |
DB_ON_COMMIT | Fired when changes are committed to disk |
Important Notes
dbField()returns a pointer into the item — invalid after updates or frees. Copy withsclone(dbField(item, "name"))when storing the value.DB_PROPS()andDB_PARAMS()are convenience macros for building query args.DB_PARAMS(.limit = N)limits result count;.upsert = 1creates if not found.- Use
ioto->dbwhen running inside the Ioto agent.
