okmodel 0.5.1 → 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 (155) hide show
  1. package/README.md +29 -14
  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 +5 -4
  19. package/dist/dialects/pg/fn/index.js +2 -2
  20. package/dist/dialects/pg/index.d.ts +2 -1
  21. package/dist/dialects/pg/index.js +23 -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/owner.d.ts +42 -0
  25. package/dist/dialects/pg/path-endpoint.d.ts +20 -0
  26. package/dist/dialects/pg/role/check.d.ts +3 -0
  27. package/dist/dialects/pg/role/index.d.ts +71 -6
  28. package/dist/dialects/pg/role/sql.d.ts +11 -0
  29. package/dist/dialects/pg/schema.d.ts +2 -0
  30. package/dist/dialects/pg/table.d.ts +25 -3
  31. package/dist/dialects/pg/tenancy.d.ts +45 -3
  32. package/dist/dialects/pg/view/client.d.ts +19 -1
  33. package/dist/dialects/pg/view/index.d.ts +4 -0
  34. package/dist/dialects/pg/view/index.js +21 -178
  35. package/dist/dialects/pg/view/refresh.d.ts +24 -0
  36. package/dist/runtime/batch.d.ts +1 -1
  37. package/dist/runtime/conflict.d.ts +2 -2
  38. package/dist/runtime/drift.d.ts +9 -0
  39. package/dist/runtime/inflight.d.ts +14 -0
  40. package/dist/runtime/pg/bun.js +4 -3
  41. package/dist/runtime/pg/pg.js +3 -3
  42. package/dist/runtime/pg/pglite.js +4 -3
  43. package/dist/runtime/pg/postgresjs.js +3 -3
  44. package/dist/runtime/plan.d.ts +18 -10
  45. package/dist/runtime/predicate.d.ts +19 -0
  46. package/dist/runtime/safety/index.js +1 -1
  47. package/dist/runtime/tenancy/composite.d.ts +26 -0
  48. package/dist/runtime/tenancy/context.d.ts +16 -0
  49. package/dist/runtime/tenancy/index.d.ts +9 -5
  50. package/dist/runtime/tenancy/index.js +1508 -37
  51. package/dist/runtime/tenancy/path.d.ts +87 -0
  52. package/dist/runtime/tenancy/rls.d.ts +67 -0
  53. package/dist/runtime/tenancy/via.d.ts +22 -0
  54. package/dist/runtime/traits/index.js +17 -11
  55. package/dist/runtime/types.d.ts +13 -1
  56. package/dist/runtime/validate/index.js +4 -4
  57. package/dist/runtime/write.d.ts +1 -1
  58. package/dist/shared/09p049xa.js +702 -0
  59. package/dist/shared/{6qd27mx0.js → 1f0xa3cb.js} +5 -5
  60. package/dist/shared/1nw1f3vs.js +23 -0
  61. package/dist/shared/{96qcj21c.js → 1z04fa85.js} +19 -9
  62. package/dist/shared/{qm7cdtvr.js → 2cg3wnxc.js} +296 -60
  63. package/dist/shared/{dyj86cmj.js → 2jd1sn0e.js} +2 -2
  64. package/dist/shared/{gbtcc2d7.js → 2z7wv5tj.js} +10 -35
  65. package/dist/shared/{k8v5v5wj.js → 32cnm7kn.js} +6 -1
  66. package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
  67. package/dist/shared/{2pqx26h8.js → 3fqwmr09.js} +31 -22
  68. package/dist/shared/{zqrnhwsq.js → 3qnhc7w5.js} +16 -9
  69. package/dist/shared/{r2sp8hrc.js → 5d8t84hg.js} +12 -3
  70. package/dist/shared/{87jvvhnt.js → 5j36z8dn.js} +16 -5
  71. package/dist/shared/{1g0drakv.js → 5yv4k6a6.js} +1 -1
  72. package/dist/shared/8dqhth8c.js +12 -0
  73. package/dist/shared/8etn7d8w.js +62 -0
  74. package/dist/shared/{v36c5g6p.js → 8x72s86k.js} +400 -13
  75. package/dist/shared/{nxdp2ze3.js → 929h19xp.js} +107 -5
  76. package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
  77. package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
  78. package/dist/shared/{efmy2gcg.js → ag4c7516.js} +1 -1
  79. package/dist/shared/b3awxn7h.js +45 -0
  80. package/dist/shared/b4v57v3x.js +9 -0
  81. package/dist/shared/bdk4sty6.js +58 -0
  82. package/dist/shared/{51mvgj8w.js → c58secgj.js} +100 -7
  83. package/dist/shared/d5azex6s.js +6 -0
  84. package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
  85. package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
  86. package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
  87. package/dist/shared/{sycnx8gt.js → f0f1n281.js} +18 -8
  88. package/dist/shared/{f5cw5q5r.js → g90m9b0g.js} +2 -1
  89. package/dist/shared/{pf0d8f77.js → gwn6v667.js} +1 -1
  90. package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
  91. package/dist/shared/{5enne4ma.js → hazqqecq.js} +17 -93
  92. package/dist/shared/{jwtxdj06.js → j3rkk835.js} +32 -9
  93. package/dist/shared/{hf22e0wt.js → j60w0dvr.js} +19 -18
  94. package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
  95. package/dist/shared/k68eedmy.js +85 -0
  96. package/dist/shared/{szm0cksa.js → knmes2kh.js} +34 -6
  97. package/dist/shared/{0t22wwh1.js → mb2ycs1p.js} +4 -2
  98. package/dist/shared/{cr74e96e.js → n076ydsc.js} +1 -1
  99. package/dist/shared/{cctw17hj.js → nx9hh281.js} +31 -28
  100. package/dist/shared/{gde73es6.js → p248q79y.js} +56 -55
  101. package/dist/shared/{janx09m5.js → p6bjzq9q.js} +11 -7
  102. package/dist/shared/{6rk2gen5.js → pjr6xrm5.js} +2 -2
  103. package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
  104. package/dist/shared/{caw8b9d8.js → q3j1tq7a.js} +35 -22
  105. package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
  106. package/dist/shared/{tm5ab8we.js → r11n8grd.js} +2 -2
  107. package/dist/shared/r1fdd0f6.js +19 -0
  108. package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
  109. package/dist/shared/rhs3xe4k.js +7 -0
  110. package/dist/shared/{ntneex2a.js → rpycarcr.js} +6 -6
  111. package/dist/shared/{aj2qxyhj.js → sbdme3vy.js} +14 -2
  112. package/dist/shared/{qv2ydck9.js → t3g0k88x.js} +638 -67
  113. package/dist/shared/{ga3sfy93.js → ttmg09vd.js} +535 -200
  114. package/dist/shared/{kfjp0gck.js → venqrjna.js} +8 -4
  115. package/dist/shared/{fancm5pt.js → vjpnzwjz.js} +138 -15
  116. package/dist/shared/{32zqc1dw.js → vmfkhszw.js} +31 -7
  117. package/dist/shared/{krxx77g0.js → wkme6tep.js} +10 -8
  118. package/dist/shared/{ps7a6h14.js → wt5rzv1h.js} +12 -8
  119. package/dist/shared/wxr8cwns.js +6 -0
  120. package/dist/shared/{6mnp99hx.js → wynzeggs.js} +16 -12
  121. package/dist/shared/x3jc53kg.js +220 -0
  122. package/dist/shared/{sdc7r2ww.js → xq0mvhts.js} +8 -8
  123. package/dist/shared/xqve9598.js +53 -0
  124. package/dist/shared/{47x8x9ze.js → y2t3jktd.js} +2 -2
  125. package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
  126. package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
  127. package/dist/shared/{nkaxvt9q.js → ys0xzyaj.js} +1 -1
  128. package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
  129. package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
  130. package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
  131. package/dist/shared/{r8x5qhd7.js → zm0mafk4.js} +10 -4
  132. package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
  133. package/dist/tooling/cli.js +41 -15
  134. package/dist/tooling/migrate/apply.d.ts +14 -0
  135. package/dist/tooling/migrate/check.d.ts +3 -4
  136. package/dist/tooling/migrate/classify.d.ts +4 -0
  137. package/dist/tooling/migrate/config.d.ts +3 -2
  138. package/dist/tooling/migrate/files.d.ts +11 -1
  139. package/dist/tooling/migrate/index.js +14 -14
  140. package/dist/tooling/migrate/lint.d.ts +1 -1
  141. package/dist/tooling/migrate/lost.d.ts +28 -0
  142. package/dist/tooling/migrate/paths.d.ts +14 -0
  143. package/dist/tooling/migrate/plan.d.ts +6 -3
  144. package/dist/tooling/migrate/runner.d.ts +25 -0
  145. package/dist/tooling/migrate/sandbox.d.ts +57 -0
  146. package/dist/tooling/migrate/sql-lex.d.ts +20 -3
  147. package/dist/tooling/migrate/text.d.ts +42 -0
  148. package/dist/tooling/node-version.d.ts +21 -0
  149. package/dist/tooling/testing/facts.d.ts +33 -5
  150. package/dist/tooling/testing/index.d.ts +1 -1
  151. package/dist/tooling/testing/index.js +3 -3
  152. package/dist/tooling/testing/isolation.d.ts +11 -5
  153. package/package.json +5 -2
  154. package/dist/shared/7zwwyh0v.js +0 -448
  155. package/dist/shared/q58y17hy.js +0 -21
