const recent = q.shape
.where(exists(
onLayer,
(layer) => layer.where.visible(1)
))
.orderBy("updated", "desc")
.limit(8)
.materialize();
01 / Declare the view
The query is the API.
The query on the left doesn't fetch eight rows and leave you hanging. It creates a maintained view: the newest eight visible shapes, in order, for as long as the component needs it.
function RecentWrites() {
return recent.data.map((shape) => (
<RecentWrite
key={shape.id}
kind={shape.kind}
color={shape.color}
updated={shape.updated}
/>
));
}
02 / Render current state
The UI is a function of the query.
The component reads the query’s current rows. Your UI framework schedules a render when that query receives an update.
Getting the initial result and maintaining the result are the same abstraction.
const mutators = {
canvasFrame: shared(args, function* (tx, a) {
for (const next of a.shapeUpdates) {
yield tx.update("shape", next);
}
})
};
await mutate.canvasFrame({
shapeUpdates: [{ id, x, y }]
});
// Every affected view is current here.
recent.data;
largest.data;
palette.data;
03 / Change state once
Named mutators are the only update path.
Dragging sends the shape’s key and its new coordinates—never its old row. The client resolves the keyed update locally. Inside that same call, the engine derives the consequences and updates every affected query. When the promise resolves, the next paint already has the right data.
const palette = q.shape
.groupBy("color").count();
const largest = q.shape
.orderBy("area", "desc").limit(6);
const recent = q.shape
.orderBy("updated", "desc").limit(8);
const selected = q.shape
.where(exists(onSelection))
.orderBy("z", "asc");
04 / Let queries do the bookkeeping
Change a row. Every impacted view updates.
Recoloring moves a count between palette groups. Resizing can reseat the leaderboard. Any edit moves the shape to the top of the feed. Selecting or deselecting changes the selection view without changing its query.
These are not four update handlers. They are four declarations. Edit the live row below and watch only the impacted panels react.
const selected = q.shape
.where(exists(onSelection))
.orderBy("z", "asc")
.materialize();
// Selection changes data, not the query.
await mutate.canvasFrame({
selectionAdds: [id]
});
05 / Change data, not query identity
Even ephemeral state can be declarative.
The selected ids live in a table. Dragging a selection box writes only the rows crossing its edge. Impacted queries are updated atomically.