Reading and writing data from code
The entity calls an app makes: list, filter, get, create, update, delete, bulk operations and live-updating lists, with what every row carries.
Last updated September 17, 2026
On this page
Pages talk to the database through the SDK's entity helper. This is what the builder writes for you; it is here so you can read the code it produces, or write your own.
import { entity } from "@praxivara/sdk";
const rows = await entity("Booking").list(); // newest first
const mine = await entity("Order").list({ mine: true }); // only the signed-in user's rows
const page = await entity("Order").list({ limit: 20, offset: 40, sort: "-total" });
const open = await entity("Task").filter({ status: "open" }); // equality
const big = await entity("Deal").filter({ amount: { op: "gte", value: 10000 } });
const one = await entity("Order").get(id);
await entity("Booking").create({ client_name, date });
await entity("Booking").bulkCreate([{ ... }, { ... }]);
await entity("Task").update(id, { done: true });
await entity("Task").delete(id); // soft delete
await entity("Task").bulkUpdate([{ id, done: true }, { id: id2, done: false }]);
await entity("Task").updateMany([id1, id2], { archived: true });
await entity("Task").deleteMany([id1, id2]);
const stop = entity("Task").subscribe(rows => setTasks(rows), { mine: true });
// later: stop();Reading
list(options)returns rows newest first. Options:limitandoffsetfor paging,sortas a field name with a leading-for descending, andmine: trueto keep only the signed-in user's rows.filter(conditions, options)takes a field-to-value map. A plain value means equals; an object withopandvaluecompares witheq,ne,lt,lte,gt,gteorcontains.get(id)returns one row.subscribe(callback, options)keeps a list up to date as rows change and returns a function that stops it. Use it for dashboards and inboxes.
What every row carries
Besides its own fields, each row has id, created_date, and mine (true when the signed-in caller created it). A signed-in reader also sees created_by. Use mine to decide whether to show an Edit or Delete control.
Writing
create(data)adds a row. Required fields and enum values are validated on the server; an invalid row throws with the field named.update(id, data)merges: fields you leave out keep their values.delete(id),remove(id)andarchive(id)are one and the same call, a soft delete.- The bulk forms (
bulkCreate,bulkUpdate,updateMany,deleteMany) make one request for many rows and are the right choice for anything more than a handful.
Errors
Every call throws on failure. Wrap it, show a real error state, and treat err.status === 401 as "sign in first" (send the visitor to the login page). A permission refusal comes back as a 403 with admin_required or forbidden.
const [tasks, setTasks] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
entity("Task").list({ mine: true })
.then(setTasks)
.catch(err => {
if (err.status === 401) navigate("/login");
else setError(err.message);
});
}, []);Backend functions use the same tables
Inside a backend function the same operations are available as ctx.entity("Name"), with slightly different return shapes. See the backend function reference.