okmodel 0.5.0 → 0.6.0

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 (169) hide show
  1. package/README.md +36 -18
  2. package/dist/adapters/pg/no-inflight-timeout.d.ts +17 -0
  3. package/dist/adapters/pg/postgres-extra.d.ts +22 -0
  4. package/dist/contracts/catalog/document.d.ts +19 -5
  5. package/dist/contracts/catalog/object.d.ts +2 -1
  6. package/dist/contracts/catalog/policy.d.ts +48 -0
  7. package/dist/contracts/catalog/types.d.ts +25 -1
  8. package/dist/contracts/catalog/view.d.ts +2 -0
  9. package/dist/contracts/internal.js +1 -1
  10. package/dist/contracts/location.d.ts +10 -0
  11. package/dist/dialects/pg/column.d.ts +13 -2
  12. package/dist/dialects/pg/ddl.d.ts +37 -1
  13. package/dist/dialects/pg/emit.d.ts +19 -1
  14. package/dist/dialects/pg/errors.d.ts +32 -1
  15. package/dist/dialects/pg/ext/citext.js +1 -1
  16. package/dist/dialects/pg/ext/index.js +1 -1
  17. package/dist/dialects/pg/ext/pg-trgm.js +1 -1
  18. package/dist/dialects/pg/filter-parse.d.ts +10 -3
  19. package/dist/dialects/pg/fn/index.js +10 -2
  20. package/dist/dialects/pg/index.d.ts +2 -1
  21. package/dist/dialects/pg/index.js +29 -17
  22. package/dist/dialects/pg/introspect.d.ts +7 -0
  23. package/dist/dialects/pg/model.d.ts +7 -2
  24. package/dist/dialects/pg/ops/or.d.ts +1 -1
  25. package/dist/dialects/pg/owner.d.ts +42 -0
  26. package/dist/dialects/pg/path-endpoint.d.ts +20 -0
  27. package/dist/dialects/pg/role/check.d.ts +3 -0
  28. package/dist/dialects/pg/role/index.d.ts +71 -6
  29. package/dist/dialects/pg/role/sql.d.ts +11 -0
  30. package/dist/dialects/pg/schema.d.ts +2 -0
  31. package/dist/dialects/pg/table.d.ts +25 -3
  32. package/dist/dialects/pg/temporal.d.ts +5 -76
  33. package/dist/dialects/pg/tenancy.d.ts +45 -3
  34. package/dist/dialects/pg/view/client.d.ts +19 -1
  35. package/dist/dialects/pg/view/index.d.ts +4 -0
  36. package/dist/dialects/pg/view/index.js +21 -178
  37. package/dist/dialects/pg/view/refresh.d.ts +24 -0
  38. package/dist/runtime/batch.d.ts +1 -1
  39. package/dist/runtime/client.d.ts +6 -1
  40. package/dist/runtime/conflict.d.ts +2 -1
  41. package/dist/runtime/drift.d.ts +9 -0
  42. package/dist/runtime/inflight.d.ts +14 -0
  43. package/dist/runtime/pg/bun.js +6 -5
  44. package/dist/runtime/pg/pg.js +5 -5
  45. package/dist/runtime/pg/pglite.js +6 -5
  46. package/dist/runtime/pg/postgresjs.js +5 -5
  47. package/dist/runtime/plan.d.ts +22 -1
  48. package/dist/runtime/predicate.d.ts +19 -0
  49. package/dist/runtime/safety/index.js +1 -1
  50. package/dist/runtime/tenancy/composite.d.ts +26 -0
  51. package/dist/runtime/tenancy/context.d.ts +16 -0
  52. package/dist/runtime/tenancy/index.d.ts +9 -5
  53. package/dist/runtime/tenancy/index.js +1508 -37
  54. package/dist/runtime/tenancy/path.d.ts +87 -0
  55. package/dist/runtime/tenancy/rls.d.ts +67 -0
  56. package/dist/runtime/tenancy/via.d.ts +22 -0
  57. package/dist/runtime/traits/index.js +17 -11
  58. package/dist/runtime/types.d.ts +13 -1
  59. package/dist/runtime/validate/index.js +4 -4
  60. package/dist/runtime/write.d.ts +1 -1
  61. package/dist/shared/09p049xa.js +702 -0
  62. package/dist/shared/{ykv7wh5b.js → 1f0xa3cb.js} +5 -5
  63. package/dist/shared/1nw1f3vs.js +23 -0
  64. package/dist/shared/{6p5k20sm.js → 1z04fa85.js} +21 -11
  65. package/dist/shared/{p7pfx624.js → 2cg3wnxc.js} +314 -65
  66. package/dist/shared/{dyj86cmj.js → 2jd1sn0e.js} +2 -2
  67. package/dist/shared/{qgvt8nx1.js → 2z7wv5tj.js} +21 -5
  68. package/dist/shared/{kyxb62mc.js → 31vm914h.js} +9 -1
  69. package/dist/shared/{sf8m6tfy.js → 32cnm7kn.js} +8 -3
  70. package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
  71. package/dist/shared/{jdgqqx31.js → 3fqwmr09.js} +38 -14
  72. package/dist/shared/{922qbgnw.js → 3qnhc7w5.js} +16 -9
  73. package/dist/shared/{zvbjc949.js → 4az561fn.js} +1 -1
  74. package/dist/shared/{k3ted12y.js → 54tqkxja.js} +20 -2
  75. package/dist/shared/{k7cc9nzk.js → 5d8t84hg.js} +15 -3
  76. package/dist/shared/{fa9vt245.js → 5j36z8dn.js} +17 -6
  77. package/dist/shared/{1g0drakv.js → 5yv4k6a6.js} +1 -1
  78. package/dist/shared/8dqhth8c.js +12 -0
  79. package/dist/shared/8etn7d8w.js +62 -0
  80. package/dist/shared/{g516zdsb.js → 8x72s86k.js} +476 -30
  81. package/dist/shared/{nkc9sfqb.js → 929h19xp.js} +145 -7
  82. package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
  83. package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
  84. package/dist/shared/{b066g80h.js → ag4c7516.js} +2 -2
  85. package/dist/shared/b3awxn7h.js +45 -0
  86. package/dist/shared/b4v57v3x.js +9 -0
  87. package/dist/shared/bdk4sty6.js +58 -0
  88. package/dist/shared/{s6gqfn5j.js → c58secgj.js} +125 -8
  89. package/dist/shared/{rrstp3kb.js → cgbamx3e.js} +2 -2
  90. package/dist/shared/d5azex6s.js +6 -0
  91. package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
  92. package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
  93. package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
  94. package/dist/shared/{wxn4b7pp.js → f0f1n281.js} +59 -12
  95. package/dist/shared/{gdh9mrtp.js → g90m9b0g.js} +3 -2
  96. package/dist/shared/{tbszx8mz.js → gwn6v667.js} +2 -2
  97. package/dist/shared/{c8aghh05.js → h15jx9bc.js} +8 -2
  98. package/dist/shared/{3p4b1fg0.js → hazqqecq.js} +17 -93
  99. package/dist/shared/{4ef7mmqf.js → j3rkk835.js} +34 -11
  100. package/dist/shared/{bt9sfq0z.js → j60w0dvr.js} +56 -21
  101. package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
  102. package/dist/shared/k68eedmy.js +85 -0
  103. package/dist/shared/{szm0cksa.js → knmes2kh.js} +34 -6
  104. package/dist/shared/{ckjbyrt9.js → mb2ycs1p.js} +7 -9
  105. package/dist/shared/{tq9afp8d.js → n076ydsc.js} +1 -1
  106. package/dist/shared/{xhh1srw3.js → nx9hh281.js} +50 -32
  107. package/dist/shared/{kdkxh3kb.js → p248q79y.js} +58 -59
  108. package/dist/shared/{990a291j.js → p6bjzq9q.js} +14 -9
  109. package/dist/shared/{h4nqvjkp.js → pjr6xrm5.js} +2 -2
  110. package/dist/shared/pz6rj8ay.js +212 -0
  111. package/dist/shared/{5vdm4sgp.js → q3j1tq7a.js} +36 -23
  112. package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
  113. package/dist/shared/{dxjp14rk.js → r11n8grd.js} +2 -2
  114. package/dist/shared/r1fdd0f6.js +19 -0
  115. package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
  116. package/dist/shared/rhs3xe4k.js +7 -0
  117. package/dist/shared/{jsd07prz.js → rpycarcr.js} +6 -6
  118. package/dist/shared/{xsq7v6wp.js → sbdme3vy.js} +14 -2
  119. package/dist/shared/{xdpj5kkm.js → t3g0k88x.js} +775 -264
  120. package/dist/shared/{ayz64vzj.js → ttmg09vd.js} +708 -19
  121. package/dist/shared/{r6pj4fq2.js → venqrjna.js} +8 -4
  122. package/dist/shared/{fancm5pt.js → vjpnzwjz.js} +138 -15
  123. package/dist/shared/{9tgmr1gh.js → vmfkhszw.js} +44 -9
  124. package/dist/shared/{wqem4jed.js → wkme6tep.js} +11 -9
  125. package/dist/shared/{qy9rdq0g.js → wt5rzv1h.js} +15 -11
  126. package/dist/shared/wxr8cwns.js +6 -0
  127. package/dist/shared/{bzsjtd7c.js → wynzeggs.js} +19 -14
  128. package/dist/shared/x3jc53kg.js +220 -0
  129. package/dist/shared/{7p2wbz7f.js → x72jb7ad.js} +1 -1
  130. package/dist/shared/{fyqkk1m0.js → xq0mvhts.js} +10 -9
  131. package/dist/shared/xqve9598.js +53 -0
  132. package/dist/shared/{47xzb9fc.js → y2t3jktd.js} +2 -2
  133. package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
  134. package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
  135. package/dist/shared/{h8ne16fq.js → ys0xzyaj.js} +1 -1
  136. package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
  137. package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
  138. package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
  139. package/dist/shared/{fb00y8fp.js → zm0mafk4.js} +12 -6
  140. package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
  141. package/dist/tooling/cli.js +97 -24
  142. package/dist/tooling/migrate/apply.d.ts +14 -0
  143. package/dist/tooling/migrate/check.d.ts +3 -4
  144. package/dist/tooling/migrate/classify.d.ts +4 -0
  145. package/dist/tooling/migrate/commands.d.ts +1 -2
  146. package/dist/tooling/migrate/config.d.ts +3 -2
  147. package/dist/tooling/migrate/drift.d.ts +1 -1
  148. package/dist/tooling/migrate/estimate.d.ts +14 -1
  149. package/dist/tooling/migrate/files.d.ts +11 -1
  150. package/dist/tooling/migrate/index.js +17 -16
  151. package/dist/tooling/migrate/lint.d.ts +4 -4
  152. package/dist/tooling/migrate/lost.d.ts +28 -0
  153. package/dist/tooling/migrate/paths.d.ts +14 -0
  154. package/dist/tooling/migrate/plan.d.ts +10 -3
  155. package/dist/tooling/migrate/policy.d.ts +11 -0
  156. package/dist/tooling/migrate/runner.d.ts +25 -0
  157. package/dist/tooling/migrate/sandbox.d.ts +57 -0
  158. package/dist/tooling/migrate/sql-lex.d.ts +39 -0
  159. package/dist/tooling/migrate/text.d.ts +42 -0
  160. package/dist/tooling/node-version.d.ts +21 -0
  161. package/dist/tooling/testing/factories.d.ts +10 -0
  162. package/dist/tooling/testing/facts.d.ts +33 -5
  163. package/dist/tooling/testing/index.d.ts +1 -1
  164. package/dist/tooling/testing/index.js +3 -3
  165. package/dist/tooling/testing/isolation.d.ts +15 -8
  166. package/package.json +10 -6
  167. package/dist/shared/0v1g424p.js +0 -26
  168. package/dist/shared/r73pt594.js +0 -426
  169. package/dist/shared/rasvvzgz.js +0 -21