@@ -1,197 +1,33 @@
1
+ import {
2
+ viewClient
3
+ } from "../../../shared/x3jc53kg.js";
1
4
  import {
2
5
  viewObject,
3
6
  materializedViewObject,
4
7
  materializedViewIndex
5
- } from "../../../shared/y005b761.js";
6
- import {
7
- encodeUuid,
8
- decodeUuid
9
- } from "../../../shared/dyj86cmj.js";
10
- import {
11
- snakeCase
12
- } from "../../../shared/ntneex2a.js";
13
- import {
14
- encodeText,
15
- decodeText
16
- } from "../../../shared/4m9fn52z.js";
8
+ } from "../../../shared/zy8r7qvz.js";
17
9
  import {
18
10
  staticNamespace2
19
- } from "../../../shared/t4tbsy9h.js";
11
+ } from "../../../shared/358zsv4r.js";
20
12
  import {
21
13
  OkmError2
22
14
  } from "../../../shared/52szzakm.js";
23
15
 
24
- // src/dialects/pg/view/client.ts
25
- function viewClient(name, columns, query, tenancy) {
26
- const field = camelCase(name);
27
- const marked = readGlobal(name, tenancy);
28
- return {
29
- field,
30
- install(model, scope, tables, casing, scoped) {
31
- if (Object.hasOwn(model, field)) {
32
- throw new OkmError2("OKM1023", `View ${name} uses the client name ${field}.`, {
33
- fix: { summary: "Give the view a name that no table uses." }
34
- });
35
- }
36
- const exposes = exposesKey(columns, scope);
37
- if (scope !== undefined && readsTenant(query, tables, casing, scoped)) {
38
- if (!exposes && marked === undefined) {
39
- throw new OkmError2("OKM1820", `View ${name} reads a tenant table and does not expose ${scope.key}.`, {
40
- fix: {
41
- summary: "Expose the tenant key so the predicate can be applied, or declare global(reason)."
42
- }
43
- });
44
- }
45
- if (exposes) {
46
- scope.scopeView(field);
47
- scoped.add(name);
48
- }
49
- }
50
- model[field] = {
51
- name: field,
52
- sql: name,
53
- primary: [],
54
- uniques: [],
55
- columns: columnModels(columns, scope),
56
- relations: []
57
- };
58
- },
59
- hook(target, ctx) {
60
- publish(field, target, ctx);
61
- }
62
- };
63
- }
64
- function publish(field, target, ctx) {
65
- if (ctx.tables === undefined || ctx.table !== undefined)
66
- return;
67
- const handle = ctx.tables[field];
68
- if (typeof handle !== "object" || handle === null)
69
- return;
70
- const source = handle;
71
- const views = target.views;
72
- const map = typeof views === "object" && views !== null ? views : {};
73
- map[field] = {
74
- find: source.find,
75
- one: source.one,
76
- count: source.count,
77
- exists: source.exists
78
- };
79
- target.views = map;
80
- delete ctx.tables[field];
81
- delete target[field];
82
- }
83
- function columnModels(columns, tenancy) {
84
- const seen = new Set;
85
- const models = [];
86
- for (const column of columns) {
87
- const field = fieldName(column.name, tenancy);
88
- if (seen.has(field)) {
89
- throw new OkmError2("OKM1020", `View column ${column.name} repeats ${field}.`, {
90
- fix: { summary: "Declare each output column once." }
91
- });
92
- }
93
- seen.add(field);
94
- const uuid = column.type.toLowerCase() === "uuid";
95
- const key = tenancy !== undefined && field === tenancy.key;
96
- models.push({
97
- field,
98
- sql: column.name,
99
- dataType: column.type,
100
- encode: uuid ? (value) => encodeUuid(textValue(value)) : (value) => encodeText(textValue(value)),
101
- decode: uuid ? decodeUuid : decodeText,
102
- hidden: false,
103
- sensitive: false,
104
- guarded: key,
105
- writable: false,
106
- guardUpdate: false
107
- });
108
- }
109
- return models;
110
- }
111
- function exposesKey(columns, tenancy) {
112
- if (tenancy === undefined)
113
- return false;
114
- return columns.some((column) => fieldName(column.name, tenancy) === tenancy.key);
115
- }
116
- function readsTenant(query, tables, casing, scoped) {
117
- for (const name of scoped) {
118
- if (mentions(query, name))
119
- return true;
120
- }
121
- for (const table of tables) {
122
- const mark = table.options?.tenancy;
123
- if (isGlobalMark(mark))
124
- continue;
125
- const sql = casing === "snake" ? snakeCase(table.name) : table.name;
126
- if (mentions(query, sql) || mentions(query, table.name))
127
- return true;
128
- }
129
- return false;
130
- }
131
- function readGlobal(name, tenancy) {
132
- if (tenancy === undefined)
133
- return;
134
- if (!isGlobalMark(tenancy)) {
135
- throw new OkmError2("OKM1020", `View ${name} tenancy must be global("reason").`, {
136
- fix: { summary: 'Pass global("reason") from okmodel/tenancy, or omit tenancy.' }
137
- });
138
- }
139
- return tenancy.reason;
140
- }
141
- function isGlobalMark(value) {
142
- if (typeof value !== "object" || value === null)
143
- return false;
144
- const record = value;
145
- return record.kind === "global" && typeof record.reason === "string" && record.reason.trim().length > 0;
146
- }
147
- function fieldName(column, tenancy) {
148
- const field = camelCase(column);
149
- if (tenancy !== undefined && (column === tenancy.key || field === tenancy.key))
150
- return tenancy.key;
151
- return field;
152
- }
153
- function camelCase(name) {
154
- let out = "";
155
- let upper = false;
156
- for (const char of name) {
157
- if (char === "_") {
158
- upper = out.length > 0;
159
- continue;
160
- }
161
- out += upper ? char.toUpperCase() : char;
162
- upper = false;
163
- }
164
- return out;
165
- }
166
- function mentions(query, name) {
167
- let pattern = '(^|[^A-Za-z0-9_])"?';
168
- for (const char of name) {
169
- if ("\\^$[]().*+?|{}".includes(char))
170
- pattern += "\\";
171
- pattern += char;
172
- }
173
- pattern += '"?(?![A-Za-z0-9_])';
174
- return new RegExp(pattern).test(query);
175
- }
176
- function textValue(value) {
177
- if (typeof value !== "string") {
178
- throw new OkmError2("OKM1121", "A view column value must be text.", {
179
- fix: { summary: "Pass a string." }
180
- });
181
- }
182
- return value;
183
- }
184
-
185
16
  // src/dialects/pg/view/index.ts
