okmodel 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +32 -16
  2. package/dist/adapters/capabilities.d.ts +34 -0
  3. package/dist/adapters/pg/bunsql-extra.d.ts +17 -0
  4. package/dist/adapters/pg/bunsql.d.ts +60 -0
  5. package/dist/adapters/pg/call.d.ts +2 -12
  6. package/dist/adapters/pg/nodepostgres-extra.d.ts +18 -0
  7. package/dist/adapters/pg/nodepostgres.d.ts +57 -0
  8. package/dist/adapters/pg/postgres-extra.d.ts +50 -1
  9. package/dist/adapters/pg/postgresjs.d.ts +0 -4
  10. package/dist/adapters/pg/session.d.ts +94 -0
  11. package/dist/adapters/pg/watch.d.ts +18 -0
  12. package/dist/contracts/catalog/object.d.ts +1 -0
  13. package/dist/contracts/catalog/types.d.ts +15 -8
  14. package/dist/contracts/connection.d.ts +13 -0
  15. package/dist/contracts/driver.d.ts +18 -5
  16. package/dist/contracts/error.d.ts +17 -1
  17. package/dist/contracts/generator.d.ts +63 -0
  18. package/dist/contracts/index.d.ts +2 -2
  19. package/dist/contracts/index.js +1 -1
  20. package/dist/contracts/internal.js +11 -9
  21. package/dist/contracts/location.d.ts +24 -0
  22. package/dist/contracts/rows.d.ts +15 -0
  23. package/dist/dialects/pg/archive-bind.d.ts +22 -0
  24. package/dist/dialects/pg/column.d.ts +126 -9
  25. package/dist/dialects/pg/compile.d.ts +1 -0
  26. package/dist/dialects/pg/custom.d.ts +6 -0
  27. package/dist/dialects/pg/filter-parse.d.ts +19 -0
  28. package/dist/dialects/pg/filters.d.ts +19 -0
  29. package/dist/dialects/pg/index.d.ts +11 -2
  30. package/dist/dialects/pg/index.js +159 -1063
  31. package/dist/dialects/pg/keys.d.ts +19 -3
  32. package/dist/dialects/pg/model.d.ts +223 -2
  33. package/dist/dialects/pg/operator-fit.d.ts +86 -0
  34. package/dist/dialects/pg/operators.d.ts +39 -1
  35. package/dist/dialects/pg/ops/arr-append.d.ts +9 -0
  36. package/dist/dialects/pg/ops/arr-ns.d.ts +7 -0
  37. package/dist/dialects/pg/ops/arr-remove.d.ts +9 -0
  38. package/dist/dialects/pg/ops/containedBy.d.ts +9 -0
  39. package/dist/dialects/pg/ops/contains.d.ts +8 -4
  40. package/dist/dialects/pg/ops/hasAnyKey.d.ts +8 -0
  41. package/dist/dialects/pg/ops/hasKey.d.ts +8 -0
  42. package/dist/dialects/pg/ops/json-ns.d.ts +6 -0
  43. package/dist/dialects/pg/ops/json-set.d.ts +12 -0
  44. package/dist/dialects/pg/ops/matches.d.ts +16 -0
  45. package/dist/dialects/pg/ops/overlaps.d.ts +9 -0
  46. package/dist/dialects/pg/ops/path.d.ts +13 -0
  47. package/dist/dialects/pg/preset.d.ts +76 -0
  48. package/dist/dialects/pg/relations.d.ts +59 -2
  49. package/dist/dialects/pg/schema.d.ts +109 -5
  50. package/dist/dialects/pg/table.d.ts +130 -11
  51. package/dist/dialects/pg/temporal.d.ts +9 -7
  52. package/dist/dialects/pg/tenancy.d.ts +94 -0
  53. package/dist/dialects/pg/through.d.ts +21 -0
  54. package/dist/dialects/pg/trait.d.ts +141 -0
  55. package/dist/dialects/pg/where.d.ts +37 -0
  56. package/dist/runtime/aggregate.d.ts +25 -0
  57. package/dist/runtime/archive-handle.d.ts +18 -0
  58. package/dist/runtime/archive-rules.d.ts +12 -0
  59. package/dist/runtime/archive.d.ts +73 -0
  60. package/dist/runtime/batch.d.ts +20 -0
  61. package/dist/runtime/client.d.ts +114 -5
  62. package/dist/runtime/conflict.d.ts +2 -1
  63. package/dist/runtime/exposure.d.ts +27 -0
  64. package/dist/runtime/hookm.d.ts +39 -0
  65. package/dist/runtime/ids/index.d.ts +11 -0
  66. package/dist/runtime/ids/index.js +193 -0
  67. package/dist/runtime/ids/okid-extended.d.ts +19 -0
  68. package/dist/runtime/ids/okid-generator.d.ts +21 -0
  69. package/dist/runtime/ids/okid-shared.d.ts +89 -0
  70. package/dist/runtime/ids/okid.d.ts +24 -0
  71. package/dist/runtime/ids/uuid.d.ts +21 -0
  72. package/dist/runtime/lock.d.ts +22 -0
  73. package/dist/runtime/operator-sql.d.ts +8 -0
  74. package/dist/runtime/page.d.ts +25 -0
  75. package/dist/runtime/pg/bun.d.ts +30 -0
  76. package/dist/runtime/pg/bun.js +52 -0
  77. package/dist/runtime/pg/pg.d.ts +29 -0
  78. package/dist/runtime/pg/pg.js +52 -0
  79. package/dist/runtime/pg/pglite.js +16 -17
  80. package/dist/runtime/pg/postgresjs.js +14 -24
  81. package/dist/runtime/plan.d.ts +146 -7
  82. package/dist/runtime/preset-stack.d.ts +17 -0
  83. package/dist/runtime/presets.d.ts +48 -0
  84. package/dist/runtime/read-stream.d.ts +26 -0
  85. package/dist/runtime/safety/index.d.ts +159 -0
  86. package/dist/runtime/safety/index.js +294 -0
  87. package/dist/runtime/safety-hook.d.ts +42 -0
  88. package/dist/runtime/server-check.d.ts +34 -0
  89. package/dist/runtime/tenancy/index.d.ts +37 -0
  90. package/dist/runtime/tenancy/index.js +365 -0
  91. package/dist/runtime/trait-read.d.ts +30 -0
  92. package/dist/runtime/traits/index.d.ts +128 -0
  93. package/dist/runtime/traits/index.js +509 -0
  94. package/dist/runtime/transaction.d.ts +19 -0
  95. package/dist/runtime/tx.d.ts +22 -7
  96. package/dist/runtime/types.d.ts +376 -27
  97. package/dist/runtime/validate/bind.d.ts +11 -0
  98. package/dist/runtime/validate/closed.d.ts +16 -0
  99. package/dist/runtime/validate/engine.d.ts +41 -0
  100. package/dist/runtime/validate/hook.d.ts +17 -0
  101. package/dist/runtime/validate/index.d.ts +21 -0
  102. package/dist/runtime/validate/index.js +175 -0
  103. package/dist/runtime/validate/load.d.ts +13 -0
  104. package/dist/runtime/validate/places.d.ts +41 -0
  105. package/dist/runtime/validate/rules.d.ts +108 -0
  106. package/dist/runtime/validate/surface.d.ts +102 -0
  107. package/dist/runtime/write.d.ts +30 -5
  108. package/dist/shared/{fgqgsb5z.js → 0qkxbm1f.js} +2 -2
  109. package/dist/shared/0v1g424p.js +26 -0
  110. package/dist/shared/10tjenmd.js +210 -0
  111. package/dist/shared/{xqbhg6cn.js → 1dp5knt7.js} +95 -10
  112. package/dist/shared/38crxbgn.js +229 -0
  113. package/dist/shared/3a5ne750.js +158 -0
  114. package/dist/shared/4b9da9d7.js +138 -0
  115. package/dist/shared/4e4c6vq2.js +62 -0
  116. package/dist/shared/{x5x59srr.js → 4jzzghr6.js} +416 -83
  117. package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
  118. package/dist/shared/{05w44d8g.js → 5z4q2zda.js} +567 -18
  119. package/dist/shared/672t5vym.js +12 -0
  120. package/dist/shared/7m88x3e9.js +45 -0
  121. package/dist/shared/7mht49yd.js +1091 -0
  122. package/dist/shared/{mtkwv8wx.js → 7p2wbz7f.js} +1 -1
  123. package/dist/shared/83eaefwr.js +10 -0
  124. package/dist/shared/96ps4g1z.js +32 -0
  125. package/dist/shared/97g2jnrw.js +76 -0
  126. package/dist/shared/{xy79j5hq.js → 9k6vetvf.js} +25 -36
  127. package/dist/shared/{w8samvk1.js → a1gdp7j9.js} +1 -1
  128. package/dist/shared/a5sxz52y.js +13 -0
  129. package/dist/shared/{dynq16vb.js → b066g80h.js} +8 -6
  130. package/dist/shared/cstgkzdx.js +154 -0
  131. package/dist/shared/{523ft3e8.js → d04j53v8.js} +6 -5
  132. package/dist/shared/{y9m15dfv.js → d2whjz4k.js} +15 -9
  133. package/dist/shared/dd4f8mnx.js +307 -0
  134. package/dist/shared/e6wg00wd.js +164 -0
  135. package/dist/shared/e7a268fy.js +195 -0
  136. package/dist/shared/{kprcwaha.js → eaxwrgby.js} +4 -3
  137. package/dist/shared/{dkn3y60a.js → ecdzej21.js} +76 -112
  138. package/dist/shared/{hadrfb9h.js → edwqqryd.js} +17 -14
  139. package/dist/shared/{m3ypagh5.js → eqmtn1bj.js} +57 -5
  140. package/dist/shared/g1b5zzj9.js +75 -0
  141. package/dist/shared/g9f0zqce.js +376 -0
  142. package/dist/shared/ge03bfca.js +64 -0
  143. package/dist/shared/{yd1kzwn2.js → jns2wx4t.js} +55 -12
  144. package/dist/shared/k3ted12y.js +33 -0
  145. package/dist/shared/k7dwkhvq.js +31 -0
  146. package/dist/shared/{hd293j9g.js → kyxb62mc.js} +14 -2
  147. package/dist/shared/m9tv7xn7.js +404 -0
  148. package/dist/shared/mrq77sgw.js +55 -0
  149. package/dist/shared/mxmcdsh5.js +450 -0
  150. package/dist/shared/n442h54c.js +14 -0
  151. package/dist/shared/n47rd821.js +442 -0
  152. package/dist/shared/n4jqhpqz.js +27 -0
  153. package/dist/shared/{mkjmqjv4.js → nfzc5z0w.js} +2 -104
  154. package/dist/shared/nsva2a6b.js +42 -0
  155. package/dist/shared/ps43134h.js +69 -0
  156. package/dist/shared/{8b04d28c.js → py3nh7jy.js} +2 -2
  157. package/dist/shared/qa5dsc7z.js +86 -0
  158. package/dist/shared/{g5fhqmwe.js → qxa0yb9j.js} +6 -4
  159. package/dist/shared/r6nwkxnt.js +86 -0
  160. package/dist/shared/{jjb7yht9.js → rtnaqre0.js} +3 -3
  161. package/dist/shared/rwmrejjz.js +26 -0
  162. package/dist/shared/{zhc5vmgf.js → s6gqfn5j.js} +2 -2
  163. package/dist/shared/sacqha1y.js +70 -0
  164. package/dist/shared/{qk3hxfja.js → sfh4pk75.js} +5 -5
  165. package/dist/shared/{j5cn2963.js → t4tbsy9h.js} +13 -64
  166. package/dist/shared/{ngk8gj61.js → tbszx8mz.js} +15 -1
  167. package/dist/shared/v18jva5b.js +90 -0
  168. package/dist/shared/x9v1qgeb.js +201 -0
  169. package/dist/shared/xatfg0gn.js +193 -0
  170. package/dist/shared/xkz8g6by.js +225 -0
  171. package/dist/shared/{rgs0st28.js → xrfnq5k8.js} +237 -434
  172. package/dist/shared/ytg3xf9p.js +149 -0
  173. package/dist/shared/yw5c610b.js +48 -0
  174. package/dist/shared/zd93g3rq.js +31 -0
  175. package/dist/shared/zt8y0wzb.js +132 -0
  176. package/dist/shared/{p0cbr3g2.js → zwmqxb0g.js} +1 -1
  177. package/dist/tooling/cli.js +14 -10
  178. package/dist/tooling/migrate/commands.d.ts +10 -0
  179. package/dist/tooling/migrate/engine.d.ts +36 -0
  180. package/package.json +41 -4
  181. package/dist/shared/gk7cs7sp.js +0 -566