@@ -1,15 +1,9 @@
1
1
  import {
2
- serializeCatalog2,
3
- catalogHash2,
4
- startupCatalog2,
5
- parseCatalog2
6
- } from "./8bwbwy8h.js";
2
+ serializeCatalog2
3
+ } from "./qq3899ht.js";
7
4
  import {
8
5
  roleExists
9
- } from "./szm0cksa.js";
10
- import {
11
- assertTargetPolicy
12
- } from "./xdpj5kkm.js";
6
+ } from "./knmes2kh.js";
13
7
  import {
14
8
  canonicalTypeName,
15
9
  createdRoleName,
@@ -20,29 +14,30 @@ import {
20
14
  checkedCast,
21
15
  omitManagedObjects,
22
16
  planMigration,
23
- parsePlan
24
- } from "./ayz64vzj.js";
17
+ sessionFailure,
18
+ assertTargetPolicy
19
+ } from "./ttmg09vd.js";
25
20
  import {
26
21
  quoteIdent,
27
22
  qualify
28
- } from "./8xsbagad.js";
23
+ } from "./9s0ypp87.js";
29
24
  import {
30
25
  alignExtensionVersions
31
- } from "./8ktwd3rh.js";
26
+ } from "./r3j8s5y0.js";
32
27
  import {
33
28
  catalog,
34
29
  isDomain
35
- } from "./g7ez901n.js";
30
+ } from "./ywspezzx.js";
36
31
  import {
37
32
  snakeCase
38
- } from "./jsd07prz.js";
33
+ } from "./rpycarcr.js";
39
34
  import {
40
35
  quoteLiteral
41
36
  } from "./94ez8kzh.js";
