Declarative Functions
Declarative server functions are defined with queryRows, insertRow, patchRow, and deleteRow. They translate directly to parameterized SQL at compile time — no V8 isolate, minimal overhead.
When to use declarative
Use declarative functions for standard CRUD operations on tables defined in your schema. For complex business logic, aggregations, or external API calls, use handler-based functions instead.
Basic example
// server/functions.ts
import { queryRows, insertRow, patchRow, deleteRow, arg } from "@zaflun/lumio-sdk/server";
// List all rules
export const getRules = queryRows("rules");
// Add a new rule (editor only — streamers only, not viewers)
export const addRule = insertRow("rules", {
text: arg("text"),
revealed: false,
}, { editorOnly: true });
// Reveal a rule
export const revealRule = patchRow("rules", arg("id"), {
revealed: true,
}, { editorOnly: true });
// Delete a rule
export const deleteRule = deleteRow("rules", arg("id"), { editorOnly: true });
queryRows
Returns all rows from a table, ordered by created_at ASC.
queryRows(tableName: string, options?: QueryOptions): ServerQuery
Options
| Option | Type | Description |
|---|---|---|
filter | Filter | Condition to filter rows |
orderBy | string | Column name to sort by (default: "created_at") |
orderDir | "asc" | "desc" | Sort direction (default: "asc") |
limit | number | arg | Maximum rows to return |
offset | number | arg | Rows to skip (for pagination) |
// List only revealed rules, newest first
export const getRevealedRules = queryRows("rules", {
filter: filter("revealed", "=", true),
orderBy: "created_at",
orderDir: "desc",
});
// Paginated rules
export const getRulesPaged = queryRows("rules", {
limit: arg("limit"),
offset: arg("offset"),
});
insertRow
Inserts a new row into a table. Returns the inserted row including its generated id and created_at.
insertRow(tableName: string, data: DataObject, options?: MutationOptions): ServerMutation
DataObject
A record of field names to values or arg() references:
export const addRule = insertRow("rules", {
text: arg("text"), // value comes from caller: addRule({ text: "..." })
revealed: false, // static value
category: arg("category"), // optional dynamic value
});
patchRow
Updates specific fields of an existing row. The first arg() or value after tableName is the row id.
patchRow(tableName: string, id: string | arg, data: DataObject, options?: MutationOptions): ServerMutation
// Reveal a specific rule
export const revealRule = patchRow("rules", arg("id"), {
revealed: true,
});
// Update multiple fields
export const updateRule = patchRow("rules", arg("id"), {
text: arg("text"),
category: arg("category"),
});
deleteRow
Deletes a row by its id.
deleteRow(tableName: string, id: string | arg, options?: MutationOptions): ServerMutation
export const deleteRule = deleteRow("rules", arg("id"), { editorOnly: true });
arg()
The arg() helper marks a field as a dynamic parameter supplied by the caller at runtime:
import { insertRow, arg } from "@zaflun/lumio-sdk/server";
export const addVote = insertRow("votes", {
choice: arg("choice"), // caller provides: castVote({ choice: "yes" })
userId: arg("userId"), // caller provides: castVote({ userId: "..." })
weight: 1, // static value
});
arg("name") is substituted with a SQL $n parameter placeholder — preventing SQL injection.
filter()
Build filter conditions for queryRows:
import { filter, arg } from "@zaflun/lumio-sdk/server";
// Static filter
export const getRevealedRules = queryRows("rules", {
filter: filter("revealed", "=", true),
});
// Dynamic filter (value from caller)
export const getRulesByCategory = queryRows("rules", {
filter: filter("category", "=", arg("category")),
});
Supported operators
| Operator | SQL equivalent |
|---|---|
"=" | = |
"!=" | <> |
">" | > |
">=" | >= |
"<" | < |
"<=" | <= |
"like" | LIKE |
"in" | = ANY(...) |
editorOnly option
Mutations with editorOnly: true can only be called from the editor surface. Calls from the layer or interactive surface are rejected with a permission error:
export const deleteRule = deleteRow("rules", arg("id"), {
editorOnly: true, // only the streamer/editor can delete
});
Use this for admin operations that viewers on the interactive page should not be able to perform.