The builder runs on Rindle’s in-browser engine (@rindle/wasm). createReactiveSqlClient and
rindle.addQuery take SQL only for now.
The builder writes the same queries as Rindle SQL, as typed TypeScript. Results are typed from your schema, and a misspelled table or column is a type error.
import { createSchema, createWasmStore, gt, number, string, boolean, table } from "@rindle/wasm";
const issue = table("issue")
.columns({ id: number(), title: string(), priority: number(), closed: boolean() })
.primaryKey("id");
const comment = table("comment")
.columns({ id: number(), issueId: number(), body: string() })
.primaryKey("id");
const schema = createSchema({ tables: [issue, comment] });
const store = await createWasmStore(schema);
const view = store.query.issue
.where.closed(false)
.where.priority(gt(3))
.orderBy("id", "desc")
.limit(50)
.sub("comments", comment, { parent: ["id"], child: ["issueId"] }, (c) =>
c.orderBy("id", "desc").limit(10),
)
.materialize();
view.subscribe((rows) => console.log(rows));The same query in SQL:
SELECT * FROM issue WHERE closed = 0 AND priority > 3 ORDER BY id DESC LIMIT 50
WITH comments OF comment ON issueId = id (ORDER BY id DESC LIMIT 10)Schema
table(name).columns({ … }).primaryKey(…cols) |
A table. |
string(), number(), boolean(), int64(), json<T>() |
Column types. Add .nullable() for a column that can be NULL. |
createSchema({ tables }) |
The schema. |
rel(parent, child, { parentCol: "childCol" }) |
A relationship, to reuse in sub, countAs and exists. Group them with defineRelationships({ … }). |
Building a query
store.query.<table> starts a query. Every method returns a new query.
| Method | SQL |
|---|---|
.where(condition) |
WHERE. Calls are combined with AND. |
.where.<column>(value) |
WHERE column = value, or pass an operator: .where.priority(gt(3)) |
.orderBy(column, "asc" | "desc") |
ORDER BY |
.limit(n) |
LIMIT |
.start(row, { exclusive }) |
WHERE (cols) > (…): page from a row |
.select(...columns) |
A column list |
.one() |
LIMIT 1. The view’s data is a row or null. |
.sub(name, table, correlation, build?) |
WITH name OF table ON … |
.countAs(name, table, correlation, build?) |
A live count of related rows on each row |
.count(), .groupBy(column), .having(…) |
Aggregates |
.materialize() |
Starts the live query. |
.ast() |
The query as JSON. |
A correlation is { parent: [...], child: [...] }: the parent columns, and the child columns
they match. A relationship from rel can stand in for the table and correlation.
Conditions
| Function | SQL |
|---|---|
eq, ne, gt, ge, lt, le |
=, !=, >, >=, <, <= |
is, isNot, isNull, isNotNull |
IS, IS NOT, IS NULL, IS NOT NULL |
like, notLike, ilike, notIlike |
LIKE, NOT LIKE, ILIKE, NOT ILIKE |
inList, notInList |
IN, NOT IN |
and(...), or(...) |
AND, OR |
exists(table, correlation, build?), notExists(…) |
EXISTS, NOT EXISTS |
import { exists, or } from "@rindle/wasm";
store.query.issue.where(
or(issue.priority(gt(8)), exists(comment, { parent: ["id"], child: ["issueId"] })),
);A table doubles as a condition factory: issue.priority(gt(8)) is the condition
priority > 8.
Views
materialize() returns a view:
data |
The current rows. |
subscribe(listener) |
Calls listener(rows) now and after every change. Returns an unsubscribe function. |
destroy() |
Stops the query. |