42
37
  import {
43
38
  identityKey2,
44
39
  identityLabel2
45
- } from "./t4tbsy9h.js";
40
+ } from "./358zsv4r.js";
46
41
  import {
47
42
  OkmError2
48
43
  } from "./52szzakm.js";
@@ -78,6 +73,16 @@ async function assumeRole(connection, role, session) {
78
73
  await connection.execute(`set role ${quoteIdent(role)}`);
79
74
  session.setRole = role;
80
75
  }
76
+ async function grantAppMeta(connection, role, session) {
77
+ if (role === undefined)
78
+ return;
79
+ const previous = session.setRole;
80
+ if (previous !== undefined)
81
+ await connection.execute("reset role");
82
+ await connection.execute(`grant select on okm_meta to ${quoteIdent(role)}`);
83
+ if (previous !== undefined)
84
+ await connection.execute(`set role ${quoteIdent(previous)}`);
85
+ }
81
86
  async function grantSchema(connection, schema, role) {
82
87
  await connection.execute(`grant usage, create on schema ${quoteIdent(schema)} to ${quoteIdent(role)}`);
83
88
  }
@@ -100,9 +105,10 @@ async function runUnit(connection, unit, run, session) {
100
105
  await rebuildInvalidIndex(connection, item.step.sql);
101
106
  const created = createdRoleName(item.step.sql);
102
107
  const existed = created !== undefined && await roleExists(connection, created);
103
- if (created === undefined)
108
+ if (created === undefined) {
104
109
  await connection.execute(item.step.sql);
105
- else if (!existed)
110
+ await assertSchemaUsageLanded(connection, item.step.sql);
111
+ } else if (!existed)
106
112
  await connection.execute(createRoleOnce(item.step.sql));
107
113
  if (created !== undefined && created === run.migrationRole) {
108
114
  if (!existed) {
@@ -305,11 +311,39 @@ function concurrentIndexName(sql) {
305
311
  const match = /^create\s+(?:unique\s+)?index\s+concurrently\s+(?:if\s+not\s+exists\s+)?(?:"([^"]+)"|([A-Za-z_][\w$]*))/i.exec(sql.trim());
306
312
  return match?.[1] ?? match?.[2];
307
313
  }
314
+ var SCHEMA_USAGE = /^\s*grant\s+usage\s+on\s+schema\s+(?:"((?:[^"]|"")*)"|([A-Za-z_][\w$]*))\s+to\s+(?:"((?:[^"]|"")*)"|([A-Za-z_][\w$]*))\s*;?\s*$/i;
315
+ async function assertSchemaUsageLanded(connection, sql) {
316
+ const match = SCHEMA_USAGE.exec(sql.trim());
317
+ if (match === null)
318
+ return;
319
+ const schema = (match[1] ?? match[2] ?? "").replaceAll('""', '"');
320
+ const role = (match[3] ?? match[4] ?? "").replaceAll('""', '"');
321
+ const found = await connection.execute(`select exists (
322
+ select 1
323
+ from pg_namespace n
324
+ cross join lateral aclexplode(n.nspacl) a
325
+ join pg_roles r on r.oid = a.grantee
326
+ where n.nspname = $1 and r.rolname = $2 and a.privilege_type = 'USAGE'
327
+ )`, [schema, role]);
328
+ const landed = found.rows[0]?.[0];
329
+ if (landed === "t" || landed === "true")
330
+ return;
331
+ throw new OkmError2("OKM1825", `Grant usage on schema ${schema} to ${role} did not take effect.`, {
332
+ kind: "forbidden",
333
+ fix: {
334
+ summary: `Make the migration role the owner of schema ${schema}. ALTER SCHEMA ${quoteIdent(schema)} OWNER TO <migration role>.`
335
+ }
336
+ });
337
+ }
308
338
  function failStep(unit, index, error) {
339
+ const lost = sessionFailure(error);
340
+ if (lost !== undefined) {
341
+ return new OkmError2(lost.code, `Migration ${unit.migrationId} failed at step ${String(index + 1)}: ${lost.message}`, { kind: lost.kind, cause: error, fix: lost.fix });
342
+ }
309
343
  if (error instanceof OkmError2)
310
344
  return error;
311
345
  const message = error instanceof Error ? error.message : "The step failed.";
312
- return new OkmError2("invalid", `Migration ${unit.migrationId} failed at step ${String(index)}: ${message}`, {
346
+ return new OkmError2("invalid", `Migration ${unit.migrationId} failed at step ${String(index + 1)}: ${message}`, {
313
347
  cause: error,
314
348
  fix: { summary: "Fix the step and run apply again. Finished steps are not repeated." }
315
349
  });
@@ -362,44 +396,6 @@ function delay(ms) {
362
396
  });
363
397
  }
364
398
 
365
- // src/tooling/migrate/files.ts
366
- import { existsSync, readdirSync, readFileSync } from "node:fs";
367
- import { join } from "node:path";
368
- function loadMigrations(directory) {
369
- if (!existsSync(directory))
370
- return [];
371
- const names = readdirSync(directory).filter((file) => file.endsWith(".sql")).sort();
372
- const migrations = [];
373
- for (const file of names) {
374
- const id = file.slice(0, -".sql".length);
375
- const catalogPath = join(directory, `${id}.catalog.json`);
376
- if (!existsSync(catalogPath)) {
377
- throw new OkmError2("invalid", `Migration ${id} is missing its catalog snapshot.`, {
378
- fix: {
379
- summary: "Generate the migration again so the SQL and the catalog are written together."
380
- }
381
- });
382
- }
383
- const plan = parsePlan(readFileSync(join(directory, file), "utf8"));
384
- const stored = parseCatalog2(readFileSync(catalogPath, "utf8"));
385
- const startup = startupCatalog2(stored);
386
- const hash = catalogHash2(startup);
387
- migrations.push(startup === stored ? { id, catalogHash: hash, steps: plan.steps } : { id, catalogHash: hash, legacyHash: catalogHash2(stored), steps: plan.steps });
388
- }
389
- return migrations;
390
- }
391
- function loadHeadSnapshot(directory) {
392
- const migrations = loadMigrations(directory);
393
- const last = migrations.at(-1);
394
- if (last === undefined)
395
- return;
396
- return {
397
- id: last.id,
398
- catalogHash: last.catalogHash,
399
- catalog: parseCatalog2(readFileSync(join(directory, `${last.id}.catalog.json`), "utf8"))
400
- };
401
- }
402
-
403
399
  // src/tooling/migrate/reference.ts
404
400
  function readReference(tables, casing, head) {
405
401
  const declared = [];
@@ -590,8 +586,10 @@ async function installSnapshot(connection, head, schema, reference, session, mig
590
586
  return;
591
587
  await connection.execute("begin");
592
588
  began = true;
593
- for (const sql of batch)
589
+ for (const sql of batch) {
594
590
  await connection.execute(sql);
591
+ await assertSchemaUsageLanded(connection, sql);
592
+ }
595
593
  await connection.execute("commit");
596
594
  began = false;
597
595
  batch.length = 0;
@@ -613,6 +611,7 @@ async function installSnapshot(connection, head, schema, reference, session, mig
613
611
  } else {
614
612
  await flush();
615
613
  await connection.execute(sql);
614
+ await assertSchemaUsageLanded(connection, sql);
616
615
  }
617
616
  if (created !== undefined && created === migrationRole) {
618
617
  await flush();
@@ -755,4 +754,4 @@ function normaliseFunction(object) {
755
754
  };
756
755
  }
757
756
 
758
- export { runTarget, assumeRole, statementOutsideTransaction, loadMigrations, loadHeadSnapshot, readReference, referenceInserts, catalogsEqual, provisionMark, expandProvisioned, provisionHistoryIsKnown, installSnapshot, snapshotDifference };
757
+ export { runTarget, assumeRole, grantAppMeta, grantSchema, assertSchemaUsageLanded, statementOutsideTransaction, readReference, referenceInserts, catalogsEqual, provisionMark, expandProvisioned, provisionHistoryIsKnown, installSnapshot, snapshotDifference };
@@ -1,19 +1,22 @@
1
1
  import {
2
2
  open2
3
- } from "./wqem4jed.js";
4
- import"./8bwbwy8h.js";
3
+ } from "./wkme6tep.js";
4
+ import"./qq3899ht.js";
5
5
  import"./n442h54c.js";
6
6
  import {
7
- assertTargetPolicy,
8
- selectTarget,
9
7
  openProject
10
- } from "./xdpj5kkm.js";
11
- import"./ayz64vzj.js";
12
- import"./8xsbagad.js";
8
+ } from "./t3g0k88x.js";
9
+ import {
10
+ sessionFailure,
11
+ finishQuiet,
12
+ assertTargetPolicy,
13
+ selectTarget
14
+ } from "./ttmg09vd.js";
15
+ import"./9s0ypp87.js";
13
16
  import {
14
17
  isExactVersion,
15
18
  compareExtensionVersions
16
- } from "./8ktwd3rh.js";
19
+ } from "./r3j8s5y0.js";
17
20
  import {
18
21
  OkmError2
19
22
  } from "./52szzakm.js";
@@ -28,8 +31,10 @@ async function extProject(cwd, command, flags) {
28
31
  if (command === "list")
29
32
  return formatList(await readExtensions(pool));
30
33
  return formatCheck(opened.built.catalog.objects, await readExtensions(pool));
34
+ } catch (error) {
35
+ throw sessionFailure(error) ?? error;
31
36
  } finally {
32
- await pool.close();
37
+ await finishQuiet(() => pool.close());
33
38
  }
34
39
  }
35
40
  var LIST_SQL = `
@@ -3,7 +3,7 @@ import {
3
3
  readHandle,
4
4
  readCall,
5
5
  attachHttp
6
- } from "./bt9sfq0z.js";
6
+ } from "./j60w0dvr.js";
7
7
  import {
8
8
  selectedColumns,
9
9
  parseOrder,
@@ -15,7 +15,7 @@ import {
15
15
  isRecord,
16
16
  registerFailFix,
17
17
  fail
18
- } from "./qgvt8nx1.js";
18
+ } from "./2z7wv5tj.js";
19
19
  import {
20
20
  OkmError2,
21
21
  throwNamed2
@@ -0,0 +1,212 @@
1
+ import {
2
+ tag
3
+ } from "./cn0n68ft.js";
4
+ import {
5
+ OkmError2
6
+ } from "./52szzakm.js";
7
+
8
+ // src/dialects/pg/filter-parse.ts
9
+ var PARSED = [
10
+ "eq",
11
+ "in",
12
+ "inList",
13
+ "notIn",
14
+ "lt",
15
+ "lte",
16
+ "gt",
17
+ "gte",
18
+ "between",
19
+ "startsWith",
20
+ "endsWith",
21
+ "contains",
22
+ "like",
23
+ "ilike",
24
+ "not",
25
+ "containedBy",
26
+ "overlaps",
27
+ "hasKey",
28
+ "hasAnyKey"
29
+ ];
30
+ var PARSED_OPS = `,${PARSED.join(",")},`;
31
+ var PARSED_FIX = "Use eq, in, notIn, lt, lte, gt, gte, between, startsWith, endsWith, contains, like, ilike, not, containedBy, overlaps, hasKey, or hasAnyKey.";
32
+ function parseQuery(allow, sort, query, relations) {
33
+ if (typeof query !== "object" || query === null || Array.isArray(query)) {
34
+ throw new OkmError2("OKM1121", "filters parse expects an object of fields.");
35
+ }
36
+ for (const field of Object.keys(allow)) {
37
+ for (const op of allow[field] ?? []) {
38
+ if (PARSED_OPS.includes(`,${op},`))
39
+ continue;
40
+ throw new OkmError2("OKM1120", `filters() cannot apply ${op} on ${field}.`, {
41
+ fix: { summary: PARSED_FIX }
42
+ });
43
+ }
44
+ }
45
+ const nested = relations ?? {};
46
+ const whereParts = [];
47
+ let orderBy;
48
+ for (const key of Object.keys(query)) {
49
+ const value = query[key];
50
+ if (key === "sort" && typeof value === "string" && sort.includes(value)) {
51
+ orderBy = { [value]: "asc" };
52
+ continue;
53
+ }
54
+ if (Object.hasOwn(allow, key)) {
55
+ whereParts.push(...clauses(key, allow[key] ?? [], value));
56
+ continue;
57
+ }
58
+ if (Object.hasOwn(nested, key)) {
59
+ whereParts.push(relationClause(key, nested[key] ?? [], value));
60
+ continue;
61
+ }
62
+ throw new OkmError2("OKM1123", `Field ${key} is not in the allow list.`, {
63
+ fix: { summary: "Remove the field, or add it to filters({ allow }) or relations." }
64
+ });
65
+ }
66
+ const where = combine(whereParts);
67
+ return orderBy === undefined ? { where } : { where, orderBy };
68
+ }
69
+ function clauses(field, ops, value) {
70
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
71
+ if (!ops.includes("eq")) {
72
+ throw new OkmError2("OKM1120", `filters() cannot apply eq on ${field}.`, {
73
+ fix: { summary: "Add eq to that field, or send an object of allowed operators." }
74
+ });
75
+ }
76
+ return [{ [field]: value }];
77
+ }
78
+ const applied = [];
79
+ for (const op of Object.keys(value)) {
80
+ if (!Object.hasOwn(value, op))
81
+ continue;
82
+ if (!ops.includes(op) && !(op === "inList" && ops.includes("in"))) {
83
+ throw new OkmError2("OKM1120", `filters() cannot apply ${op} on ${field}.`, {
84
+ fix: { summary: "Send an operator that field's allow list names." }
85
+ });
86
+ }
87
+ applied.push(one(field, op, value[op]));
88
+ }
89
+ if (applied.length === 0) {
90
+ throw new OkmError2("OKM1120", `filters() cannot apply a value on ${field}.`, {
91
+ fix: { summary: "Send eq as a scalar, or an object of allowed operators." }
92
+ });
93
+ }
94
+ return applied;
95
+ }
96
+ function one(field, op, value) {
97
+ switch (op) {
98
+ case "eq":
99
+ return {
100
+ [field]: value !== null && typeof value === "object" ? tag("eq", value) : value
101
+ };
102
+ case "in":
103
+ case "inList":
104
+ return { [field]: tag("inList", list(value, op)) };
105
+ case "notIn":
106
+ return { [field]: tag("notIn", list(value, op)) };
107
+ case "lt":
108
+ return { [field]: tag("lt", value) };
109
+ case "lte":
110
+ return { [field]: tag("lte", value) };
111
+ case "gt":
112
+ return { [field]: tag("gt", value) };
113
+ case "gte":
114
+ return { [field]: tag("gte", value) };
115
+ case "between": {
116
+ if (!Array.isArray(value) || value.length !== 2) {
117
+ throw new OkmError2("OKM1120", `between on ${field} needs two bounds.`, {
118
+ fix: { summary: "Send between as [from, to]." }
119
+ });
120
+ }
121
+ return { [field]: tag("between", [value[0], value[1]]) };
122
+ }
123
+ case "startsWith":
124
+ return { [field]: tag("startsWith", text(value, op)) };
125
+ case "endsWith":
126
+ return { [field]: tag("endsWith", text(value, op)) };
127
+ case "contains":
128
+ return { [field]: tag("contains", value) };
129
+ case "not":
130
+ if (value !== null && typeof value === "object") {
131
+ throw new OkmError2("OKM1120", `not on ${field} takes a scalar.`, {
132
+ fix: { summary: "Send not a scalar or null. Nested operators are not accepted." }
133
+ });
134
+ }
135
+ return { [field]: tag("not", value) };
136
+ case "containedBy":
137
+ return { [field]: tag("containedBy", value) };
138
+ case "overlaps":
139
+ return { [field]: tag("overlaps", value) };
140
+ case "hasKey":
141
+ return { [field]: tag("hasKey", text(value, "hasKey")) };
142
+ case "hasAnyKey":
143
+ return { [field]: tag("hasAnyKey", strings(value, field)) };
144
+ case "like":
145
+ return { [field]: tag("like", text(value, op)) };
146
+ case "ilike":
147
+ return { [field]: tag("ilike", text(value, op)) };
148
+ default:
149
+ throw new OkmError2("OKM1120", `filters() cannot apply ${op} on ${field}.`, {
150
+ fix: { summary: "Use an operator parse applies." }
151
+ });
152
+ }
153
+ }
154
+ function relationClause(name, fields, value) {
155
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
156
+ throw new OkmError2("OKM1120", `filters() cannot apply a value on ${name}.`, {
157
+ fix: { summary: "Send the relation an object of allowlisted fields." }
158
+ });
159
+ }
160
+ const parts = [];
161
+ for (const field of Object.keys(value)) {
162
+ if (!Object.hasOwn(value, field))
163
+ continue;
164
+ if (!fields.includes(field)) {
165
+ throw new OkmError2("OKM1123", `Field ${field} is not in the allow list.`, {
166
+ fix: { summary: "Remove the field, or add it to filters({ relations })." }
167
+ });
168
+ }
169
+ parts.push(...clauses(field, PARSED, value[field]));
170
+ }
171
+ if (parts.length === 0) {
172
+ throw new OkmError2("OKM1120", `filters() cannot apply a value on ${name}.`, {
173
+ fix: { summary: "Send the relation an object of allowlisted fields." }
174
+ });
175
+ }
176
+ return { [name]: tag("has", combine(parts)) };
177
+ }
178
+ function combine(parts) {
179
+ const first = parts[0];
180
+ if (first === undefined)
181
+ return {};
182
+ if (parts.length === 1)
183
+ return first;
184
+ return tag("and", parts);
185
+ }
186
+ function list(value, op) {
187
+ if (!Array.isArray(value)) {
188
+ throw new OkmError2("OKM1120", `${op} needs an array.`, {
189
+ fix: { summary: "Send that operator an array of values." }
190
+ });
191
+ }
192
+ return value;
193
+ }
194
+ function strings(value, field) {
195
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
196
+ throw new OkmError2("OKM1120", `hasAnyKey on ${field} needs an array of strings.`, {
197
+ fix: { summary: "Send hasAnyKey an array of strings." }
198
+ });
199
+ }
200
+ return value;
201
+ }
202
+ function text(value, op) {
203
+ if (typeof value !== "string") {
204
+ throw new OkmError2("OKM1120", `${op} needs a string.`, {
205
+ fix: { summary: "Send that operator a string." }
206
+ });
207
+ }
208
+ return value;
209
+ }
210
+ export {
211
+ parseQuery
212
+ };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  PgSession
3
- } from "./wqem4jed.js";
3
+ } from "./wkme6tep.js";
4
4
  import {
5
5
  isConnectionLost
6
- } from "./tbszx8mz.js";
6
+ } from "./gwn6v667.js";
7
7
  import {
8
8
  driverErrors,
9
9
  rejectClosed,
@@ -11,12 +11,12 @@ import {
11
11
  runCall,
12
12
  rowsFrom,
13
13
  resultFrom
14
- } from "./rrstp3kb.js";
14
+ } from "./cgbamx3e.js";
15
15
 
16
16
  // src/adapters/pg/postgres-extra.ts
17
17
  var RESET_ALL = "RESET ALL";
18
18
  var UNLOCK = "SELECT pg_advisory_unlock_all()";
19
- async function checkout(pool) {
19
+ async function checkout2(pool) {
20
20
  if (pool.isClosed())
21
21
  return rejectClosed();
22
22
  const reserved = await reserveConnection(pool.sql, pool.acquireMs, pool.counters);
@@ -24,16 +24,17 @@ async function checkout(pool) {
24
24
  const local = new Set;
25
25
  const session = new PgSession(reserved, pool.counters, "reserved", local, pool.isClosed, pool.poolInflight, pool.notices, pool.named);
26
26
  let released = false;
27
- let lost = false;
28
- const guard = (run) => lost ? rejectClosed("The connection was lost.") : run().catch((error) => {
27
+ const lost = { on: false };
28
+ arm(reserved, lost);
29
+ const guard = (run) => lost.on ? rejectClosed("CONNECTION_CLOSED") : run().catch((error) => {
29
30
  if (isConnectionLost(error))
30
- lost = true;
31
+ lost.on = true;
31
32
  throw error;
32
33
  });
33
34
  return {
34
35
  execute: (text, params, options) => guard(() => runCall(pool.isClosed(), options, (watch) => session.query(text, params, watch))),
35
36
  batch: (statements, options) => guard(() => runCall(pool.isClosed(), options, async (watch) => {
36
- const { runAtomicBatch } = await import("./b066g80h.js");
37
+ const { runAtomicBatch } = await import("./ag4c7516.js");
37
38
  return runAtomicBatch(session, statements, watch);
38
39
  })),
39
40
  cancel() {
@@ -44,17 +45,21 @@ async function checkout(pool) {
44
45
  return;
45
46
  released = true;
46
47
  try {
47
- if (!lost)
48
+ if (!lost.on)
48
49
  await resetConnection(reserved, session.depth());
49
50
  } finally {
50
51
  pool.counters.reserved = Math.max(0, pool.counters.reserved - 1);
51
- if (!lost)
52
+ if (lost.on)
53
+ await pool.sql.unsafe("select 1").catch(() => {
54
+ return;
55
+ });
56
+ else
52
57
  reserved.release();
53
58
  }
54
59
  }
55
60
  };
56
61
  }
57
- async function describe(sql, text, params) {
62
+ async function describe2(sql, text, params) {
58
63
  const pending = sql.unsafe(text, asParams(params), { prepare: true });
59
64
  const described = await pending.describe();
60
65
  return {
@@ -62,7 +67,7 @@ async function describe(sql, text, params) {
62
67
  parameterCount: described.types.length
63
68
  };
64
69
  }
65
- async function* stream(sql, text, params) {
70
+ async function* stream2(sql, text, params) {
66
71
  const pending = sql.unsafe(text, asParams(params));
67
72
  for await (const chunk of pending.cursor(64)) {
68
73
  yield rowsFrom(chunk);
@@ -124,7 +129,21 @@ function asParams(params) {
124
129
  return [];
125
130
  return params;
126
131
  }
127
- async function holdCheckout(gate, checkout) {
132
+ function watchReserved2(sql, lost) {
133
+ arm(sql, lost);
134
+ }
135
+ function arm(sql, lost) {
136
+ const unsafe = sql.unsafe.bind(sql);
137
+ sql.unsafe = (text, params, options) => unsafe(text, params, {
138
+ ...options,
139
+ onexecute(connection) {
140
+ connection.onclose = () => {
141
+ lost.on = true;
142
+ };
143
+ }
144
+ });
145
+ }
146
+ async function holdCheckout2(gate, checkout) {
128
147
  try {
129
148
  const connection = await checkout();
130
149
  let released = false;
@@ -143,7 +162,7 @@ async function holdCheckout(gate, checkout) {
143
162
  throw error;
144
163
  }
145
164
  }
146
- async function holdListener(gate, start) {
165
+ async function holdListener2(gate, start) {
147
166
  try {
148
167
  const stop = await start();
149
168
  let stopped = false;
@@ -162,7 +181,7 @@ async function holdListener(gate, start) {
162
181
  throw error;
163
182
  }
164
183
  }
165
- function watchQuery(pending, watch, onAbort, ctx) {
184
+ function watchQuery2(pending, watch, onAbort, ctx) {
166
185
  return pending.then((result) => {
167
186
  finishWatch(pending, watch, onAbort, ctx);
168
187
  const why = watch.reason();
@@ -194,11 +213,5 @@ async function classify(error, watch) {
194
213
  }
195
214
  return Promise.reject(errors.mapDriverError(error));
196
215
  }
197
- export {
198
- checkout,
199
- describe,
200
- holdCheckout,
201
- holdListener,
202
- stream,
203
- watchQuery
204
- };
216
+
217
+ export { checkout2, describe2, stream2, watchReserved2, holdCheckout2, holdListener2, watchQuery2 };