Skip to main content

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

OptionTypeDescription
filterFilterCondition to filter rows
orderBystringColumn name to sort by (default: "created_at")
orderDir"asc" | "desc"Sort direction (default: "asc")
limitnumber | argMaximum rows to return
offsetnumber | argRows 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

OperatorSQL 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.