v0.5.1
♻️ Changed
- A pull request no longer runs the Postgres suite. The label
needs: postgresruns the suite on 15 and 18 and the tarball on 18, in the same Actions run as the other checks. Adding that label without a push starts it on its own and does not cancel the run.bun run verifyruns that suite on this machine. The release and the weekly run still cover 15 through 18 (D212). - A pull request update is one Actions run. Checks are named
area / piece, so each one readsCI / area / piece. Long test groups are split (migrateandmigrate pg,driversandrows,schema,columns, andschema pg,tenancy,client, andclient pg,package,contracts, andsafety). Node and Deno areruntimes / portable. Path labels and the pull request lint are jobs in that run. The required status isgate / check(D213). - Running the Postgres suite with no database is loud. The preflight names the unreachable primary and how many files would skip, and
CI=truefails instead of running. Each skipped Postgres test counts toward a finalN Postgres tests SKIPPEDline (QA-R2, D216). - CI runs the date/time codecs on Node 22 and 24 with
temporal-polyfilland on Node 26 natively, in atemporal / nodejob that joins thegate / checkneeds. The Postgres suite workflow proves the D215 pid probe refuses a transaction-mode pgbouncer with OKM1854 on every suite run (QA-R3, D216). bun run type-costmeasures a 250-table inferred schema beside the other probes and fails above measured +20% (21,180 instantiations). Check time is reported, not gated (QA-R4, D216).
🐛 Fixed
runtime
update,delete,archive, andrestorenow refuse a where with no effective predicate, including undefined values (QA-C1, QA-H2). A field value is a leaf.eqkeeps a timestamp, a date, bytes, or a jsonb object in the filter. A bare object stays OKM1121 (D125, D210).- An
or()branch with no effective predicate is now refused, in reads and in writes (QA-H1).or([])still matches nothing. or()with a non-array or with more than one argument is now refused (QA-M4).- An unknown key on
update, andtxwith the function before the options, are now refused (QA-M2). - A bad option on
find,one, andcountnow rejects the query, sosafeandcatchsee OKM1120 (QA-M11).pageandaggregatealready did. - A read on a replica that refuses or drops the connection falls back to the primary on postgres.js, node-postgres, and Bun.sql.
onRoutereportsfallback:unhealthy. A driver error with an empty message now has text (QA-M1, D214). - Closing a client before it connects no longer leaves an unhandled rejection.
connectedrejects with anunavailableerror that says the client was closed first (QA-M5, D214). - OKM1104 lists each accepted constraint once and does not name the tenant key, which every unique includes (QA-L11, D214).
- OKM1200 reads
Validation failed: <field> <reason>and names the first failing field (QA-L12, D214).
dialects
- Compiled SQL for a tenant table keeps the tenant predicate on every table alias, including a where that compares an object through
eq(QA-S4). - A missing table or column maps to
undefined_tableorundefined_column, with a fix that namesokm migrate applyandokm migrate status. Calls that share one caller signal now share one abort listener instead of adding one each (QA-L8, D214). - A TLS or certificate failure maps to
unavailablewith reasontlsand a fix that namessslmode(QA-L9, D214). filters().parseno longer throws a TypeError onconstructor,__proto__,toString, orhasOwnProperty. A key that is not allowlisted is OKM1123. Parse applieseq,in,notIn,lt,lte,gt,gte,between,startsWith,endsWith,contains,like, andilike. An operator the allow type accepts and parse cannot apply is OKM1120 whenparse()runs (QA-M9, D215).- The shipped
Temporaldeclaration is empty interfaces, so it merges with TypeScript's Temporal lib and withtemporal-polyfill(QA-L2, D215). - Emitted row types keep
jsonb<T>and write an optional insert column asx?: T(QA-L3, D215). fn({ searchPath })is checked as a comma-separated list of identifiers when the function is built (QA-S3, D215).
tooling
- The commit-cut harness waits until the server has answered
COMMITbefore it drops the client. A fixed delay could reset the socket first, so the transaction rolled back while the caller still gotoutcome_unknown. - A hand-written migration step is linted per statement. A leading comment, a second statement, a semicolon inside a comment,
DOandCALL, andALTER COLUMN … TYPEcan now be refused (QA-H3).-- okm-allowon the step silences that code on every statement of the step. - Port 6432 counts as a pooler. Apply, seed, and check refuse a backend pid that changes between two statements, with OKM1854, unless
--allow-pooleris set (QA-M6, D215). okm checkon a schema withcitextand a view exits 0. The scratch search path includes the schemas that hold extension types, then restores the previous value (QA-M7, D215).isolation()uses a new tenant pair each run, asserts only on the row it inserted, deletes that row, and names a missing factory. It covers aggregate, page, batch, and stream when the client has them (QA-M8, D215).- A CLI error prints
error <code>: <message>and the fix, and exits 1. The stack is printed only with--verboseorOKM_DEBUG=1(QA-M10, D215). - The published
package.jsonno longer carries theworkspacesfield. The pack step strips it from the tarball only; the root keeps it, and the tarball smoke test asserts it (QA-R1, D216). - Apply's
failed at step Ncounts from 1, the same number the linter prints. Status still prints the stored index (QA-L5, D215). - A renamed table's plan row estimate uses the old table's row count (QA-L6, D215).
okm,okm help,okm --help, andokm -hprint the commands and exit 0.okm <command> --helpprints that command (QA-L7, D215).- Apply refuses a database whose
standard_conforming_stringsis off (QA-S2, D215).
docs
- Temporal values keep microseconds. Showing one passes
fractionalSecondDigits. The codecs do not warn (QA-L1, D215). db.viewskeys are camelCased. A materialized view is refreshed withREFRESH MATERIALIZED VIEWuntil arefresh()handle in 0.6 (QA-L10, D215).lists_touchis the triggertimestamps({ enforce: "trigger" })installs on a table namedlists.archivable()installs no trigger (QA-L13, D215).- Hidden columns in
whereandorderByare unchanged. The options for 0.6 are recorded in D215 (QA-S1). timeoutandsignalon Bun.sql and PGlite do not settle a call whose statement is already running, and an outer-client call inside a PGlitetx()callback queues behind the transaction instead of throwing (QA-M3, D216). Neither driver can cancel an in-flight statement, and the client-side race did not fit the size cap, so both stay known limits. OKM1192 is reserved for the later refusal.- Date and time columns need a
Temporalglobal. Bun and Node 26 have it; Node 22 and 24 need the polyfill line before the columns are used (QA-D1, D216). - The
okmbin's shebang is node:bunx okmruns with Node,bun --bun okmselects the Bun runtime, and a.tsconfig needs Node 22.18 or newer (QA-D2, D216). - The update/delete rule names its codes: no effective predicate, including undefined values, is OKM1102, and an empty
or()branch is OKM1121 (QA-D3, D216). - The linter page states the statement split, comment handling, and the
DOandCALLrule (QA-D4, D216). - Circuits start closed, so the first read goes to a replica without waiting for a probe (QA-D5, D216).
- Known limits records the M3 outcome, sub-microsecond rounding on write, the PGlite outer-client queue rule, and the thirteen
filters().parseoperators (QA-D6, D216). - Production states the pooler refusal: the refused hosts and ports, the pid probe, and
--allow-pooler(QA-D7, D216). - The views section shows the camelCase handle and the
REFRESH MATERIALIZED VIEWrefresh (QA-D8, D216). - Catalog identity and constraint names wait for 0.6, with the rename design (QA-L4).