Query limits
Opt-in default limits for find, tree walks, to-many include, page, and groupBy, with a hard ceiling.
By default a read with no limit is refused (OKM1101 for find, descendants, ancestors, page, and a grouped aggregate; OKM1105 for a to-many include). limits is an opt-in default for those calls. Leave it out and nothing changes: TypeScript still requires the argument and a limit on each of those calls.
When you set a key, TypeScript makes that call's argument and limit optional for that key only:
Key set in connect | TypeScript change |
|---|---|
limits.find | find(), descendants(), and ancestors() may omit the argument; limit on the options object is optional |
limits.page | page() may omit the argument; limit is optional |
limits.include | A to-many include may omit limit |
limits.groupBy | A grouped aggregate may omit limit |
Keys you leave out keep today's rule. max does not change which arguments TypeScript requires.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
import { warnings } from "okmodel/warnings";
const notesTable = table("notes", { id: t.identity(), title: t.text() });
const app = schema({ tables: [notesTable] });
export const db = connect(process.env.DATABASE_URL ?? "", {
schema: app,
limits: { find: 50, include: 20, page: 25, groupBy: 100, max: 1000 },
warnings: warnings(),
});Every key is optional and independent. include and groupBy never take the value of find.
| Key | Applies to |
|---|---|
find | find, descendants, and ancestors with no limit and no .all(reason). That includes search, matches, presets, and relation filters. depth on a tree walk is steps, not this row bound. |
include | A to-many include (many and manyThrough, at any depth) with no limit. A to-one include has no limit. |
page | The page size of page() with no limit. |
groupBy | aggregate with groupBy and no limit. |
max | A ceiling for the limit you write, on find, descendants, ancestors, page(), aggregate, and include. |
const notes = await db.notes.find({ orderBy: { id: "asc" } }); // limit 50
const few = await db.notes.find({ orderBy: { id: "asc" }, limit: 5 }); // limit 5
const every = await db.notes.find({ orderBy: { id: "asc" } }).all("nightly export"); // no limitA call that states a limit or .all(reason) never takes a default.
Set defaults once
okm init writes this object on connect. The library never turns a default on by itself. Leave limits out and find() still needs a limit (OKM1101). With limits.find set, a bare find() uses that default.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
const notesTable = table("notes", { id: t.identity(), title: t.text() });
const app = schema({ tables: [notesTable] });
export const db = connect(process.env.DATABASE_URL ?? "", {
schema: app,
limits: { find: 100, include: 20, page: 50, groupBy: 500, max: 1000 },
});
const rows = await db.notes.find();A limit on the call, or .all(reason), still wins.
max
max is a hard ceiling. A limit above it is OKM1101, and the fix is .all(reason), which reads past max on purpose.
await db.notes.find({ orderBy: { id: "asc" }, limit: 5000 }); // OKM1101
await db.notes.find({ orderBy: { id: "asc" }, limit: 5000 }).all("backfill"); // allowedWhat limits do not touch
.stream(), one, count, exists, an aggregate without groupBy, the limit of update and delete, bulk write predicates, and raw().
Check at connect
limits is checked once, when the client connects. Each key is a positive integer, the keys are find, include, page, groupBy, and max, and no key is above max. A bad value is OKM1120 and rejects connected (and the first query).
See the limit
.inspect() lists the bounded rule with the source: limits.find, limits.page, limits.groupBy, or limits.include (provenance connect). A limit you wrote shows as limit (provenance caller). The onQuery event carries limit: { value, source } for the root read.
OKM2011
A default can hide rows. With warnings on, a read that took a default and returned exactly that many rows is OKM2011 in development: the call site, the key (limits.find = 50), and the fix. descendants and ancestors take limits.find and do not emit OKM2011. The fix is a limit that fits the call, page(), or .all(reason).
The warning never fires for a limit you wrote, for .all(reason), or for page(). In production every warning is off until levels turns it on. See Warnings.