package/README.md CHANGED
@@ -17,6 +17,7 @@ Version 0.1.1. Apache-2.0.
17
17
  - [Find](#find)
18
18
  - [Errors](#errors)
19
19
  - [Close](#close)
20
+ - [Keys](#keys)
20
21
  - [Commands](#commands)
21
22
  - [Roadmap](#roadmap)
22
23
  - [Size](#size)
@@ -24,19 +25,15 @@ Version 0.1.1. Apache-2.0.
24
25
 
25
26
  ## Install
26
27
 
27
- Install okmodel and the postgres.js driver.
28
+ Four Postgres drivers. Pick the one the runtime already has. postgres.js is the default, on Node and Bun. node-postgres is the other choice on Node and Bun when `pg` is already installed. Bun.sql is built into Bun and runs only there. PGlite is in-process, on Node and Bun.
28
29
 
29
30
  ```sh
30
31
  bun add okmodel postgres
31
- ```
32
-
33
- PGlite is the in-process driver.
34
-
35
- ```sh
32
+ bun add okmodel pg
36
33
  bun add okmodel @electric-sql/pglite
37
34
  ```
38
35
 
39
- okmodel has no runtime dependencies. The driver is a peer.
36
+ Bun.sql needs no extra package: `import { connect } from "okmodel/pg/bun"`. okmodel has no runtime dependencies. Each installed driver is an optional peer.
40
37
 
41
38
  ## Quickstart
42
39
 
@@ -66,6 +63,8 @@ export default defineConfig({
66
63
 
67
64
  `t.identity()` is the primary key. An insert omits the id, and the row that comes back carries it. Identity ids come back as strings by default. `t.identity({ as: "number" })` returns numbers. Push and reviewed migrations are two ways to do the same job: pick one per database.
68
65
 
66
+ Ids can also be generated in the application. Import `uuidv4`, `uuidv7`, or `okid` from `okmodel/ids` and pass one to `.default()`, or set `defaults.id` on `schema()` for every id column that does not choose its own. A column choice wins. A literal stays a database default. A generator is not stored in the catalog, so changing it does not create a migration, and an insert that bypasses okmodel has to supply the value. An OKID column is text with collation C, so a sortable id orders the same everywhere. Sortable ids include the time they were created.
67
+
69
68
  Tested on PostgreSQL 15 to 18.
70
69
 
71
70
  `schema.ts`:
@@ -162,6 +161,10 @@ if (row?.title !== "hello" || row.author?.name !== "Ada") {
162
161
  }
163
162
  ```
164
163
 
164
+ A jsonb filter uses `contains`, and the fragment stays a parameter: `{ meta: contains({ published: true }) }`. `json.set(["published"], true)` writes that path inside `update`. The column builder is `t.json()`; the `json` import is this write namespace.
165
+
166
+ An array column uses `contains` and `overlaps` the same way. `arr.append("news")` and `arr.remove("news")` add or remove one element inside `update`.
167
+
165
168
  ### Errors
166
169
 
167
170
  `safe` returns the `OkmError` instead of throwing when the author name is already used.
@@ -200,6 +203,14 @@ if (author.name !== "Lin" || author.id.length === 0) {
200
203
  await db.close();
201
204
  ```
202
205
 
206
+ ## Keys
207
+
208
+ `t.identity()` is a bigint identity primary key. Insert and update omit it. It works on every supported Postgres version. The quickstart uses it.
209
+
210
+ `t.id()` is a uuid primary key. The default is `uuidv7()`, which needs Postgres 18; on an older server `okm migrate apply` stops with OKM1812 before it runs any statement. `t.id({ default: "uuidv4" })` uses `gen_random_uuid()`, built in from Postgres 13. `t.id({ default: "none" })` takes the id on insert and omits it from update.
211
+
212
+ `.primaryKey()` on a column is a natural key. Insert supplies it. Update cannot change it. A composite key is the `primaryKey` option on the table, naming the columns in order.
213
+
203
214
  ## Commands
204
215
 
205
216
  | Command | What it does |
@@ -218,11 +229,13 @@ await db.close();
218
229
 
219
230
  ## Roadmap
220
231
 
221
- - [x] 0.1 — Schema, queries, and migrations on PostgreSQL, with postgres.js and PGlite.
222
- - [ ] 0.2 — Hidden and sensitive fields, validation, traits, tenancy, archive and restore, richer relations, presets, transactions, and operators for JSON, arrays, ranges, and search.
223
- - [ ] 0.3 — Extensions, domains, functions, triggers, views, roles, and grants.
224
- - [ ] 0.4 — Safer migration plans, backfill, drift checks, provisioning, reference data, and a testing package.
225
- - [ ] 0.5 — A primary with replicas, read routing, and a reference app.
232
+ Status is on the [board](https://github.com/users/omqkhafi/projects/1). Each release is a milestone.
233
+
234
+ - [x] [0.1](https://github.com/omqkhafi/okmodel/milestone/1) — Schema, queries, and migrations on PostgreSQL, with postgres.js and PGlite.
235
+ - [ ] [0.2](https://github.com/omqkhafi/okmodel/milestone/2) — Hidden and sensitive fields, validation, traits, tenancy, archive and restore, richer relations, presets, transactions, and operators for JSON, arrays, ranges, and search.
236
+ - [ ] [0.3](https://github.com/omqkhafi/okmodel/milestone/3) — Extensions, domains, functions, triggers, views, roles, and grants.
237
+ - [ ] [0.4](https://github.com/omqkhafi/okmodel/milestone/4) — Safer migration plans, backfill, drift checks, provisioning, reference data, and a testing package.
238
+ - [ ] [0.5](https://github.com/omqkhafi/okmodel/milestone/5) — A primary with replicas, read routing, and a reference app.
226
239
 
227
240
  `okmodel/internal` has no stability promise. Names on that subpath can change or disappear in any release.
228
241
 
@@ -232,10 +245,13 @@ Each limit, with the version that lifts it, is in [known limits](https://github.
232
245
 
233
246
  Measured on this release.
234
247
 
235
- | | Minified | Gzip | Cold import |
236
- | --------------------------------- | -------: | -----: | ----------: |
237
- | Runtime entry | 5,525 | 2,042 | 1.758 ms |
238
- | App startup (10 tables, one find) | 77,537 | 25,625 | 9.922 ms |
248
+ | | Minified | Gzip | Cold import |
249
+ | -------------------------------------------- | -------: | -----: | ----------: |
250
+ | Runtime entry | 5,288 | 2,026 | 1.991 ms |
251
+ | App startup (10 tables, one find) | 88,938 | 29,778 | 10.380 ms |
252
+ | App startup, every 0.2 feature in use (full) | 113,705 | 37,506 | 12.068 ms |
253
+
254
+ The full app has column tenancy, `archivable()`, `timestamps()`, validation rules, `one`, `many` and `manyThrough` relations, presets, and calls `include`, `page`, `aggregate`, `tx` and `batch`. A feature costs bytes only in an app that uses it: the full app is 24,767 minified and 7,728 gzip bytes above the plain one. The runtime entry and the plain app are gated. The full app is printed, not gated.
239
255
 
240
256
  The rest of the measurements are in [size](https://github.com/omqkhafi/okmodel/blob/main/docs/size.md).
241
257
 
@@ -41,6 +41,40 @@ export declare const PGLITE_CAPABILITIES: {
41
41
  readonly prepared: "unnamed";
42
42
  readonly describe: true;
43
43
  };
44
+ /**
45
+ * node-postgres execution flags.
46
+ *
47
+ * Interactive transactions, cursor streaming, listen, and cancel are set
48
+ * because the conformance suite passes them. Describe is false: `pg` cannot
49
+ * describe a statement without running it, and that case is skipped.
50
+ * Parameterized queries use the unnamed extended protocol.
51
+ */
52
+ export declare const NODE_POSTGRES_CAPABILITIES: {
53
+ readonly transactions: "interactive";
54
+ readonly stream: true;
55
+ readonly listen: true;
56
+ readonly cancel: true;
57
+ readonly prepared: "unnamed";
58
+ readonly describe: false;
59
+ };
60
+ /**
61
+ * Bun.sql execution flags.
62
+ *
63
+ * Interactive transactions, cursor streaming, and listen pass the conformance
64
+ * suite. `cancel` is false: `Query.cancel()` does not abort the backend
65
+ * (Bun 1.4), so the cancel and in-flight timeout cases are skipped.
66
+ * `describe` is false: Bun.sql has no describe API. RAISE NOTICE is not
67
+ * surfaced, so the notice case is skipped. `prepare` is off, so a
68
+ * parameterized query does not leave a named statement.
69
+ */
70
+ export declare const BUNSQL_CAPABILITIES: {
71
+ readonly transactions: "interactive";
72
+ readonly stream: true;
73
+ readonly listen: true;
74
+ readonly cancel: false;
75
+ readonly prepared: "unnamed";
76
+ readonly describe: false;
77
+ };
44
78
  /**
45
79
  * Reads one capability flag.
46
80
  *
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Reserved connections for Bun.sql.
3
+ *
4
+ * Loaded on the first reserve, batch, or stream. A read does not use it.
5
+ */
6
+ import type { DriverConnection } from "../../contracts/driver.js";
7
+ import { type HeldPool } from "./bunsql.js";
8
+ /**
9
+ * Checks out one connection and clears it on release.
10
+ *
11
+ * A connection that is gone is neither reset nor parked: Bun.sql has already
12
+ * dropped it, and parking it would hand a dead session to the next caller.
13
+ *
14
+ * @param held - The pool and its counters
15
+ * @returns A connection the caller must release
16
+ */
17
+ export declare function checkout(held: HeldPool): Promise<DriverConnection>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Bun.sql adapter (`okmodel/pg/bun`).
3
+ *
4
+ * Bun's built-in client. There is no package to install. This module is the
5
+ * only place that imports `bun`. It runs on Bun; another runtime cannot load
6
+ * that import.
7
+ *
8
+ * `idleTimeout` stays 0, which is Bun's default: no idle timer, and a
9
+ * finished script exits without `close()`. `Query.cancel()` does not abort
10
+ * the backend, so `cancel` is false. Server notices are not surfaced.
11
+ */
12
+ import { SQL, type ReservedSQL } from "bun";
13
+ import type { DriverPool, DriverPoolConfig, WireValue } from "../../contracts/driver.js";
14
+ import { noticeBuffer, type WireQuery } from "./session.js";
15
+ export { BUNSQL_CAPABILITIES as capabilities, hasCapability, readCapability, } from "../capabilities.js";
16
+ export { DriverError } from "../error.js";
17
+ /** TLS values Bun.sql accepts that this adapter forwards. */
18
+ export type BunSqlTls = boolean | "disable" | "allow" | "prefer" | "require" | "verify-ca" | "verify-full";
19
+ /** Options for {@link open}. */
20
+ export type BunSqlConfig = DriverPoolConfig & {
21
+ /** Connection URL for this endpoint. */
22
+ readonly url: string;
23
+ /**
24
+ * Named prepared statements, or the unnamed protocol.
25
+ *
26
+ * Unnamed is the default (`prepare: false`). `prepared: "named"` is not
27
+ * for transaction-mode poolers.
28
+ */
29
+ readonly prepared?: "named" | "unnamed";
30
+ /** Session search path for every connection in the pool. */
31
+ readonly searchPath?: string;
32
+ /** TLS mode passed to Bun.sql. */
33
+ readonly ssl?: BunSqlTls;
34
+ };
35
+ /** What a checkout needs from the pool that opened it. */
36
+ export type HeldPool = {
37
+ readonly sql: SQL;
38
+ readonly parked: ReservedSQL[];
39
+ readonly acquireMs: number | undefined;
40
+ readonly counters: Counters;
41
+ readonly notices: ReturnType<typeof noticeBuffer>;
42
+ readonly isClosed: () => boolean;
43
+ };
44
+ /** Pool occupancy. */
45
+ export type Counters = {
46
+ reserved: number;
47
+ busy: number;
48
+ reservedBusy: number;
49
+ waiting: number;
50
+ };
51
+ /**
52
+ * Opens a Bun.sql pool for one endpoint.
53
+ *
54
+ * @param config - URL, pool size, and acquire timeout
55
+ * @returns The pool
56
+ */
57
+ export declare function open(config: BunSqlConfig): DriverPool;
58
+ export declare function send(sql: SQL, text: string, params: readonly WireValue[] | undefined): WireQuery;
59
+ export declare function reserve(sql: SQL, acquireMs: number | undefined, counters: Counters): Promise<ReservedSQL>;
60
+ export declare function park(parked: ReservedSQL[], reserved: ReservedSQL): Promise<void>;
@@ -28,24 +28,14 @@ export declare function needsWatch(options: ExecuteOptions | undefined): boolean
28
28
  /**
29
29
  * Next transaction depth after one statement.
30
30
  *
31
- * Only a whole command matches, so `ROLLBACK TO SAVEPOINT` stays inside the
32
- * transaction. Kept here so a read does not load the batch runner.
31
+ * `BEGIN` may carry modes (`begin isolation level serializable`). `ROLLBACK TO
32
+ * SAVEPOINT` stays inside the transaction. Kept here so a read does not load the batch runner.
33
33
  *
34
34
  * @param depth - Depth before the statement
35
35
  * @param text - Statement text
36
36
  * @returns Depth after a successful statement
37
37
  */
38
38
  export declare function nextTransactionDepth(depth: number, text: string): number;
39
- /**
40
- * Opens a watch for one call.
41
- *
42
- * The caller has already rejected a pre-aborted signal and a non-positive
43
- * timeout.
44
- *
45
- * @param options - Options that include a signal or a timeout
46
- * @returns The watch. The caller must {@link Watch.finish} it
47
- */
48
- export declare function openWatch(options: ExecuteOptions): Watch;
49
39
  /**
50
40
  * Runs `fn` with a watch when the caller set a signal or a timeout.
51
41
  *
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Reserved connections for node-postgres.
3
+ *
4
+ * Loaded on the first reserve, batch, or stream. A read does not use it.
5
+ */
6
+ import type { DriverConnection } from "../../contracts/driver.js";
7
+ import { type HeldPool } from "./nodepostgres.js";
8
+ /**
9
+ * Checks out one client and clears it on release.
10
+ *
11
+ * A client whose connection is gone is destroyed on release, and nothing more is
12
+ * sent to it. A checked-out client has no pool error listener, so one is set here:
13
+ * without it a dropped socket is an uncaught `error` event.
14
+ *
15
+ * @param held - The pool and its counters
16
+ * @returns A connection the caller must release
17
+ */
18
+ export declare function checkout(held: HeldPool): Promise<DriverConnection>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * node-postgres adapter (`okmodel/pg/pg`).
3
+ *
4
+ * One pool per `open` call. `pg` is an optional peer of this entry.
5
+ * Idle clients are unref'd (`allowExitOnIdle`) and are not closed on a timer
6
+ * (`idleTimeoutMillis: 0`), so a finished script exits and a live process
7
+ * keeps its connection. Cancel sends a Postgres CancelRequest on a side
8
+ * socket. That socket is unref'd.
9
+ */
10
+ import pg, { type PoolClient, type QueryConfig, type QueryResult } from "pg";
11
+ import type { DriverPool, DriverPoolConfig, WireValue } from "../../contracts/driver.js";
12
+ import { noticeBuffer, type WireQuery } from "./session.js";
13
+ export { hasCapability, NODE_POSTGRES_CAPABILITIES as capabilities, readCapability, } from "../capabilities.js";
14
+ export { DriverError } from "../error.js";
15
+ /** Options for {@link open}. */
16
+ export type NodePostgresConfig = DriverPoolConfig & {
17
+ /** Connection URL for this endpoint. */
18
+ readonly url: string;
19
+ /**
20
+ * Named prepared statements, or the unnamed protocol.
21
+ *
22
+ * Unnamed is the default. It stays valid behind a pooler in transaction mode.
23
+ * `prepared: "named"` is not for transaction-mode poolers.
24
+ */
25
+ readonly prepared?: "named" | "unnamed";
26
+ /** Session search path for every connection in the pool. */
27
+ readonly searchPath?: string;
28
+ /** TLS mode passed to node-postgres. */
29
+ readonly ssl?: boolean | "require" | "allow" | "prefer" | "verify-full" | object;
30
+ };
31
+ /** What a checkout needs from the pool that opened it. */
32
+ export type HeldPool = {
33
+ readonly pool: InstanceType<typeof pg.Pool>;
34
+ readonly acquireMs: number | undefined;
35
+ readonly counters: Counters;
36
+ readonly notices: ReturnType<typeof noticeBuffer>;
37
+ readonly named: boolean;
38
+ readonly isClosed: () => boolean;
39
+ };
40
+ /** Pool occupancy. */
41
+ export type Counters = {
42
+ reserved: number;
43
+ busy: number;
44
+ reservedBusy: number;
45
+ waiting: number;
46
+ };
47
+ /**
48
+ * Opens a node-postgres pool for one endpoint.
49
+ *
50
+ * @param config - URL, pool size, and acquire timeout
51
+ * @returns The pool
52
+ */
53
+ export declare function open(config: NodePostgresConfig): DriverPool;
54
+ export declare function send(runner: {
55
+ query(config: QueryConfig): Promise<QueryResult>;
56
+ }, text: string, params: readonly WireValue[] | undefined, named: boolean, client: PoolClient | undefined): WireQuery;
57
+ export declare function connectClient(pool: InstanceType<typeof pg.Pool>, acquireMs: number | undefined, counters: Counters): Promise<PoolClient>;
@@ -4,7 +4,8 @@
4
4
  * Loaded on the first reserve, batch, describe, or stream.
5
5
  */
6
6
  import type { Sql } from "postgres";
7
- import type { DescribeResult, DriverConnection, WireValue } from "../../contracts/driver.js";
7
+ import type { DescribeResult, DriverConnection, ExecuteResult, WireValue } from "../../contracts/driver.js";
8
+ import { type Watch } from "./call.js";
8
9
  import { type Canceller, type Counters, type NoticeBuffer } from "./postgresjs.js";
9
10
  /** State `open` shares with a checkout. */
10
11
  export type HeldPool = {
@@ -41,3 +42,51 @@ export declare function describe(sql: Sql, text: string, params?: readonly WireV
41
42
  * @returns Chunks of wire rows
42
43
  */
43
44
  export declare function stream(sql: Sql, text: string, params?: readonly WireValue[]): AsyncIterable<readonly (readonly WireValue[])[]>;
45
+ /** Refcount a checkout or a listener borrows from the pool. */
46
+ type Gate = {
47
+ enter(): void;
48
+ leave(): void;
49
+ };
50
+ /**
51
+ * Keeps sockets referenced until `release` finishes.
52
+ *
53
+ * The caller has already entered `gate`. A second `release` does not change
54
+ * the count. Checkout failure leaves the gate.
55
+ *
56
+ * @param gate - Refcount already entered for this checkout
57
+ * @param checkout - Reserves the connection
58
+ * @returns The connection, with release counted once
59
+ */
60
+ export declare function holdCheckout<T extends {
61
+ release(): Promise<void>;
62
+ }>(gate: Gate, checkout: () => Promise<T>): Promise<T>;
63
+ /**
64
+ * Keeps sockets referenced for as long as the listener is active.
65
+ *
66
+ * The caller has already entered `gate`.
67
+ *
68
+ * @param gate - Listener refcount already entered
69
+ * @param start - Subscribes and returns the stop function
70
+ * @returns A stop function that can be called again
71
+ */
72
+ export declare function holdListener(gate: Gate, start: () => Promise<() => Promise<void>>): Promise<() => Promise<void>>;
73
+ /**
74
+ * Finishes a query that can be aborted by a signal or a timeout.
75
+ *
76
+ * The caller has already tracked `pending` and attached `onAbort`.
77
+ *
78
+ * @param pending - The in-flight statement
79
+ * @param watch - Abort signal and the reason it fired
80
+ * @param onAbort - Listener the caller attached
81
+ * @param ctx - Notice slice and the session counters the plain path also uses
82
+ * @returns The wire result, or a rejected driver error
83
+ */
84
+ export declare function watchQuery(pending: Canceller & Promise<unknown>, watch: Watch, onAbort: () => void, ctx: {
85
+ readonly start: number;
86
+ readonly text: string;
87
+ readonly notices: NoticeBuffer;
88
+ leave(): void;
89
+ note(text: string): void;
90
+ untrack(pending: Canceller): void;
91
+ }): Promise<ExecuteResult>;
92
+ export {};
@@ -88,8 +88,4 @@ export declare class PgSession implements BatchSession {
88
88
  private note;
89
89
  private enter;
90
90
  private leave;
91
- private track;
92
- private untrack;
93
- private watched;
94
- private finishWatched;
95
91
  }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Shared interactive session for drivers that speak wire text.
3
+ *
4
+ * The postgres.js adapter keeps its own session. node-postgres and Bun.sql
5
+ * share this one: transaction depth, notices, and a watched cancel.
6
+ */
7
+ import type { ExecuteResult, Notice, WireValue } from "../../contracts/driver.js";
8
+ import type { BatchSession } from "./batch.js";
9
+ import type { Watch } from "./call.js";
10
+ /** A query the session can abort when the driver supports it. */
11
+ export type WireQuery = Promise<unknown> & {
12
+ cancel?(): void;
13
+ };
14
+ /** Sends one statement and returns the driver's own result. */
15
+ export type WireSender = (text: string, params: readonly WireValue[] | undefined) => WireQuery;
16
+ /** Notice slice shared by a pool. */
17
+ export type NoticeBuffer = {
18
+ start(): number;
19
+ since(start: number): readonly Notice[];
20
+ push(notice: {
21
+ readonly severity?: string | undefined;
22
+ readonly message?: string | undefined;
23
+ readonly code?: string | undefined;
24
+ }): void;
25
+ };
26
+ /**
27
+ * Quotes one identifier.
28
+ *
29
+ * @param name - Channel or cursor name
30
+ * @returns A double-quoted identifier
31
+ */
32
+ export declare function quoteIdent(name: string): string;
33
+ /**
34
+ * An empty notice buffer the pool fills as the server sends notices.
35
+ *
36
+ * @returns The buffer
37
+ */
38
+ export declare function noticeBuffer(): NoticeBuffer;
39
+ /**
40
+ * One connection's statement runner.
41
+ *
42
+ * `send` is the driver. This class owns depth, notices, and cancel tracking.
43
+ */
44
+ export declare class WireSession implements BatchSession {
45
+ readonly canCancel: boolean;
46
+ private transactionDepth;
47
+ private readonly local;
48
+ private readonly send;
49
+ private readonly notices;
50
+ private readonly isClosed;
51
+ private readonly onEnter;
52
+ private readonly onLeave;
53
+ private readonly shared;
54
+ /**
55
+ * @param send - Runs one statement on this connection
56
+ * @param notices - Pool notice buffer
57
+ * @param isClosed - Pool closed flag
58
+ * @param canCancel - The driver aborts an in-flight statement
59
+ * @param onEnter - Marks one statement in flight
60
+ * @param onLeave - Marks that statement finished
61
+ * @param shared - Pool-wide in-flight set, when this connection is reserved
62
+ */
63
+ constructor(send: WireSender, notices: NoticeBuffer, isClosed: () => boolean, canCancel: boolean, onEnter: () => void, onLeave: () => void, shared?: Set<WireQuery>);
64
+ /** @inheritdoc */
65
+ query(text: string, params: readonly WireValue[] | undefined, watch: Watch | undefined): Promise<ExecuteResult>;
66
+ /** @inheritdoc */
67
+ inTransaction(): boolean;
68
+ /** @inheritdoc */
69
+ abandon(): void;
70
+ /**
71
+ * Open transaction depth.
72
+ *
73
+ * @returns The depth. Zero means no transaction
74
+ */
75
+ depth(): number;
76
+ /** Aborts in-flight statements on this connection. */
77
+ cancel(): void;
78
+ private note;
79
+ private track;
80
+ private untrack;
81
+ private watched;
82
+ private finishWatched;
83
+ }
84
+ /**
85
+ * Yields cursor chunks from one connection that is already checked out.
86
+ *
87
+ * The cursor is session-local. `ROLLBACK` in the end drops it.
88
+ *
89
+ * @param run - Executes on the checked-out connection
90
+ * @param text - Query to stream
91
+ * @param params - Wire parameters
92
+ * @returns Chunks of wire rows
93
+ */
94
+ export declare function cursorStream(run: (text: string, params?: readonly WireValue[]) => Promise<ExecuteResult>, text: string, params: readonly WireValue[] | undefined): AsyncIterable<readonly (readonly WireValue[])[]>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Deadline and abort signal for one call.
3
+ *
4
+ * Loaded the first time a call passes `signal` or `timeout`. A plain execute
5
+ * does not load it.
6
+ */
7
+ import type { ExecuteOptions } from "../../contracts/driver.js";
8
+ import type { Watch } from "./call.js";
9
+ /**
10
+ * Opens a watch for one call.
11
+ *
12
+ * The caller has already rejected a pre-aborted signal and a non-positive
13
+ * timeout.
14
+ *
15
+ * @param options - Options that include a signal or a timeout
16
+ * @returns The watch. The caller must {@link Watch.finish} it
17
+ */
18
+ export declare function openWatch(options: ExecuteOptions): Watch;
@@ -25,6 +25,7 @@ export type ColumnInput = CommonInput & {
25
25
  readonly dataType: string;
26
26
  readonly nullable: boolean;
27
27
  readonly defaultExpression?: string;
28
+ readonly collation?: string;
28
29
  readonly identity?: {
29
30
  readonly always: boolean;
30
31
  };
@@ -132,16 +132,16 @@ export type ExtensionIdentity = {
132
132
  };
133
133
  /** Stable identity. The variant depends on the kind. */
134
134
  export type ObjectIdentity = NamespaceIdentity | AnchoredIdentity | FunctionIdentity | GrantIdentity | DefaultPrivilegeIdentity | RoleIdentity | ExtensionIdentity;
135
- /** Where an object came from. */
135
+ /**
136
+ * Where an object, a query, or a rule came from.
137
+ *
138
+ * `source` is the authoring location (`schema.ts:12`). It is recorded when
139
+ * the object is defined and is not part of the catalog hash.
140
+ */
136
141
  export type Provenance = {
137
- readonly origin: "file";
138
- readonly name: string;
139
- } | {
140
- readonly origin: "trait";
141
- readonly name: string;
142
- } | {
143
- readonly origin: "extension";
142
+ readonly origin: "file" | "trait" | "extension";
144
143
  readonly name: string;
144
+ readonly source?: string;
145
145
  };
146
146
  /**
147
147
  * An edge to another object.
@@ -179,6 +179,13 @@ export type ColumnDefinition = {
179
179
  readonly stored: boolean;
180
180
  readonly expression: string;
181
181
  };
182
+ /**
183
+ * Collation name, such as `C`.
184
+ *
185
+ * Absent when the column uses the type's default collation. A client
186
+ * generator is not stored here.
187
+ */
188
+ readonly collation?: string;
182
189
  };
183
190
  /**
184
191
  * Index definition.
@@ -31,3 +31,16 @@ export declare function isConnectionErrno(code: string): boolean;
31
31
  * @returns `true` when no session remains
32
32
  */
33
33
  export declare function isConnectionFailure(error: unknown): boolean;
34
+ /**
35
+ * Reports whether the connection is gone after `error`, or the outcome of a
36
+ * statement on it is unknown (`outcome_unknown`).
37
+ *
38
+ * It reads what {@link isConnectionFailure} reads, plus the messages node-postgres
39
+ * ("Connection terminated unexpectedly") and Bun.sql (`ERR_POSTGRES_CONNECTION_CLOSED`)
40
+ * give, and the error's `cause`. Nothing more should be sent to such a connection:
41
+ * not a rollback, not a reset. Loaded with the code that reserves a connection.
42
+ *
43
+ * @param error - Caught value
44
+ * @returns `true` when the session cannot be used again
45
+ */
46
+ export declare function isConnectionLost(error: unknown): boolean;
@@ -154,10 +154,23 @@ export type DriverPoolConfig = {
154
154
  /** Connections in the pool. PGlite is always one. */
155
155
  readonly max?: number;
156
156
  /**
157
- * Wait for a connection up to `acquire` milliseconds, then fail with
158
- * OKM1846. Omitted means wait without that deadline.
157
+ * Ceilings in milliseconds. An adapter reads `acquire`: it waits for a
158
+ * connection up to that long, then fails with OKM1846. Omitted means wait
159
+ * without a deadline. The other keys belong to the runtime.
159
160
  */
160
- readonly timeouts?: {
161
- readonly acquire?: number;
162
- };
161
+ readonly timeouts?: DriverTimeouts;
162
+ };
163
+ /**
164
+ * Ceilings from `connect({ timeouts })`, in milliseconds (spec §15).
165
+ *
166
+ * `acquire` bounds the wait for a connection (OKM1846). `statement` is the
167
+ * default `timeout` of a call that sets none. `transaction` bounds a whole
168
+ * `tx()`. `idleInTransaction` bounds the time a `tx()` waits between
169
+ * statements. Every one but `acquire` fails as kind `timeout`.
170
+ */
171
+ export type DriverTimeouts = {
172
+ readonly acquire?: number;
173
+ readonly statement?: number;
174
+ readonly transaction?: number;
175
+ readonly idleInTransaction?: number;
163
176
  };
@@ -31,7 +31,7 @@ export type ColumnCode = (typeof COLUMN_CODES)[number];
31
31
  * These are spec §21 codes. They are a type only, so the runtime entry does
32
32
  * not gain a second registry.
33
33
  */
34
- export type QueryCode = "OKM1101" | "OKM1102" | "OKM1104" | "OKM1105" | "OKM1111" | "OKM1120" | "OKM1121" | "OKM1190" | "OKM1801" | "OKM1802" | "OKM1843";
34
+ export type QueryCode = "OKM1101" | "OKM1102" | "OKM1104" | "OKM1105" | "OKM1111" | "OKM1120" | "OKM1121" | "OKM1124" | "OKM1130" | "OKM1190" | "OKM1701" | "OKM1704" | "OKM1801" | "OKM1802" | "OKM1803" | "OKM1843";
35
35
  /** Kinds from spec §14, in category order. */
36
36
  export declare const ERROR_KINDS: readonly ["invalid", "not_null", "check", "foreign_key", "unique", "exclusion", "conflict", "not_found", "not_unique", "forbidden", "serialization", "deadlock", "lock_timeout", "timeout", "cancelled", "unavailable", "schema_drift", "driver", "read_only", "outcome_unknown"];
37
37
  /** One spec §14 kind. */
@@ -51,6 +51,16 @@ export type ErrorFix = {
51
51
  /** Accepted name to use instead, when one is close. */
52
52
  readonly suggestion?: string;
53
53
  };
54
+ /**
55
+ * One failed validation check.
56
+ *
57
+ * `message` is a key, never prose and never a row value. `path` walks the
58
+ * value: a field name, or a row index then a field name.
59
+ */
60
+ export type ValidationIssue = {
61
+ readonly path: readonly (string | number)[];
62
+ readonly message: string;
63
+ };
54
64
  /** Column name to constraint reason. Row values are not included. */
55
65
  export type ErrorFields = Readonly<Record<string, string>>;
56
66
  /** Body of {@link OkmError.toHttp}. */
@@ -80,6 +90,8 @@ export type ErrorLog = {
80
90
  readonly batchIndex: number | null;
81
91
  readonly fix: ErrorFix;
82
92
  readonly fields: ErrorFields;
93
+ /** Validation checks, when the failure is OKM1200. */
94
+ readonly issues?: readonly ValidationIssue[];
83
95
  readonly table?: string;
84
96
  readonly columns?: readonly string[];
85
97
  readonly constraint?: string;
@@ -105,6 +117,8 @@ export type OkmErrorOptions = {
105
117
  */
106
118
  readonly includeValues?: boolean;
107
119
  readonly values?: Readonly<Record<string, string>>;
120
+ /** Checks from a failed validation. Omitted on every other error. */
121
+ readonly issues?: readonly ValidationIssue[];
108
122
  /**
109
123
  * Category overrides from `connect({ errors })`.
110
124
  *
@@ -164,6 +178,8 @@ export declare class OkmError extends Error {
164
178
  readonly batchIndex: number | null;
165
179
  /** Constraint reason used by {@link fields}. */
166
180
  readonly fieldReason: string;
181
+ /** Validation checks. Absent when this error is not a failed check. */
182
+ readonly issues?: readonly ValidationIssue[];
167
183
  /**
168
184
  * Same text as `message`.
169
185
  *