okmodel 0.1.0 → 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 +237 -19
  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 +390 -25
  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/{tb4ze1tr.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/{ckb1p0a4.js → 4jzzghr6.js} +416 -83
  117. package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
  118. package/dist/shared/{kynx7vbm.js → 5z4q2zda.js} +604 -21
  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/{ax16zpvm.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/{vkm3q4x1.js → eaxwrgby.js} +4 -3
  137. package/dist/shared/{7ck0dtry.js → ecdzej21.js} +160 -81
  138. package/dist/shared/{px90pf9p.js → edwqqryd.js} +21 -16
  139. package/dist/shared/{g2v6gnc8.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/{79ggp945.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/{4j72449d.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/{f5thc1s0.js → xrfnq5k8.js} +237 -418
  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 +56 -4
  181. package/dist/shared/gk7cs7sp.js +0 -566
@@ -0,0 +1,376 @@
1
+ import {
2
+ isConnectionLost
3
+ } from "./tbszx8mz.js";
4
+ import {
5
+ openClient,
6
+ withHttp,
7
+ settleCall
8
+ } from "./mxmcdsh5.js";
9
+ import {
10
+ rejectKeys,
11
+ isRecord,
12
+ fail
13
+ } from "./xrfnq5k8.js";
14
+ import {
15
+ OkmError2
16
+ } from "./52szzakm.js";
17
+
18
+ // src/runtime/transaction.ts
19
+ var BEGIN = {
20
+ "read committed": "BEGIN ISOLATION LEVEL READ COMMITTED",
21
+ "repeatable read": "BEGIN ISOLATION LEVEL REPEATABLE READ",
22
+ serializable: "BEGIN ISOLATION LEVEL SERIALIZABLE"
23
+ };
24
+
25
+ class Frame {
26
+ done = false;
27
+ failed = undefined;
28
+ stopped = undefined;
29
+ savepoints = 0;
30
+ signal;
31
+ abort;
32
+ active = 0;
33
+ halt;
34
+ idle = undefined;
35
+ cut = () => {
36
+ return;
37
+ };
38
+ conn;
39
+ idleMs;
40
+ constructor(conn, idleMs, stoppable) {
41
+ this.conn = conn;
42
+ this.idleMs = idleMs;
43
+ this.abort = stoppable ? new AbortController : undefined;
44
+ this.signal = this.abort?.signal;
45
+ this.halt = new Promise((_, reject) => {
46
+ this.cut = reject;
47
+ });
48
+ this.halt.catch(() => {
49
+ return;
50
+ });
51
+ }
52
+ stop(error) {
53
+ if (this.done || this.stopped !== undefined)
54
+ return;
55
+ this.stopped = error;
56
+ this.abort?.abort();
57
+ this.cut(error);
58
+ }
59
+ check() {
60
+ if (this.done) {
61
+ throw new OkmError2("driver", "The transaction has finished. Use the client the callback received only while the callback runs.", { kind: "driver" });
62
+ }
63
+ if (this.stopped !== undefined)
64
+ throw this.stopped;
65
+ }
66
+ enter() {
67
+ this.active += 1;
68
+ this.rest();
69
+ }
70
+ leave() {
71
+ this.active -= 1;
72
+ if (this.active === 0)
73
+ this.arm();
74
+ }
75
+ arm() {
76
+ this.rest();
77
+ if (this.idleMs === undefined || this.done || this.active > 0)
78
+ return;
79
+ this.idle = setTimeout(() => {
80
+ this.stop(new OkmError2("timeout", `The transaction sat idle for ${String(this.idleMs)} ms (timeouts.idleInTransaction).`, { kind: "timeout" }));
81
+ }, this.idleMs);
82
+ }
83
+ rest() {
84
+ if (this.idle !== undefined)
85
+ clearTimeout(this.idle);
86
+ this.idle = undefined;
87
+ }
88
+ note(error, whole) {
89
+ const kind = error?.kind;
90
+ if (!whole || kind === "cancelled" || kind === "timeout")
91
+ this.failed ??= error;
92
+ }
93
+ }
94
+ async function tx(session, args) {
95
+ const fn = typeof args[0] === "function" ? args[0] : args[1];
96
+ const given = typeof args[0] === "function" ? {} : args[0] ?? {};
97
+ try {
98
+ if (typeof fn !== "function")
99
+ fail("OKM1121", "tx expects a callback: tx(fn) or tx(options, fn).");
100
+ if (!isRecord(given))
101
+ fail("OKM1121", "tx options must be an object.");
102
+ rejectKeys(given, ["isolation", "retry", "signal", "timeout"], "tx");
103
+ const options = given;
104
+ check(options);
105
+ const call = fn;
106
+ return session.tx === undefined ? await outer(session, call, options) : await nested(session, call, options);
107
+ } catch (error) {
108
+ return failWith(session, error);
109
+ }
110
+ }
111
+ function failWith(session, error) {
112
+ if (error instanceof OkmError2 || !(error instanceof Error) || error.name !== "DriverError") {
113
+ return Promise.reject(error);
114
+ }
115
+ return settleCall(session, error);
116
+ }
117
+ function check(options) {
118
+ if (options.isolation !== undefined && !Object.hasOwn(BEGIN, options.isolation)) {
119
+ fail("OKM1120", `isolation must be one of: ${Object.keys(BEGIN).join(", ")}.`);
120
+ }
121
+ const { retry, timeout } = options;
122
+ if (retry !== undefined && (!Number.isInteger(retry) || retry < 0)) {
123
+ fail("OKM1121", "retry must be an integer from 0 up.");
124
+ }
125
+ if (timeout !== undefined && (typeof timeout !== "number" || !(timeout > 0))) {
126
+ fail("OKM1121", "timeout must be a number of milliseconds above 0.");
127
+ }
128
+ }
129
+ async function outer(session, fn, options) {
130
+ const pool = session.pool;
131
+ if (pool.reserve === undefined || pool.capabilities.transactions !== "interactive") {
132
+ throw new OkmError2("OKM1111", `tx() needs a driver with transactions: "interactive". This driver has "${pool.capabilities.transactions}".`, withHttp(session.http, {
133
+ fix: { summary: "Use batch() for an atomic unit on this driver." }
134
+ }));
135
+ }
136
+ await session.connected;
137
+ const started = Date.now();
138
+ const limit = options.timeout ?? session.timeouts?.transaction;
139
+ const deadline = limit === undefined ? undefined : started + limit;
140
+ const retries = options.retry ?? 0;
141
+ for (let attempt = 0;; attempt += 1) {
142
+ try {
143
+ return await once(session, fn, options, deadline);
144
+ } catch (error) {
145
+ const kind = error instanceof OkmError2 ? error.kind : undefined;
146
+ if (attempt >= retries || kind !== "serialization" && kind !== "deadlock")
147
+ throw error;
148
+ await pause(attempt);
149
+ if (options.signal?.aborted === true)
150
+ throw cancelled();
151
+ if (deadline !== undefined && Date.now() >= deadline)
152
+ throw timedOut();
153
+ }
154
+ }
155
+ }
156
+ function pause(attempt) {
157
+ const ms = Math.random() * Math.min(100, 4 * 2 ** attempt);
158
+ return new Promise((resolve) => setTimeout(resolve, ms));
159
+ }
160
+ function cancelled() {
161
+ return new OkmError2("cancelled", "The transaction was cancelled.", { kind: "cancelled" });
162
+ }
163
+ function timedOut() {
164
+ return new OkmError2("timeout", "The transaction timed out.", { kind: "timeout" });
165
+ }
166
+ async function once(session, fn, options, deadline) {
167
+ const signal = options.signal;
168
+ if (signal?.aborted === true)
169
+ throw cancelled();
170
+ if (deadline !== undefined && Date.now() >= deadline)
171
+ throw timedOut();
172
+ const conn = await reserve(session);
173
+ const frame = new Frame(conn, session.timeouts?.idleInTransaction, signal !== undefined || deadline !== undefined);
174
+ const after = [];
175
+ const hear = session.hookm === undefined ? undefined : await import("./96ps4g1z.js");
176
+ const onAbort = () => frame.stop(cancelled());
177
+ signal?.addEventListener("abort", onAbort, { once: true });
178
+ const timer = deadline === undefined ? undefined : setTimeout(() => frame.stop(timedOut()), deadline - Date.now());
179
+ let began = false;
180
+ let committing = false;
181
+ let committed = false;
182
+ try {
183
+ await step(session, frame, options.isolation === undefined ? "BEGIN" : BEGIN[options.isolation]);
184
+ began = true;
185
+ hear?.phase(session.hookm, "start", 0);
186
+ frame.arm();
187
+ const t = openClient(held(session, frame, after, 0));
188
+ const value = await Promise.race([fn(t), frame.halt]);
189
+ frame.check();
190
+ if (frame.failed !== undefined)
191
+ throw frame.failed;
192
+ frame.rest();
193
+ committing = true;
194
+ await commit(session, frame);
195
+ committed = true;
196
+ return value;
197
+ } catch (error) {
198
+ if (began && !committed) {
199
+ if (!committing)
200
+ await frame.conn.execute("ROLLBACK").catch(() => {
201
+ return;
202
+ });
203
+ if (!(error instanceof OkmError2 && error.kind === "outcome_unknown")) {
204
+ hear?.phase(session.hookm, "rollback", 0);
205
+ }
206
+ }
207
+ return await failWith(session, error);
208
+ } finally {
209
+ frame.rest();
210
+ frame.done = true;
211
+ if (timer !== undefined)
212
+ clearTimeout(timer);
213
+ signal?.removeEventListener("abort", onAbort);
214
+ try {
215
+ await conn.release();
216
+ } catch (error) {
217
+ hear?.report(session, error);
218
+ }
219
+ if (committed) {
220
+ hear?.phase(session.hookm, "commit", 0);
221
+ await run(session, after, hear);
222
+ }
223
+ }
224
+ }
225
+ async function reserve(session) {
226
+ try {
227
+ return await session.pool.reserve();
228
+ } catch (error) {
229
+ return failWith(session, error);
230
+ }
231
+ }
232
+ function step(session, frame, text) {
233
+ return frame.conn.execute(text).catch((error) => failWith(session, error));
234
+ }
235
+ async function commit(session, frame) {
236
+ try {
237
+ await frame.conn.execute("COMMIT");
238
+ } catch (error) {
239
+ if (isConnectionLost(error)) {
240
+ throw new OkmError2("OKM1401", "The commit was sent and its result never arrived. The transaction may or may not have committed.", withHttp(session.http, {
241
+ kind: "outcome_unknown",
242
+ cause: error,
243
+ fix: {
244
+ summary: "Check whether the write landed, using an idempotency key, before retrying."
245
+ }
246
+ }));
247
+ }
248
+ throw error;
249
+ }
250
+ }
251
+ async function run(session, after, hear) {
252
+ for (const callback of after) {
253
+ try {
254
+ await callback();
255
+ } catch (error) {
256
+ if (hear !== undefined)
257
+ hear.report(session, error);
258
+ else
259
+ (await import("./96ps4g1z.js")).report(session, error);
260
+ }
261
+ }
262
+ }
263
+ async function nested(session, fn, options) {
264
+ if (Object.keys(options).length > 0) {
265
+ fail("OKM1121", "isolation, retry, timeout, and signal belong to the outermost tx(). A nested tx() is a savepoint on the same transaction.");
266
+ }
267
+ const { state: frame, depth } = session.tx;
268
+ frame.check();
269
+ frame.savepoints += 1;
270
+ const name = `okm_t${String(frame.savepoints)}`;
271
+ const hear = session.hookm === undefined ? undefined : await import("./96ps4g1z.js");
272
+ const saved = frame.failed;
273
+ const after = [];
274
+ let released = false;
275
+ try {
276
+ await step(session, frame, `SAVEPOINT ${name}`);
277
+ hear?.phase(session.hookm, "start", depth + 1);
278
+ const t = openClient(held(session, frame, after, depth + 1));
279
+ const value = await Promise.race([fn(t), frame.halt]);
280
+ frame.check();
281
+ if (frame.failed !== saved)
282
+ throw frame.failed;
283
+ await step(session, frame, `RELEASE SAVEPOINT ${name}`);
284
+ released = true;
285
+ hear?.phase(session.hookm, "commit", depth + 1);
286
+ session.tx.after.push(...after);
287
+ return value;
288
+ } catch (error) {
289
+ if (!released && frame.stopped === undefined) {
290
+ await frame.conn.execute(`ROLLBACK TO SAVEPOINT ${name}`).catch(() => {
291
+ return;
292
+ });
293
+ frame.failed = saved;
294
+ hear?.phase(session.hookm, "rollback", depth + 1);
295
+ }
296
+ return await failWith(session, error);
297
+ }
298
+ }
299
+ function held(session, frame, after, depth) {
300
+ const base = session.pool;
301
+ const guarded = async (run, whole) => {
302
+ frame.check();
303
+ frame.enter();
304
+ try {
305
+ return await run();
306
+ } catch (error) {
307
+ frame.note(error, whole);
308
+ throw error;
309
+ } finally {
310
+ frame.leave();
311
+ }
312
+ };
313
+ const pool = depth === 0 ? {
314
+ capabilities: base.capabilities,
315
+ execute: (text, params, options) => guarded(() => frame.conn.execute(text, params, stoppable(frame, options)), false),
316
+ batch: (statements, options) => guarded(() => frame.conn.batch(statements, stoppable(frame, options)), true),
317
+ stats: () => base.stats(),
318
+ close: () => Promise.resolve()
319
+ } : base;
320
+ const next = {
321
+ ...session,
322
+ pool,
323
+ tx: {
324
+ depth,
325
+ state: frame,
326
+ after,
327
+ extras: {
328
+ afterCommit(callback) {
329
+ if (typeof callback !== "function") {
330
+ fail("OKM1121", "afterCommit expects a function.");
331
+ }
332
+ frame.check();
333
+ after.push(callback);
334
+ },
335
+ async advisoryLock(key, options) {
336
+ const [text, wire] = lockKey(key);
337
+ try {
338
+ await pool.execute(text, [wire], callOf(options));
339
+ } catch (error) {
340
+ await failWith(next, error);
341
+ }
342
+ }
343
+ }
344
+ }
345
+ };
346
+ return next;
347
+ }
348
+ function stoppable(frame, options) {
349
+ const own = frame.signal;
350
+ if (own === undefined)
351
+ return options;
352
+ return {
353
+ ...options,
354
+ signal: options?.signal === undefined ? own : AbortSignal.any([options.signal, own])
355
+ };
356
+ }
357
+ function lockKey(key) {
358
+ if (typeof key === "string") {
359
+ return ["select pg_advisory_xact_lock(hashtextextended($1, 0))", key];
360
+ }
361
+ const fits = typeof key === "number" ? Number.isSafeInteger(key) : typeof key === "bigint" && key >= -(2n ** 63n) && key < 2n ** 63n;
362
+ if (!fits)
363
+ fail("OKM1121", "advisoryLock takes a string, a safe integer, or a bigint that fits in 64 bits.");
364
+ return ["select pg_advisory_xact_lock($1::bigint)", String(key)];
365
+ }
366
+ function callOf(options) {
367
+ if (options?.signal === undefined && options?.timeout === undefined)
368
+ return;
369
+ return {
370
+ ...options.signal !== undefined ? { signal: options.signal } : {},
371
+ ...options.timeout !== undefined ? { timeout: options.timeout } : {}
372
+ };
373
+ }
374
+ export {
375
+ tx
376
+ };
@@ -0,0 +1,64 @@
1
+ import {
2
+ withHttp,
3
+ attachHttp
4
+ } from "./mxmcdsh5.js";
5
+ import {
6
+ OkmError2
7
+ } from "./52szzakm.js";
8
+
9
+ // src/runtime/server-check.ts
10
+ var versionQuery = "select current_setting('server_version_num'), version(), (select (xpath('//catalog_hash/text()', query_to_xml('select catalog_hash from okm_meta where id = ''head''', true, false, '')))[1]::text where to_regclass('okm_meta') is not null)";
11
+ async function acceptServer(pool, schema, rows, http, requireMeta, options, source) {
12
+ for (const name in schema.model) {
13
+ if (schema.model[name]?.presets !== undefined) {
14
+ (await import("./r6nwkxnt.js")).checkSchema(schema);
15
+ break;
16
+ }
17
+ }
18
+ const version = rows[0]?.[1];
19
+ if (version === null || version === undefined || !version.startsWith("PostgreSQL")) {
20
+ throw new OkmError2("OKM1801", "The server is not PostgreSQL. The schema dialect is postgres.", withHttp(http, {
21
+ fix: { summary: "Open the schema with the Postgres driver that matches it." }
22
+ }));
23
+ }
24
+ const recorded = rows[0]?.[2];
25
+ if (recorded === null || recorded === undefined || recorded.length === 0) {
26
+ if (requireMeta) {
27
+ throw new OkmError2("OKM1520", "okm_meta has no catalog hash.", withHttp(http, {
28
+ fix: {
29
+ summary: "Apply migrations so okm_meta records the catalog, or omit requireMeta to adopt this database."
30
+ }
31
+ }));
32
+ }
33
+ } else {
34
+ const { assertCompatible } = await import("./sfh4pk75.js");
35
+ try {
36
+ await assertCompatible(pool, schema, recorded, source, options);
37
+ } catch (error) {
38
+ if (error instanceof OkmError2)
39
+ throw attachHttp(http, error);
40
+ throw error;
41
+ }
42
+ }
43
+ const major = Math.floor(Number(rows[0]?.[0] ?? "0") / 1e4);
44
+ const requires = schema.requires?.postgres;
45
+ if (requires === undefined) {
46
+ if (major < 15) {
47
+ throw new OkmError2("OKM1803", `The server is PostgreSQL ${String(major)}. PostgreSQL 15 is the oldest supported.`, withHttp(http, {
48
+ fix: { summary: "Upgrade to PostgreSQL 15, or set schema({ requires }) to this major." }
49
+ }));
50
+ }
51
+ return;
52
+ }
53
+ const match = /^>=(\d+)$/.exec(requires.trim());
54
+ const need = match?.[1] === undefined ? undefined : Number(match[1]);
55
+ if (need === undefined || major < need) {
56
+ throw new OkmError2("OKM1802", `The server is PostgreSQL ${String(major)}. schema({ requires }) asks for ${requires}.`, withHttp(http, {
57
+ fix: { summary: "Upgrade the server, or lower requires to a version the server meets." }
58
+ }));
59
+ }
60
+ }
61
+ export {
62
+ acceptServer,
63
+ versionQuery
64
+ };
@@ -1,16 +1,24 @@
1
+ import {
2
+ touchFields,
3
+ fieldSealed
4
+ } from "./7m88x3e9.js";
1
5
  import {
2
6
  projectExpr,
3
7
  quote,
4
8
  list,
5
9
  isRecord,
10
+ registerFailFix,
6
11
  fail
7
- } from "./f5thc1s0.js";
12
+ } from "./xrfnq5k8.js";
8
13
  import {
9
14
  throwNamed2
10
- } from "./ycwz42az.js";
15
+ } from "./52szzakm.js";
11
16
 
12
17
  // src/runtime/conflict.ts
13
- function readConflict(table, value) {
18
+ registerFailFix("OKM1104", "Set on to the columns of a unique constraint or the primary key.");
19
+ registerFailFix("OKM1190", "Remove the guarded field. Input cannot set it.");
20
+ var NO_ALLOW = new Set;
21
+ function readConflict(table, value, allow = NO_ALLOW) {
14
22
  if (value === undefined || value === "error")
15
23
  return;
16
24
  if (value === "ignore")
@@ -33,7 +41,7 @@ function readConflict(table, value) {
33
41
  return {
34
42
  kind: "update",
35
43
  columns: uniqueColumns(table, value.on),
36
- update: updateColumns(table, update)
44
+ update: updateColumns(table, update, allow)
37
45
  };
38
46
  }
39
47
  fail("OKM1120", 'onConflict must be "error", "ignore", { on, update }, or { on, return: true }.');
@@ -44,9 +52,17 @@ function finishInsert(head, returning, params, plan, table, returningColumns, ke
44
52
  }
45
53
  const target = plan.columns.map((column) => quote(column.sql)).join(", ");
46
54
  if (plan.kind === "update") {
47
- const set = plan.update.map((column) => `${quote(column.sql)} = excluded.${quote(column.sql)}`).join(", ");
55
+ const assignments = plan.update.map((column) => `${quote(column.sql)} = excluded.${quote(column.sql)}`);
56
+ const touch = touchFields(table.model);
57
+ if (touch !== undefined) {
58
+ for (const field of touch) {
59
+ const column = table.columns.get(field);
60
+ if (column !== undefined)
61
+ assignments.push(`${quote(column.sql)} = now()`);
62
+ }
63
+ }
48
64
  return {
49
- text: `${head} on conflict (${target}) do update set ${set}${returning}`,
65
+ text: `${head} on conflict (${target})${conflictWhere(table, plan.columns)} do update set ${assignments.join(", ")}${returning}`,
50
66
  params: [...params]
51
67
  };
52
68
  }
@@ -71,9 +87,29 @@ function firstOrCreate(head, returning, params, keys, table, returningColumns, k
71
87
  const names = returningColumns.map((column) => quote(column.field)).join(", ");
72
88
  const fromTable = returningColumns.map((column) => projectExpr(`t.${quote(column.sql)}`, column.dataType)).join(", ");
73
89
  const match = keys.map((column) => `ins.${quote(column.field)} = t.${quote(column.sql)}`).join(" and ");
74
- const text = `with ins(${names}) as (${head} on conflict (${keyList}) do nothing${returning}) select ${names} from ins union all select ${fromTable} from ${quote(table.model.sql)} t where ${left} in (${tuples.join(", ")}) and not exists (select 1 from ins where ${match})`;
90
+ const text = `with ins(${names}) as (${head} on conflict (${keyList})${conflictWhere(table, keys)} do nothing${returning}) select ${names} from ins union all select ${fromTable} from ${quote(table.model.sql)} t where ${left} in (${tuples.join(", ")}) and not exists (select 1 from ins where ${match})`;
75
91
  return { text, params: next };
76
92
  }
93
+ function conflictWhere(table, columns) {
94
+ const archive = table.model.archive;
95
+ if (archive === undefined || samePrimary(table, columns))
96
+ return "";
97
+ return ` where ${quote(archive.at)} is null`;
98
+ }
99
+ function samePrimary(table, columns) {
100
+ const primary = table.model.primary;
101
+ if (columns.length !== primary.length)
102
+ return false;
103
+ for (const field of primary) {
104
+ let found = false;
105
+ for (const column of columns)
106
+ if (column.field === field)
107
+ found = true;
108
+ if (!found)
109
+ return false;
110
+ }
111
+ return true;
112
+ }
77
113
  function uniqueColumns(table, on) {
78
114
  const names = conflictNames(on);
79
115
  for (const unique of table.model.uniques) {
@@ -92,7 +128,7 @@ function uniqueColumns(table, on) {
92
128
  const accepted = table.model.uniques.map((fields) => fields.join(", "));
93
129
  throwNamed2("OKM1104", names.join(", "), accepted, `onConflict on ${table.model.name} names ${names.join(", ")}, which is not a unique constraint. Accepted: ${list(accepted)}.`);
94
130
  }
95
- function updateColumns(table, value) {
131
+ function updateColumns(table, value, allow) {
96
132
  if (!Array.isArray(value) || value.length === 0) {
97
133
  fail("OKM1120", "onConflict update must name at least one column.");
98
134
  }
@@ -104,8 +140,9 @@ function updateColumns(table, value) {
104
140
  if (column === undefined) {
105
141
  throwNamed2("OKM1120", name, table.names, `Field ${name} is not on ${table.model.name}. Accepted names: ${list(table.names)}.`);
106
142
  }
107
- if (!column.writable)
108
- refuseWrite(table.model.name, column);
143
+ if (fieldSealed(table.model, name) || column.guardUpdate || !column.writable && !(column.guarded && allow.has(name))) {
144
+ refuseWrite(table, column);
145
+ }
109
146
  columns.push(column);
110
147
  }
111
148
  return columns;
@@ -137,10 +174,16 @@ function rejectConflictKeys(keys, accepted) {
137
174
  }
138
175
  }
139
176
  function refuseWrite(table, column) {
177
+ if (fieldSealed(table.model, column.field)) {
178
+ fail("OKM1190", `Field ${table.model.name}.${column.field} is set by a trait. Input cannot set it.`);
179
+ }
180
+ if (column.guardUpdate) {
181
+ fail("OKM1190", `Field ${table.model.name}.${column.field} is a primary key. Input cannot change it.`);
182
+ }
140
183
  if (column.guarded) {
141
- fail("OKM1190", `Field ${table}.${column.field} is guarded. Input cannot set it.`);
184
+ fail("OKM1190", `Field ${table.model.name}.${column.field} is guarded. Input cannot set it.`);
142
185
  }
143
- fail("OKM1120", `Field ${table}.${column.field} cannot be written.`);
186
+ fail("OKM1120", `Field ${table.model.name}.${column.field} cannot be written.`);
144
187
  }
145
188
  export {
146
189
  finishInsert,
@@ -0,0 +1,33 @@
1
+ // src/adapters/pg/watch.ts
2
+ function openWatch(options) {
3
+ let kind;
4
+ const controller = new AbortController;
5
+ const onAbort = () => {
6
+ if (kind === undefined)
7
+ kind = "cancelled";
8
+ controller.abort();
9
+ };
10
+ options.signal?.addEventListener("abort", onAbort, { once: true });
11
+ let timer;
12
+ if (options.timeout !== undefined) {
13
+ timer = setTimeout(() => {
14
+ if (kind === undefined)
15
+ kind = "timeout";
16
+ controller.abort();
17
+ }, options.timeout);
18
+ }
19
+ return {
20
+ signal: controller.signal,
21
+ finish() {
22
+ if (timer !== undefined)
23
+ clearTimeout(timer);
24
+ options.signal?.removeEventListener("abort", onAbort);
25
+ },
26
+ reason() {
27
+ return kind;
28
+ }
29
+ };
30
+ }
31
+ export {
32
+ openWatch
33
+ };
@@ -0,0 +1,31 @@
1
+ // src/contracts/location.ts
2
+ function callerLocation(skip) {
3
+ const lines = new Error().stack?.split(`
4
+ `);
5
+ if (lines === undefined)
6
+ return;
7
+ let left = skip;
8
+ for (const line of lines) {
9
+ const slash = line.lastIndexOf("/");
10
+ if (slash < 0)
11
+ continue;
12
+ const tail = line.slice(slash + 1);
13
+ const colon = tail.indexOf(":");
14
+ if (colon < 1 || tail.startsWith("location."))
15
+ continue;
16
+ if (left > 0) {
17
+ left -= 1;
18
+ continue;
19
+ }
20
+ const end = tail.indexOf(":", colon + 1);
21
+ if (end < 0)
22
+ return;
23
+ return `${tail.slice(0, colon)}:${tail.slice(colon + 1, end)}`;
24
+ }
25
+ return;
26
+ }
27
+ function withLocation(message, source) {
28
+ return source === undefined ? message : `${message} (${source})`;
29
+ }
30
+
31
+ export { callerLocation, withLocation };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OkmError2
3
- } from "./ycwz42az.js";
3
+ } from "./52szzakm.js";
4
4
 
5
5
  // src/adapters/error.ts
6
6
  class DriverError2 extends Error {
@@ -57,6 +57,18 @@ function errorField2(error, key) {
57
57
  const value = Reflect.get(error, key);
58
58
  return typeof value === "string" && value.length > 0 ? value : undefined;
59
59
  }
60
+ function sqlstateOf(error) {
61
+ const code = errorField2(error, "code");
62
+ if (isSqlstate(code))
63
+ return code;
64
+ const errno = errorField2(error, "errno");
65
+ if (isSqlstate(errno))
66
+ return errno;
67
+ return errorField2(error, "sqlstate");
68
+ }
69
+ function isSqlstate(value) {
70
+ return value !== undefined && /^[0-9A-Z]{5}$/.test(value);
71
+ }
60
72
  function mapDriverError2(error, batchIndex) {
61
73
  if (error instanceof OkmError2)
62
74
  return error;
@@ -65,7 +77,7 @@ function mapDriverError2(error, batchIndex) {
65
77
  }
66
78
  const message = error instanceof Error ? error.message : "driver error";
67
79
  return new DriverError2(message, driverFields({
68
- sqlstate: errorField2(error, "code") ?? errorField2(error, "sqlstate"),
80
+ sqlstate: sqlstateOf(error),
69
81
  constraint: errorField2(error, "constraint_name") ?? errorField2(error, "constraint"),
70
82
  table: errorField2(error, "table_name") ?? errorField2(error, "table"),
71
83
  column: errorField2(error, "column_name") ?? errorField2(error, "column"),