186
17
  function view(name, options) {
187
18
  const schema = options.schema ?? "public";
188
19
  const columns = options.columns.map((column) => ({ name: column.name, dataType: column.type }));
189
20
  const query = bodyText(options.query);
190
- const bound = viewClient(name, options.columns, query, options.tenancy);
21
+ const bound = viewClient(name, options.columns, query, options.tenancy, "plain");
22
+ let securityInvoker = false;
191
23
  return {
192
24
  name,
193
25
  schema,
194
- install: bound.install,
26
+ "~kind": "view",
27
+ install(model, tenancy, tables, casing, scoped) {
28
+ bound.install(model, tenancy, tables, casing, scoped);
29
+ securityInvoker = tenancy?.strategy === "rls" && scoped.has(name);
30
+ },
195
31
  hook: bound.hook,
196
32
  contribute(peers, built) {
197
33
  assertPeers(peers);
@@ -203,7 +39,8 @@ function view(name, options) {
203
39
  name,
204
40
  columns,
205
41
  query,
206
- provenance
42
+ provenance,
43
+ ...securityInvoker ? { securityInvoker: true } : {}
207
44
  })
208
45
  ];
209
46
  }
@@ -213,7 +50,12 @@ function materializedView(name, options) {
213
50
  const schema = options.schema ?? "public";
214
51
  const columns = options.columns.map((column) => ({ name: column.name, dataType: column.type }));
215
52
  const query = bodyText(options.query);
216
- const bound = viewClient(name, options.columns, query, options.tenancy);
53
+ if (options.refresh !== undefined && options.refresh !== "concurrently") {
54
+ throw new OkmError2("OKM1120", `Materialized view ${name} refresh must be "concurrently".`, {
55
+ fix: { summary: 'Omit refresh, or pass refresh: "concurrently" with a unique index.' }
56
+ });
57
+ }
58
+ const bound = viewClient(name, options.columns, query, options.tenancy, options.refresh === "concurrently" ? "concurrently" : "blocking");
217
59
  const indexes = options.indexes ?? [];
218
60
  if (options.refresh === "concurrently" && !indexes.some((index) => index.unique === true)) {
219
61
  throw new OkmError2("OKM1822", `Materialized view ${name} refreshes concurrently and has no unique index.`, { fix: { summary: "Add a unique index, or refresh without CONCURRENTLY." } });
@@ -229,6 +71,7 @@ function materializedView(name, options) {
229
71
  return {
230
72
  name,
231
73
  schema,
74
+ "~kind": "materialized",
232
75
  install: bound.install,
233
76
  hook: bound.hook,
234
77
  contribute(peers, built) {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `REFRESH MATERIALIZED VIEW` for one view handle.
3
+ *
4
+ * Loaded the first time `refresh()` runs. A featureless app, and an app that
5
+ * never calls it, do not import this module. The name is unqualified so the
6
+ * session `search_path` selects the schema, matching a view `find`.
7
+ */
8
+ /**
9
+ * Refreshes one materialized view on the primary.
10
+ *
11
+ * `CONCURRENTLY` when the declaration asked for it. The statement timeout is
12
+ * the client's, the same ceiling a write uses. A database failure is mapped
13
+ * and logged like any other statement.
14
+ *
15
+ * The refresh runs on a reserved primary connection with `app.unscoped` set
16
+ * in that same transaction. Under `FORCE ROW LEVEL SECURITY` the owner would
17
+ * otherwise refresh zero rows. `CONCURRENTLY` cannot run inside a transaction,
18
+ * so that form sets the session value and clears it before release.
19
+ *
20
+ * @param session - Pool, timeout, and logger from the client
21
+ * @param name - SQL name of the materialized view
22
+ * @param concurrently - True when the view declares `refresh: "concurrently"`
23
+ */
24
+ export declare function refreshView(session: object, name: string, concurrently: boolean): Promise<void>;
@@ -12,7 +12,7 @@ import { type Session } from "./client.js";
12
12
  * Runs write handles as one atomic unit.
13
13
  *
14
14
  * @param session - Client session
15
- * @param ops - Write handles: `insert`, `update`, `delete`, `archive`. A `restore`, or a write with `expect`, is OKM1121 (D183)
15
+ * @param ops - Write handles: `insert`, `update`, `delete`, `archive`. A `restore`, a write with `expect`, or `refresh()` is OKM1121 (D183, D239)
16
16
  * @param options - `signal` and `timeout` for the whole batch
17
17
  * @param replica - Set by `.replica()`. A batch needs the primary (OKM1840)
18
18
  * @returns One result per operation, in order
@@ -18,10 +18,10 @@ export type ConflictPlan = {
18
18
  * @param table - Target table
19
19
  * @param value - The option the caller passed
20
20
  * @param allow - Guarded fields this write may set
21
- * @param tenantKey - The tenant key on a tenant schema, which every unique includes
21
+ * @param tenantKey - The tenant key, or every tenant key when the schema has several. A unique that includes them matches when `on` names the other columns. The target keeps the keys, in the unique's order. Naming a key is OKM1104.
22
22
  * @returns The plan, or `undefined` for the default `"error"`
23
23
  */
24
- export declare function readConflict(table: Indexed, value: unknown, allow?: ReadonlySet<string>, tenantKey?: string): ConflictPlan | undefined;
24
+ export declare function readConflict(table: Indexed, value: unknown, allow?: ReadonlySet<string>, tenantKey?: string | readonly string[]): ConflictPlan | undefined;
25
25
  /**
26
26
  * Appends the conflict clause, or wraps a first-or-create insert.
27
27
  *
@@ -29,3 +29,12 @@ export declare function assertCompatible(pool: DriverPool, schema: QuerySchema,
29
29
  readonly catalog?: CatalogArtifact;
30
30
  readonly catalogDir?: string;
31
31
  }, options: ExecuteOptions | undefined): Promise<void>;
32
+ /**
33
+ * Directory of `catalog.hash` and `catalog.json`.
34
+ *
35
+ * A trailing `/` or `\` is removed so the joined file name is one path.
36
+ *
37
+ * @param catalogDir - Directory the caller passed, or the default `.okm`
38
+ * @returns The directory, without a trailing slash
39
+ */
40
+ export declare function artifactDir(catalogDir: string | undefined): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Refuses a positive timeout on a driver that cannot cancel.
3
+ *
4
+ * `tx({ timeout })` and `batch({ timeout })` load this with the call. The
5
+ * connect graph does not. The message stays the one {@link noTimeout} throws.
6
+ */
7
+ import type { DriverPool } from "../contracts/driver.js";
8
+ /**
9
+ * Throws OKM1120 when `timeout` is positive and the driver cannot cancel.
10
+ *
11
+ * @param pool - Driver the call will use
12
+ * @param timeout - Milliseconds, when the caller passed one
13
+ */
14
+ export declare function refuseUncancellableTimeout(pool: DriverPool, timeout: number | undefined): Promise<void>;
@@ -1,9 +1,10 @@
1
+ import"../../shared/8dqhth8c.js";
1
2
  import {
2
3
  DriverError2
3
4
  } from "../../shared/31vm914h.js";
4
5
  import {
5
6
  open5
6
- } from "../../shared/k8v5v5wj.js";
7
+ } from "../../shared/32cnm7kn.js";
7
8
  import {
8
9
  BUNSQL_CAPABILITIES,
9
10
  readCapability2,
@@ -11,12 +12,12 @@ import {
11
12
  } from "../../shared/cgbamx3e.js";
12
13
  import {
13
14
  createClient
14
- } from "../../shared/hf22e0wt.js";
15
+ } from "../../shared/j60w0dvr.js";
15
16
 
16
17
  // src/runtime/pg/bun.ts
17
18
  function connect(target, options) {
18
19
  if (typeof target === "object" && !isPool(target)) {
19
- return import("../../shared/nxdp2ze3.js").then((mod) => mod.default(target, options, open5));
20
+ return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open5));
20
21
  }
21
22
  const owned = !isPool(target);
22
23
  const pool = isPool(target) ? target : open5({
@@ -3,7 +3,7 @@ import {
3
3
  } from "../../shared/31vm914h.js";
4
4
  import {
5
5
  open4
6
- } from "../../shared/96qcj21c.js";
6
+ } from "../../shared/1z04fa85.js";
7
7
  import {
8
8
  NODE_POSTGRES_CAPABILITIES,
9
9
  readCapability2,
@@ -11,12 +11,12 @@ import {
11
11
  } from "../../shared/cgbamx3e.js";
12
12
  import {
13
13
  createClient
14
- } from "../../shared/hf22e0wt.js";
14
+ } from "../../shared/j60w0dvr.js";
15
15
 
16
16
  // src/runtime/pg/pg.ts
17
17
  function connect(target, options) {
18
18
  if (typeof target === "object" && !isPool(target)) {
19
- return import("../../shared/nxdp2ze3.js").then((mod) => mod.default(target, options, open4));
19
+ return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open4));
20
20
  }
21
21
  const owned = !isPool(target);
22
22
  const pool = isPool(target) ? target : open4({
@@ -1,9 +1,10 @@
1
+ import"../../shared/8dqhth8c.js";
1
2
  import {
2
3
  DriverError2
3
4
  } from "../../shared/31vm914h.js";
4
5
  import {
5
6
  open3
6
- } from "../../shared/87jvvhnt.js";
7
+ } from "../../shared/5j36z8dn.js";
7
8
  import {
8
9
  PGLITE_CAPABILITIES,
9
10
  readCapability2,
@@ -11,12 +12,12 @@ import {
11
12
  } from "../../shared/cgbamx3e.js";
12
13
  import {
13
14
  createClient
14
- } from "../../shared/hf22e0wt.js";
15
+ } from "../../shared/j60w0dvr.js";
15
16
 
16
17
  // src/runtime/pg/pglite.ts
17
18
  async function connect(target, options) {
18
19
  if (typeof target === "object" && !isPool(target)) {
19
- return import("../../shared/nxdp2ze3.js").then((mod) => mod.default(target, options, open3));
20
+ return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open3));
20
21
  }
21
22
  const pool = isPool(target) ? target : await open3({
22
23
  ...target !== undefined ? { dataDir: target } : {},
@@ -3,7 +3,7 @@ import {
3
3
  } from "../../shared/31vm914h.js";
4
4
  import {
5
5
  open2
6
- } from "../../shared/krxx77g0.js";
6
+ } from "../../shared/wkme6tep.js";
7
7
  import {
8
8
  POSTGRESJS_CAPABILITIES,
9
9
  readCapability2,
@@ -11,12 +11,12 @@ import {
11
11
  } from "../../shared/cgbamx3e.js";
12
12
  import {
13
13
  createClient
14
- } from "../../shared/hf22e0wt.js";
14
+ } from "../../shared/j60w0dvr.js";
15
15
 
16
16
  // src/runtime/pg/postgresjs.ts
17
17
  function connect(target, options) {
18
18
  if (typeof target === "object" && !isPool(target)) {
19
- return import("../../shared/nxdp2ze3.js").then((mod) => mod.default(target, options, open2));
19
+ return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open2));
20
20
  }
21
21
  const owned = !isPool(target);
22
22
  const pool = isPool(target) ? target : open2({
@@ -18,6 +18,7 @@ export type RouteConstraint = "auto" | "primary" | "replica";
18
18
  */
19
19
  export type CallScope = {
20
20
  readonly value: string;
21
+ readonly values?: Readonly<Record<string, string>>;
21
22
  } | {
22
23
  readonly unscoped: string;
23
24
  };
@@ -249,6 +250,15 @@ export declare function emitJoin(sink: Sink, parent: string, child: string, rela
249
250
  export declare function emitWhere(schema: QuerySchema, table: Indexed, where: unknown, sink: Sink, alias: string, depth: number, appended?: boolean, extra?: Keyset): void;
250
251
  export declare function emitOrder(table: Indexed, orderBy: unknown, sink: Sink, alias: string): void;
251
252
  export declare function emitPrimaryOrder(table: Indexed, sink: Sink, alias: string): void;
253
+ /**
254
+ * Refuses a hidden field in `where` or `orderBy`.
255
+ *
256
+ * `"filter"` is `hidden({ filterable: true })` and is allowed here.
257
+ * Aggregate loads this on its first call and applies it before the groupBy rule.
258
+ *
259
+ * @param column - The field the caller named
260
+ */
261
+ export declare function refuseHidden(column: ColumnModel): void;
252
262
  export type ParsedInclude = {
253
263
  readonly name: string;
254
264
  readonly relation: RelationModel;
@@ -289,18 +299,15 @@ export declare function quote(name: string): string;
289
299
  export declare function list(names: readonly string[]): string;
290
300
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
291
301
  /**
292
- * Whether `where` constrains a row.
302
+ * Throws OKM1121 for an `or()` that is not an array, or for an empty branch.
293
303
  *
294
- * A field value is a leaf. Anything other than `undefined` counts, including
295
- * `null`, objects, arrays, and operators. The walk does not enter a field value.
296
- * It enters the where object's own keys, `and`, `or`, and `not` when `not` is
297
- * the where itself. An `or()` branch with no predicate is OKM1121. `or([])`
298
- * matches nothing.
304
+ * The write and archive predicate walk uses the same throw. It lives here
305
+ * because the read planner throws it too, and that planner stays in this module.
299
306
  *
300
- * @param where - Caller filter, or one `and` / `or` / `not` operand
301
- * @returns `false` when the filter matches every row
307
+ * @param empty - `true` when a branch has no predicate
308
+ * @returns Never
302
309
  */
303
- export declare function effectivePredicate(where: unknown): boolean;
310
+ export declare function orFail(empty: boolean): never;
304
311
  /**
305
312
  * Records the fix text for a code thrown from a chunk that loads on first use.
306
313
  *
@@ -316,6 +323,7 @@ export declare function registerFailFix(code: QueryCode, summary: string): void;
316
323
  *
317
324
  * @param code - Spec code
318
325
  * @param message - What failed
326
+ * @param fix - Fix sentence for this call. Omitted, the sentence registered for `code` is used
319
327
  */
320
- export declare function fail(code: QueryCode, message: string): never;
328
+ export declare function fail(code: QueryCode, message: string, fix?: string): never;
321
329
  export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Whether a `where` constrains a row.
3
+ *
4
+ * Write and archive load this module. A read does not. The walk is the same
5
+ * one those paths used when it lived in the planner.
6
+ */
7
+ /**
8
+ * Whether `where` constrains a row.
9
+ *
10
+ * A field value is a leaf. Anything other than `undefined` counts, including
11
+ * `null`, objects, arrays, and operators. The walk does not enter a field value.
12
+ * It enters the where object's own keys, `and`, `or`, and `not` when `not` is
13
+ * the where itself. An `or()` branch with no predicate is OKM1121. `or([])`
14
+ * matches nothing.
15
+ *
16
+ * @param where - Caller filter, or one `and` / `or` / `not` operand
17
+ * @returns `false` when the filter matches every row
18
+ */
19
+ export declare function effectivePredicate(where: unknown): boolean;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  callerLocation
3
- } from "../../shared/k7dwkhvq.js";
3
+ } from "../../shared/y6jdds7g.js";
4
4
  import {
5
5
  installSafetyHook
6
6
  } from "../../shared/a5sxz52y.js";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Composite tenancy (`compositeTenancy()`).
3
+ *
4
+ * Every tenant table carries the key list, in that order. A column-only app
5
+ * does not import this file. `via()` is a separate import: this file calls a
6
+ * table's own `rewrite` and does not load the path compiler.
7
+ */
8
+ import type { ColumnTenancy } from "../../dialects/pg/tenancy.js";
9
+ /**
10
+ * Composite tenancy for `schema({ tenancy })`.
11
+ *
12
+ * Every table gains each key unless it passes `global("reason")` or `via()`.
13
+ * The keys are guarded uuids, in this order. Insert fills them from `for()`.
14
+ * Reads and writes filter on every key.
15
+ *
16
+ * @typeParam Keys - Field names, at least one
17
+ * @param input - The key list and `uuid`
18
+ * @returns The object `schema()` applies
19
+ */
20
+ export declare function compositeTenancy<const Keys extends readonly [string, ...string[]]>(input: {
21
+ readonly key: Keys;
22
+ readonly type: "uuid";
23
+ }): ColumnTenancy & {
24
+ readonly key: Keys[number];
25
+ readonly keys: Keys;
26
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What a table tenancy `rewrite` receives.
3
+ *
4
+ * `columnTenancy()` and `compositeTenancy()` pass it. `via()` reads it.
5
+ * This file is types only, so it is not in a bundle.
6
+ */
7
+ import type { AnyTable } from "../../dialects/pg/table.js";
8
+ import type { ColumnTenancy } from "../../dialects/pg/tenancy.js";
9
+ /** Context for one table whose tenancy mark carries `rewrite`. */
10
+ export type TableRewriteContext = {
11
+ readonly tables: readonly AnyTable[];
12
+ readonly keys: readonly string[];
13
+ readonly encodes: readonly ((value: string) => string)[];
14
+ readonly api: ColumnTenancy;
15
+ readonly extras: Map<string, readonly string[]>;
16
+ };
@@ -22,16 +22,20 @@ export declare function global(reason: string): {
22
22
  /**
23
23
  * Column tenancy for `schema({ tenancy })`.
24
24
  *
25
- * Every table gains `key` unless it passes `global("reason")`. The key is a
26
- * guarded uuid. Insert fills it from `for()`. Reads and writes filter on it.
25
+ * Every table gains `key` unless it passes `global("reason")` or `via()`.
26
+ * The key is a guarded uuid. Insert fills it from `for()`. Reads and writes
27
+ * filter on it. A list of keys is `compositeTenancy()`.
27
28
  *
28
29
  * @typeParam Key - Field name of the tenant key
29
30
  * @param input - Field name and `uuid`
30
31
  * @returns The object `schema()` applies
31
32
  */
32
- export declare function columnTenancy<const Key extends string>(input: {
33
- readonly key: Key;
33
+ export declare function columnTenancy<const Key>(input: {
34
+ readonly key: Key extends readonly unknown[] ? "columnTenancy() takes one key. Use compositeTenancy()." : Key extends string ? Key : "columnTenancy() key must be a field name.";
34
35
  readonly type: "uuid";
35
36
  }): ColumnTenancy & {
36
- readonly key: Key;
37
+ readonly key: Key extends string ? Key : string;
37
38
  };
39
+ export { compositeTenancy } from "./composite.js";
40
+ export { via } from "./via.js";
41
+ export { RlsRoleError, rlsTenancy, type RlsRoleReason } from "./rls.js";