Drizzle ORM & Generator
@kalamdb/orm is the Drizzle package for KalamDB. Use it when you want generated tables, typed queries, or table-level live helpers. It runs on top of @kalamdb/client.
Install it with the client and Drizzle:
Driver quick start
Copy this after you have a generated schema.ts file.
The driver uses KalamDB SQL over HTTP and normalizes temporal values for Drizzle columns. timestamp(..., { mode: 'date' }), date(..., { mode: 'date' }), and time(...) can read KalamDB’s numeric wire values without app-side parsing.
Pass a full KalamDBClient to kalamDriver() so FILE uploads can route to queryWithFiles() when needed.
Table helpers
Use kTable instead of raw pgTable so the schema retains KalamDB table type metadata.
Available table helpers:
| Helper | Use for |
|---|---|
kTable.shared(name, columns, options?) | WITH (TYPE = 'SHARED') tables |
kTable.user(name, columns, options?) | per-user isolated tables |
kTable.stream(name, columns, options?) | stream tables |
kTable.system(name, columns, options?) | system metadata tables |
kSystemColumns([...]) | _seq, _deleted, and _commit_seq typed hidden columns |
KalamDB-specific columns:
| Helper | Runtime value |
|---|---|
file(name) | `FileRef |
bytes(name) | `Uint8Array |
embedding(name, dimensions) | `number[] |
Generate schema.ts
Generate a Drizzle schema from a running KalamDB server:
The generator reads SHOW TABLES, calls DESCRIBE <namespace.table> when column metadata is incomplete, and emits only the imports needed by the generated tables. It preserves primary keys, not-null constraints, system-column options, comments, table config constants such as chat_messagesConfig, and $inferSelect / $inferInsert aliases.
Options:
| Option | Description |
|---|---|
--namespace <name> | Limit output to one or more namespaces. Repeat it or pass comma-separated names. |
--include-system | Include system and dba tables. |
--include-system-columns <mode> | Add typed hidden columns to generated table definitions. Use all, _seq, or _deleted. |
--bigint-mode <mode> | Choose how generated BIGINT columns are emitted. Accepted values are string, bigint, or number; default is string. |
--no-type-aliases | Skip generated $inferSelect and $inferInsert aliases. |
BIGINT defaults to text() because KalamDB transports Int64 values as strings to preserve precision. Choose --bigint-mode bigint when you want Drizzle to coerce values to native bigint, or --bigint-mode number only when values fit safely in JavaScript numbers.
Keep schema.ts fresh during local development
Add a generator script to your app so the command stays short:
In a kalam.toml project, kalam dev watches schema.sql and reruns kalam schema gen when [dev].generate_types = true:
See Local Development. The legacy kalam --watch-schema server-polling flag is deprecated.
Exact KalamDB datatype mapping
| KalamDB type | Generated Drizzle helper | Read behavior |
|---|---|---|
BOOLEAN | boolean() | boolean |
INT | integer() | number |
SMALLINT | smallint() | number |
BIGINT | text() by default | string for Int64 precision |
DOUBLE | doublePrecision() | number |
FLOAT | real() | number |
TEXT | text() | string |
TIMESTAMP | timestamp(..., { mode: 'date' }) | Date when using date mode |
DATETIME | timestamp(..., { mode: 'date' }) | Date when using date mode |
DATE | date(..., { mode: 'date' }) | UTC-date Date |
TIME | time() | HH:mm:ss[.fraction] string |
JSON | jsonb() | JSON value |
BYTES | bytes() | Uint8Array |
EMBEDDING(n) | embedding(name, n) | number[] |
UUID | uuid() | UUID string |
DECIMAL(p,s) | numeric() | exact decimal string |
FILE | file() | `FileRef |
Upsert and returning
Drizzle returning() and onConflictDoUpdate() compile to KalamDB SQL and run through the same driver:
FILE uploads through Drizzle
You do not wrap every query. Normal select, insert, update, and delete calls go through db directly. Only FILE bytes need multipart SQL, and the driver handles that when upload values appear in .values() or .set():
You can also pass a File or Blob directly to a generated file() column; the driver uses the filename (or upload for plain blobs) as the multipart field name.
kalamDriver() compiles the Drizzle builder, normalizes quoted identifiers and DEFAULT columns for KalamDB, replaces upload params with FILE("name"), and calls client.queryWithFiles() when bytes are present.
For raw SQL strings (no Drizzle builder), use queryWithFiles() from @kalamdb/orm or @kalamdb/client. Use compileQuery() when you need normalized SQL and params without executing.
See FILE Columns & Uploads for download URLs, FileRef, and progress callbacks.
Execute as a user
Agents and service workers can compile a Drizzle builder and run it through KalamDB’s EXECUTE AS USER path:
Only pass a user id that your service account is authorized to impersonate.
Live table helpers
Use liveTable() for React state, dashboards, and admin UI screens that want the current materialized row set.
liveTable() reuses the same @kalamdb/client connection and normalizes timestamp/date/time fields from the Drizzle table metadata. It accepts the same row-oriented options as client.live(), including lastRows, from, limit, getKey, and onCheckpoint. Use client.liveEvents() directly when you need low-level change events.
UI and example fit
Use this package in UI code or service code that wants typed tables. Worker code should import @kalamdb/consumer only when it needs topic consumption.