zmdbzero-maintenance data layer
Docs Benchmarks Anti-patterns OpenAPI
Docs / Build an application

GuidesSupported

Short, task-shaped answers to things people actually search for. Each one is a working snippet against the real API, plus the reason it is written that way.

Querying#

Conditional filtersBuilding a where from optional inputs without dropping 0 and ''
Count rowshasMore is free, a total is not, and aggregate is how you get one
Cursor-based paginationKeyset pagination, and why OFFSET gets slower
EXISTS subquerieswhereExists and correlated subqueries
Dynamic queriesComposing a builder across functions

Writing#

Increment / decrementRepository increment and expression-valued patches
Toggle a booleanAtomic not() through update / updateMany
Bulk updateOne shared patch ships; different values per row remain ToDo
UpsertTyped conflict targets and expression-valued update fields

Increment and toggle use the same closed expression vocabulary in UpdateBuilder.set() and BaseRepository patches. Updating different rows to different values is a separate, wider CASE / VALUES problem; updateMany covers one validated patch over all matching rows.

Schema#

Array and JSON defaultsdefaultTo with a JSON value, and the shared-reference trap
Timestamp defaultsnow() in the database versus new Date() in the process
Case-insensitive uniqueExpression index on the PostgreSQL family/SQLite; generated column on the MySQL family/SQL Server
Full-text search with generated columnstsvector via generatedColumnDdl
Vector searchToDo — typed distance ships; complete runnable guide remains
PostGISToDo — geometry predicates ship; full guide remains

Local development#

Local PostgresDocker, psql, and a test database that resets fast
Local MySQLSame, plus the collation settings that matter
PGlitePostgres in-process, for tests

The three facts behind most of these#

Worth knowing before reading any individual page:

cross-checks it either.

---

See also: Tutorials · Query Builder · Gotchas