db
Use db for structured offline records that need filtering, sorting and reactive counts. Queries return read-only signals that update after table writes.
Create a table with a migration
import type { KuitoConfig } from 'kuito/config';
export default {
name: 'Library',
ios: { bundleIdentifier: 'com.example.library' },
android: { applicationId: 'com.example.library' },
migrations: [
'CREATE TABLE tracks (id INTEGER PRIMARY KEY, title TEXT NOT NULL, album TEXT, plays INTEGER NOT NULL)',
],
} satisfies KuitoConfig;Render a query and update its rows
import { db, List, Text, type Schema } from 'kuito';
/** A Standard Schema from a type guard. An app passes Valibot's, Zod's or ArkType's instead. */
function schema<T>(test: (value: unknown) => value is T, expected: string): Schema<T> {
return {
'~standard': {
version: 1,
vendor: 'app',
validate: (value) => (test(value) ? { value } : { issues: [{ message: expected }] }),
},
};
}
type Track = { id: number; title: string; album: string | null; plays: number };
const field = (row: object, key: string, type: string, nullable = false) =>
typeof Reflect.get(row, key) === type || (nullable && Reflect.get(row, key) === null);
const tracks = db.table(
'tracks',
schema(
(row): row is Track =>
typeof row === 'object' &&
row !== null &&
field(row, 'id', 'number') &&
field(row, 'title', 'string') &&
field(row, 'album', 'string', true) &&
field(row, 'plays', 'number'),
'expected a track',
),
);
function Played() {
const top = db.query(tracks, { orderBy: { plays: 'desc' }, limit: 20 });
return <List data={top.value} renderItem={({ item }) => <Text>{item.title}</Text>} />;
}
await tracks.insert({ id: 1, title: 'Intro', album: null, plays: 0 });
await tracks.update({ id: 1 }, { plays: 1 }); // `Played` shows the new order
await tracks.delete({ album: null });The schema validates each row. This example includes a small Standard Schema validator so it has no schema-library dependency. Use the equivalent schema from your chosen library in an app.
Choose and change records
query(table, { where, orderBy, limit }) returns the matching rows. Conditions
on different columns are combined. A scalar means equality; comparison objects
support gt, gte, lt, lte, not, in and SQL like. null matches SQL
NULL. count(table, where) returns a reactive count.
insert, update and delete return promises. A write is transactional and
queries refresh after it commits. An empty where matches every row; construct
deletion filters deliberately. Use db.transaction when several SQL statements
must commit together. Query order is only guaranteed when you specify orderBy.
Append migrations in config as the schema evolves. Keep existing migration positions stable for installations that already applied them.
See Save local data for preferences, string storage and secrets.
Référence
Exports 8
Méthodes, constantes et types exposés par cet espace de noms natif.
tableThe table name, whose rows match schema.functiontransactionRuns writes, and lands every table write it makes in one transaction:
all of them, or none.functionqueryThe rows of table that options select, as a signal: read synchronously
at first, then again on the background thread after each write to the table.functioncountHow many rows of table where matches, as a signal that follows writes as a query does.typeComparisonComparisons of one column's value: a row matches when every one holds.typeWhereRows whose columns equal these values, or pass these comparisons; null matches NULL.typeQueryOptionsSelects the rows a database query returns: which ones match, their order, and how many.typeTableA table the migrations made, and the schema each of its rows matches.