okmodel 0.5.1 → 0.7.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 (233) hide show
  1. package/README.md +100 -1116
  2. package/dist/adapters/capabilities.d.ts +3 -0
  3. package/dist/adapters/failure.d.ts +13 -2
  4. package/dist/adapters/lazy-errors.d.ts +22 -0
  5. package/dist/adapters/pg/bunsql-extra.d.ts +54 -3
  6. package/dist/adapters/pg/bunsql.d.ts +14 -1
  7. package/dist/adapters/pg/cursor.d.ts +17 -0
  8. package/dist/adapters/pg/no-inflight-timeout.d.ts +20 -0
  9. package/dist/adapters/pg/nodepostgres-extra.d.ts +22 -1
  10. package/dist/adapters/pg/nodepostgres.d.ts +12 -0
  11. package/dist/adapters/pg/pglite-wire.d.ts +24 -0
  12. package/dist/adapters/pg/pglite.d.ts +10 -0
  13. package/dist/adapters/pg/postgres-extra.d.ts +41 -3
  14. package/dist/adapters/pg/reserved.d.ts +42 -0
  15. package/dist/adapters/pg/session.d.ts +0 -18
  16. package/dist/contracts/catalog/document.d.ts +19 -5
  17. package/dist/contracts/catalog/object.d.ts +2 -1
  18. package/dist/contracts/catalog/policy.d.ts +48 -0
  19. package/dist/contracts/catalog/types.d.ts +25 -1
  20. package/dist/contracts/catalog/view.d.ts +2 -0
  21. package/dist/contracts/connection.d.ts +7 -6
  22. package/dist/contracts/internal.js +1 -1
  23. package/dist/contracts/location.d.ts +10 -0
  24. package/dist/dialects/pg/column.d.ts +13 -2
  25. package/dist/dialects/pg/ddl.d.ts +37 -1
  26. package/dist/dialects/pg/emit.d.ts +19 -1
  27. package/dist/dialects/pg/errors.d.ts +32 -1
  28. package/dist/dialects/pg/ext/citext.js +1 -1
  29. package/dist/dialects/pg/ext/index.js +1 -1
  30. package/dist/dialects/pg/ext/pg-trgm.js +1 -1
  31. package/dist/dialects/pg/filter-parse.d.ts +5 -4
  32. package/dist/dialects/pg/floor.d.ts +68 -0
  33. package/dist/dialects/pg/fn/index.js +2 -2
  34. package/dist/dialects/pg/index.d.ts +8 -2
  35. package/dist/dialects/pg/index.js +67 -171
  36. package/dist/dialects/pg/introspect.d.ts +7 -0
  37. package/dist/dialects/pg/keys.d.ts +11 -8
  38. package/dist/dialects/pg/model.d.ts +47 -2
  39. package/dist/dialects/pg/morph.d.ts +43 -0
  40. package/dist/dialects/pg/operator-fit.d.ts +2 -2
  41. package/dist/dialects/pg/operators.d.ts +14 -7
  42. package/dist/dialects/pg/ops/bucket.d.ts +65 -0
  43. package/dist/dialects/pg/ops/inc.d.ts +2 -2
  44. package/dist/dialects/pg/ops/matches.d.ts +9 -12
  45. package/dist/dialects/pg/ops/relevance.d.ts +13 -0
  46. package/dist/dialects/pg/ops/search-query.d.ts +22 -0
  47. package/dist/dialects/pg/ops/window.d.ts +103 -0
  48. package/dist/dialects/pg/owner.d.ts +42 -0
  49. package/dist/dialects/pg/path-endpoint.d.ts +20 -0
  50. package/dist/dialects/pg/preset.d.ts +1 -1
  51. package/dist/dialects/pg/relations.d.ts +100 -3
  52. package/dist/dialects/pg/role/check.d.ts +3 -0
  53. package/dist/dialects/pg/role/index.d.ts +71 -6
  54. package/dist/dialects/pg/role/sql.d.ts +11 -0
  55. package/dist/dialects/pg/schema.d.ts +33 -3
  56. package/dist/dialects/pg/table.d.ts +25 -3
  57. package/dist/dialects/pg/tenancy.d.ts +45 -3
  58. package/dist/dialects/pg/view/client.d.ts +19 -1
  59. package/dist/dialects/pg/view/index.d.ts +4 -0
  60. package/dist/dialects/pg/view/index.js +21 -178
  61. package/dist/dialects/pg/view/refresh.d.ts +24 -0
  62. package/dist/runtime/aggregate.d.ts +8 -2
  63. package/dist/runtime/batch.d.ts +1 -1
  64. package/dist/runtime/bucket-group.d.ts +70 -0
  65. package/dist/runtime/conflict.d.ts +24 -6
  66. package/dist/runtime/drift.d.ts +9 -0
  67. package/dist/runtime/include.d.ts +0 -8
  68. package/dist/runtime/inflight.d.ts +14 -0
  69. package/dist/runtime/page.d.ts +4 -1
  70. package/dist/runtime/pg/bun.js +12 -5
  71. package/dist/runtime/pg/pg.js +5 -5
  72. package/dist/runtime/pg/pglite.d.ts +1 -0
  73. package/dist/runtime/pg/pglite.js +9 -8
  74. package/dist/runtime/pg/postgresjs.js +5 -5
  75. package/dist/runtime/plan.d.ts +113 -15
  76. package/dist/runtime/predicate.d.ts +19 -0
  77. package/dist/runtime/read-stream.d.ts +13 -16
  78. package/dist/runtime/result-name.d.ts +17 -0
  79. package/dist/runtime/safety/index.js +1 -1
  80. package/dist/runtime/server-check.d.ts +3 -3
  81. package/dist/runtime/sort-bind.d.ts +21 -0
  82. package/dist/runtime/sort.d.ts +56 -0
  83. package/dist/runtime/sync.d.ts +70 -0
  84. package/dist/runtime/tenancy/composite.d.ts +26 -0
  85. package/dist/runtime/tenancy/context.d.ts +16 -0
  86. package/dist/runtime/tenancy/index.d.ts +9 -5
  87. package/dist/runtime/tenancy/index.js +1511 -38
  88. package/dist/runtime/tenancy/path.d.ts +87 -0
  89. package/dist/runtime/tenancy/rls.d.ts +67 -0
  90. package/dist/runtime/tenancy/via.d.ts +22 -0
  91. package/dist/runtime/text-search.d.ts +20 -0
  92. package/dist/runtime/traits/index.d.ts +80 -0
  93. package/dist/runtime/traits/index.js +187 -17
  94. package/dist/runtime/tree.d.ts +38 -0
  95. package/dist/runtime/types.d.ts +231 -23
  96. package/dist/runtime/validate/index.js +4 -4
  97. package/dist/runtime/version.d.ts +39 -0
  98. package/dist/runtime/window.d.ts +21 -0
  99. package/dist/runtime/write.d.ts +55 -3
  100. package/dist/shared/{krxx77g0.js → 14vx95q4.js} +12 -18
  101. package/dist/shared/1est4ezg.js +313 -0
  102. package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
  103. package/dist/shared/1w508jbr.js +1611 -0
  104. package/dist/shared/2c13q96h.js +18 -0
  105. package/dist/shared/2d3xq4ps.js +9 -0
  106. package/dist/shared/2shdbn8q.js +23 -0
  107. package/dist/shared/{t4tbsy9h.js → 358zsv4r.js} +1 -1
  108. package/dist/shared/3v7t1yrv.js +208 -0
  109. package/dist/shared/5e3tf63j.js +220 -0
  110. package/dist/shared/5fe3kbsh.js +10 -0
  111. package/dist/shared/5v3xf80k.js +37 -0
  112. package/dist/shared/{51mvgj8w.js → 63qtkrca.js} +130 -3
  113. package/dist/shared/{gbtcc2d7.js → 67txcrcw.js} +62 -66
  114. package/dist/shared/79dt02vc.js +12 -0
  115. package/dist/shared/{v36c5g6p.js → 7k9grvf6.js} +407 -14
  116. package/dist/shared/7kms6fvj.js +20 -0
  117. package/dist/shared/7mnme5tn.js +8 -0
  118. package/dist/shared/7n7ddwt4.js +6 -0
  119. package/dist/shared/{87jvvhnt.js → 81ebdx9p.js} +48 -68
  120. package/dist/shared/{szm0cksa.js → 8skf0cam.js} +34 -6
  121. package/dist/shared/{gjthds9j.js → 9628a9xt.js} +1 -1
  122. package/dist/shared/9a4ae4p8.js +31 -0
  123. package/dist/shared/{8xsbagad.js → 9s0ypp87.js} +88 -7
  124. package/dist/shared/9y3mmmh1.js +436 -0
  125. package/dist/shared/ab9gmbwy.js +213 -0
  126. package/dist/shared/{sycnx8gt.js → ax7qv55k.js} +18 -8
  127. package/dist/shared/{f5cw5q5r.js → aytqh5y2.js} +6 -4
  128. package/dist/shared/{fancm5pt.js → b5pftnn2.js} +138 -15
  129. package/dist/shared/{efmy2gcg.js → b76b8d95.js} +2 -2
  130. package/dist/shared/bdk4sty6.js +58 -0
  131. package/dist/shared/{32zqc1dw.js → bg3rym3g.js} +63 -32
  132. package/dist/shared/{0t22wwh1.js → bm22fvzr.js} +16 -14
  133. package/dist/shared/bz84tkzm.js +342 -0
  134. package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
  135. package/dist/shared/cn957f8d.js +179 -0
  136. package/dist/shared/{pf0d8f77.js → cnkky55j.js} +25 -14
  137. package/dist/shared/{5fqx9yh4.js → dk8v79p3.js} +3 -1
  138. package/dist/shared/{nkaxvt9q.js → dkxgzaqd.js} +224 -19
  139. package/dist/shared/dzj09cye.js +10 -0
  140. package/dist/shared/{4m9fn52z.js → ed0b8k4s.js} +1 -1
  141. package/dist/shared/{z2rnngj4.js → ek2wt2dz.js} +8 -5
  142. package/dist/shared/exn3sd90.js +359 -0
  143. package/dist/shared/g6evj1j3.js +66 -0
  144. package/dist/shared/ga9j92qj.js +25 -0
  145. package/dist/shared/{qv2ydck9.js → gs74dbj5.js} +651 -76
  146. package/dist/shared/gzaveazc.js +285 -0
  147. package/dist/shared/{8rsy3hxz.js → h15jx9bc.js} +1 -1
  148. package/dist/shared/{dyj86cmj.js → hyh73qk6.js} +3 -3
  149. package/dist/shared/je4axnm8.js +22 -0
  150. package/dist/shared/{ycatkxmq.js → jgqj11w4.js} +1 -1
  151. package/dist/shared/{6qd27mx0.js → jvd0mqag.js} +5 -5
  152. package/dist/shared/jznfax0y.js +155 -0
  153. package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
  154. package/dist/shared/{ps7a6h14.js → kr0jzbw2.js} +12 -8
  155. package/dist/shared/{janx09m5.js → ktz42yez.js} +20 -8
  156. package/dist/shared/{gde73es6.js → m6p12kbr.js} +56 -55
  157. package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
  158. package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
  159. package/dist/shared/{nxdp2ze3.js → mtaszv5a.js} +144 -12
  160. package/dist/shared/n816peh1.js +45 -0
  161. package/dist/shared/nbw1z4yd.js +18 -0
  162. package/dist/shared/{cctw17hj.js → p6qc5gcp.js} +38 -34
  163. package/dist/shared/{6rk2gen5.js → pbp1ss85.js} +20 -17
  164. package/dist/shared/pt94kz7f.js +6 -0
  165. package/dist/shared/{wq9n6pwr.js → pz6rj8ay.js} +82 -9
  166. package/dist/shared/q5c6ngn3.js +13 -0
  167. package/dist/shared/{8bwbwy8h.js → qq3899ht.js} +128 -18
  168. package/dist/shared/{8ktwd3rh.js → r3j8s5y0.js} +1 -1
  169. package/dist/shared/rhs3xe4k.js +7 -0
  170. package/dist/shared/{ntneex2a.js → rpycarcr.js} +6 -6
  171. package/dist/shared/{sdc7r2ww.js → rs73fca9.js} +8 -8
  172. package/dist/shared/{tm5ab8we.js → sfz1ksn6.js} +7 -4
  173. package/dist/shared/{6mnp99hx.js → svncdeh5.js} +16 -12
  174. package/dist/shared/{hf22e0wt.js → tbrvgw6z.js} +62 -42
  175. package/dist/shared/te5as7z7.js +622 -0
  176. package/dist/shared/{ga3sfy93.js → tsvww22q.js} +535 -200
  177. package/dist/shared/{47x8x9ze.js → ttsqgp4p.js} +20 -13
  178. package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
  179. package/dist/shared/vb6qfyve.js +152 -0
  180. package/dist/shared/{r2sp8hrc.js → vczs8gd4.js} +22 -13
  181. package/dist/shared/{1g0drakv.js → vqrjpcqn.js} +145 -3
  182. package/dist/shared/{2pqx26h8.js → w72kgg4q.js} +31 -22
  183. package/dist/shared/{96qcj21c.js → w79hsckn.js} +16 -51
  184. package/dist/shared/wa07eas9.js +730 -0
  185. package/dist/shared/{k8v5v5wj.js → x933k9a3.js} +75 -34
  186. package/dist/shared/{cr74e96e.js → xhfsfkgk.js} +62 -28
  187. package/dist/shared/xjk7hnn5.js +272 -0
  188. package/dist/shared/{5enne4ma.js → xnxsed62.js} +66 -113
  189. package/dist/shared/xqve9598.js +53 -0
  190. package/dist/shared/{9x25fxhc.js → y34a8714.js} +1 -1
  191. package/dist/shared/{k7dwkhvq.js → y6jdds7g.js} +4 -1
  192. package/dist/shared/y6njgyda.js +249 -0
  193. package/dist/shared/{c9z5g0fm.js → ywr8hmey.js} +5 -2
  194. package/dist/shared/{g7ez901n.js → ywspezzx.js} +1 -1
  195. package/dist/shared/z7s6fpxv.js +62 -0
  196. package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
  197. package/dist/shared/{9m80mkac.js → ze4hxsmy.js} +1 -1
  198. package/dist/shared/zm0ptry0.js +40 -0
  199. package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
  200. package/dist/shared/zp9fmend.js +145 -0
  201. package/dist/shared/{y005b761.js → zy8r7qvz.js} +6 -2
  202. package/dist/tooling/cli.js +41 -15
  203. package/dist/tooling/migrate/apply.d.ts +14 -0
  204. package/dist/tooling/migrate/check.d.ts +3 -4
  205. package/dist/tooling/migrate/classify.d.ts +4 -0
  206. package/dist/tooling/migrate/config.d.ts +3 -2
  207. package/dist/tooling/migrate/engine.d.ts +3 -2
  208. package/dist/tooling/migrate/files.d.ts +11 -1
  209. package/dist/tooling/migrate/index.js +14 -14
  210. package/dist/tooling/migrate/lint.d.ts +1 -1
  211. package/dist/tooling/migrate/lost.d.ts +28 -0
  212. package/dist/tooling/migrate/paths.d.ts +14 -0
  213. package/dist/tooling/migrate/plan.d.ts +6 -3
  214. package/dist/tooling/migrate/runner.d.ts +25 -0
  215. package/dist/tooling/migrate/sandbox.d.ts +57 -0
  216. package/dist/tooling/migrate/sql-lex.d.ts +20 -3
  217. package/dist/tooling/migrate/text.d.ts +42 -0
  218. package/dist/tooling/node-version.d.ts +21 -0
  219. package/dist/tooling/testing/facts.d.ts +33 -5
  220. package/dist/tooling/testing/index.d.ts +1 -1
  221. package/dist/tooling/testing/index.js +3 -3
  222. package/dist/tooling/testing/isolation.d.ts +11 -5
  223. package/package.json +8 -3
  224. package/dist/shared/7m88x3e9.js +0 -45
  225. package/dist/shared/7zwwyh0v.js +0 -448
  226. package/dist/shared/aj2qxyhj.js +0 -90
  227. package/dist/shared/caw8b9d8.js +0 -204
  228. package/dist/shared/jwtxdj06.js +0 -76
  229. package/dist/shared/kfjp0gck.js +0 -212
  230. package/dist/shared/q58y17hy.js +0 -21
  231. package/dist/shared/qm7cdtvr.js +0 -912
  232. package/dist/shared/r8x5qhd7.js +0 -86
  233. package/dist/shared/zqrnhwsq.js +0 -31
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Config paths resolved against the project directory.
3
+ */
4
+ /**
5
+ * Resolves a config path against `cwd`.
6
+ *
7
+ * An absolute segment stays absolute. A relative segment, including `..`,
8
+ * is resolved from `cwd`.
9
+ *
10
+ * @param cwd - Project directory
11
+ * @param parts - `schema`, `tables`, `migrations`, `out`, a seed file, or a child
12
+ * @returns An absolute path
13
+ */
14
+ export declare function projectPath(cwd: string, ...parts: readonly string[]): string;
@@ -128,9 +128,12 @@ export declare function formatPlan(plan: MigrationPlan, lockText?: (step: PlanSt
128
128
  /**
129
129
  * Reads a plan written by {@link formatPlan}.
130
130
  *
131
- * A blank line ends a step. A blank line inside a quote, a dollar quote, or
132
- * a block comment stays in that step, and so does a `--` line while the
133
- * quote is still open.
131
+ * A blank line ends a step. A blank line inside a quote, a dollar quote, a
132
+ * block comment, or a `BEGIN ATOMIC` routine body stays in that step, and so
133
+ * does a `--` line while that quote or body is still open.
134
+ *
135
+ * `\r\n` and a lone `\r` are read as `\n`. A leading UTF-8 BOM is stripped.
136
+ * UTF-16 is refused.
134
137
  *
135
138
  * @param text - SQL file text
136
139
  * @returns The plan. The header class is kept when the file has no steps
@@ -95,7 +95,32 @@ export declare function assumeRole(connection: DriverConnection, role: string, s
95
95
  * @param schema - Schema the migration writes
96
96
  * @param role - Role that was just created
97
97
  */
98
+ /**
99
+ * Grants the application role `SELECT` on `okm_meta`.
100
+ *
101
+ * No other privilege. When the session has `SET ROLE`, the grant runs as
102
+ * the session user and the role is restored. A second apply grants the
103
+ * same privilege again.
104
+ *
105
+ * @param connection - Reserved connection
106
+ * @param role - Application role. Omitted when the config names none
107
+ * @param session - Role the runner already assumed
108
+ */
109
+ export declare function grantAppMeta(connection: DriverConnection, role: string | undefined, session: {
110
+ setRole?: string;
111
+ }): Promise<void>;
98
112
  export declare function grantSchema(connection: DriverConnection, schema: string, role: string): Promise<void>;
113
+ /**
114
+ * Fails when `GRANT USAGE ON SCHEMA` did not add the role.
115
+ *
116
+ * Postgres warns and changes nothing when the acting role does not own the
117
+ * schema. A later check then reports the grant forever. The migration role
118
+ * has to own the schema first.
119
+ *
120
+ * @param connection - Reserved connection, in the grant's transaction
121
+ * @param sql - The statement that just ran
122
+ */
123
+ export declare function assertSchemaUsageLanded(connection: DriverConnection, sql: string): Promise<void>;
99
124
  /**
100
125
  * Reports whether Postgres refuses to run `sql` inside a transaction.
101
126
  *
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Replays `okm migrate check` inside one transaction and rolls it back.
3
+ *
4
+ * The scratch schema is created in that transaction. Nothing here updates a
5
+ * system catalog or a real ACL. A step that cannot run in a transaction is
6
+ * rewritten to the transactional form, or skipped and named.
7
+ */
8
+ import type { Catalog } from "../../contracts/catalog/types.js";
9
+ import type { MigrateConfig } from "./config.js";
10
+ import { type MigrationPlan, type PlanStep } from "./plan.js";
11
+ /** One migration the check replays. */
12
+ export type CheckMigration = {
13
+ readonly id: string;
14
+ readonly catalog: Catalog;
15
+ readonly steps: readonly PlanStep[];
16
+ };
17
+ /** The first migration whose replay does not match its catalog. */
18
+ export type ReplayStop = {
19
+ readonly index: number;
20
+ readonly back: MigrationPlan;
21
+ };
22
+ /** Replay result. `skips` are statements check did not execute. */
23
+ export type ReplayOutcome = {
24
+ readonly skips: readonly string[];
25
+ readonly stop?: ReplayStop;
26
+ };
27
+ /**
28
+ * Replays `history` in one transaction and rolls it back.
29
+ *
30
+ * @param url - Target URL
31
+ * @param scratch - Schema created inside the transaction
32
+ * @param config - Roles and timeouts
33
+ * @param allowPooler - Passed through to the pooler guard
34
+ * @param history - Migrations in apply order
35
+ * @returns Skipped statements, and the first catalog mismatch
36
+ */
37
+ export declare function replayCheckHistory(url: string, scratch: string, config: MigrateConfig, allowPooler: boolean, history: readonly CheckMigration[]): Promise<ReplayOutcome>;
38
+ /**
39
+ * Compares a head snapshot with a full replay. Both run in rolled-back transactions.
40
+ *
41
+ * @param url - Target URL
42
+ * @param provided - Scratch schema for the snapshot
43
+ * @param replayed - Scratch schema for the history
44
+ * @param config - Roles and timeouts
45
+ * @param allowPooler - Passed through to the pooler guard
46
+ * @param history - Migrations in apply order
47
+ * @returns The difference, or `undefined` when the catalogs match
48
+ */
49
+ export declare function proveCheckSnapshot(url: string, provided: string, replayed: string, config: MigrateConfig, allowPooler: boolean, history: readonly CheckMigration[]): Promise<string | undefined>;
50
+ /**
51
+ * Rewrites `"public".` to the scratch schema.
52
+ *
53
+ * @param steps - Plan steps
54
+ * @param schema - Scratch schema
55
+ * @returns The same steps, aimed at `schema`
56
+ */
57
+ export declare function retargetSteps(steps: readonly PlanStep[], schema: string): readonly PlanStep[];
@@ -6,8 +6,11 @@
6
6
  * quote, and `''` is one quote inside it. `E'...'` still treats a backslash
7
7
  * as an escape. A dollar quote runs until the same tag; a different tag
8
8
  * inside it is text, so `$outer$ ... $inner$ ... $inner$ ... $outer$` stays
9
- * one span. An unterminated string, quoted identifier, block comment, or
10
- * dollar quote is one opaque tail. This function does not throw.
9
+ * one span. A `BEGIN ATOMIC` body of `CREATE FUNCTION` or `CREATE PROCEDURE`
10
+ * stays in that statement: a semicolon inside it does not split, and
11
+ * `CASE ... END` does not close the body. `BEGIN ATOMIC` elsewhere still
12
+ * splits. An unterminated string, quoted identifier, block comment, dollar
13
+ * quote, or atomic body is one opaque tail. This function does not throw.
11
14
  */
12
15
  /** Statements of `sql`, comments removed, with no trailing semicolon. */
13
16
  export declare function sqlStatements(sql: string): readonly string[];
@@ -15,8 +18,22 @@ export declare function sqlStatements(sql: string): readonly string[];
15
18
  * Whether `sql` still has an open quote or block comment.
16
19
  *
17
20
  * A line comment does not count: it ends at the newline or at the end.
21
+ * An unclosed `BEGIN ATOMIC` routine body counts too.
18
22
  *
19
23
  * @param sql - Step text accumulated so far
20
- * @returns `true` when a later blank line is still inside that quote
24
+ * @returns `true` when a later blank line is still inside that quote or body
21
25
  */
22
26
  export declare function sqlQuoteOpen(sql: string): boolean;
27
+ /**
28
+ * Transaction control in a migration step.
29
+ *
30
+ * Dollar-quoted bodies are scanned only for a `DO` block. `CREATE FUNCTION`
31
+ * and `CREATE PROCEDURE` may commit inside their own body. A `BEGIN ATOMIC`
32
+ * body stays one statement, so its `END` is not transaction control. A bare
33
+ * `BEGIN` or `END` inside a `DO` body is plpgsql and is ignored. `ROLLBACK TO`
34
+ * does not end the outer transaction.
35
+ *
36
+ * @param sql - Step text
37
+ * @returns The command, or `undefined` when the step stays in one transaction
38
+ */
39
+ export declare function transactionControl(sql: string): string | undefined;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Migration file text before it is parsed.
3
+ *
4
+ * Line endings and a UTF-8 BOM are normalized here, once, so every reader
5
+ * sees the same plan. UTF-16 is refused. The kind stays `invalid`.
6
+ */
7
+ import { OkmError } from "../../contracts/error.js";
8
+ /** Why a migration file was refused before it was applied. */
9
+ export type MigrationTextReason = "no-steps" | "utf16";
10
+ /**
11
+ * A migration file this version will not apply.
12
+ *
13
+ * `reason` is `no-steps` or `utf16`. The kind stays `invalid`.
14
+ */
15
+ export declare class MigrationTextError extends OkmError {
16
+ /** Which check refused the file. */
17
+ readonly reason: MigrationTextReason;
18
+ /**
19
+ * @param reason - Which check failed
20
+ * @param message - What the author should change
21
+ */
22
+ constructor(reason: MigrationTextReason, message: string);
23
+ }
24
+ /**
25
+ * Strips a UTF-8 BOM and turns `\r\n` and a lone `\r` into `\n`.
26
+ *
27
+ * @param text - File text
28
+ * @param label - File name used when the text is UTF-16
29
+ * @returns Text `parsePlan` can split on `\n`
30
+ */
31
+ export declare function prepareMigrationText(text: string, label?: string): string;
32
+ /**
33
+ * Refuses a non-empty file that produced no steps and has no `-- no steps` line.
34
+ *
35
+ * An intentional empty plan from `formatPlan` carries that line.
36
+ * Anything else would apply as "nothing to apply" and skip the linter.
37
+ *
38
+ * @param text - Text already passed through {@link prepareMigrationText}
39
+ * @param stepCount - Steps the parser returned
40
+ * @param label - File name in the error
41
+ */
42
+ export declare function assertMigrationSteps(text: string, stepCount: number, label: string): void;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Node version `okm` needs in order to load `okmodel.config.ts`.
3
+ *
4
+ * Node 22.18 unflags type stripping. Bun loads TypeScript itself, so the
5
+ * check does not apply when `bun --bun` is the runtime.
6
+ */
7
+ /**
8
+ * Whether `version` can strip types in a `.ts` config.
9
+ *
10
+ * @param version - `process.version`, such as `v22.18.0`
11
+ * @returns `true` for Node 22.18 and every newer major
12
+ */
13
+ export declare function nodeSupportsConfigTypes(version: string): boolean;
14
+ /**
15
+ * Startup text when this process cannot load a TypeScript config.
16
+ *
17
+ * @param version - `process.version`
18
+ * @param bunRuntime - `true` when Bun is running the process
19
+ * @returns The stderr line, or `undefined` when the process can continue
20
+ */
21
+ export declare function nodeStartupMessage(version: string, bunRuntime: boolean): string | undefined;
@@ -2,9 +2,9 @@
2
2
  * What a factory needs from a compiled schema: required columns, foreign keys,
3
3
  * and which tables are tenant or global.
4
4
  *
5
- * Column tenancy is the only strategy in this version. A table is tenant when
6
- * its predicate binds a scope, and global when `global("reason")` opted it out.
7
- * `schemaPerTenant` and `databasePerTenant` are not in 0.4.
5
+ * A table is tenant when its predicate binds a scope, and global when
6
+ * `global("reason")` opted it out. Composite and path use that probe.
7
+ * `schemaPerTenant` and `databasePerTenant` are not in this version.
8
8
  */
9
9
  import type { Catalog } from "../../contracts/catalog/types.js";
10
10
  import type { QuerySchema, RelationModel } from "../../dialects/pg/model.js";
@@ -46,6 +46,25 @@ export type TableFacts = {
46
46
  /** `global("reason")`. Absent on a tenant table and on a schema with no tenancy. */
47
47
  readonly globalReason: string | undefined;
48
48
  };
49
+ /** One view or materialized view. Isolation reads it; it does not insert into it. */
50
+ export type ViewFacts = {
51
+ /** Client name, camelCase. */
52
+ readonly name: string;
53
+ /** SQL name. */
54
+ readonly sql: string;
55
+ readonly kind: "view" | "materializedView";
56
+ /** Author SQL. */
57
+ readonly query: string;
58
+ readonly columns: readonly {
59
+ readonly field: string;
60
+ readonly dataType: string;
61
+ readonly guarded: boolean;
62
+ }[];
63
+ /** The predicate binds a scope. A global view is not tenant. */
64
+ readonly tenant: boolean;
65
+ /** `global("reason")` on the view. Absent when the view is not global. */
66
+ readonly globalReason: string | undefined;
67
+ };
49
68
  /**
50
69
  * Scope value used to ask a tenancy object whether a table is tenant.
51
70
  *
@@ -56,13 +75,22 @@ export declare const tenantProbe = "00000000-0000-4000-8000-000000000001";
56
75
  /**
57
76
  * Reads every table in declaration order.
58
77
  *
59
- * Views and materialized views are in the query model too. They have no rows
60
- * of their own to insert, so they are left out.
78
+ * Views are read by {@link readViews}. They are not tables, so they are left out here.
61
79
  *
62
80
  * @param schema - Compiled schema
63
81
  * @returns One facts object per table
64
82
  */
65
83
  export declare function readFacts(schema: TestingSchema): readonly TableFacts[];
84
+ /**
85
+ * Reads every view and materialized view in model order.
86
+ *
87
+ * A global view is not tenant. The reason comes from the view declaration,
88
+ * which is not stored on the catalog.
89
+ *
90
+ * @param schema - Compiled schema
91
+ * @returns One facts object per view
92
+ */
93
+ export declare function readViews(schema: TestingSchema): readonly ViewFacts[];
66
94
  /**
67
95
  * A column the factory must set when the definition and the overrides omit it.
68
96
  *
@@ -72,7 +72,7 @@ export type Testing<S extends TestingSchema = TestingSchema> = {
72
72
  /**
73
73
  * Runs the cross-tenant check.
74
74
  *
75
- * @returns Checked tenant tables and skipped global tables
75
+ * @returns Checked tenant tables and views, and skipped global objects
76
76
  */
77
77
  isolation(): Promise<IsolationReport>;
78
78
  /** Closes the client and the pool. */
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  testing2
3
- } from "../../shared/v36c5g6p.js";
4
- import"../../shared/8xsbagad.js";
5
- import"../../shared/8bwbwy8h.js";
3
+ } from "../../shared/7k9grvf6.js";
4
+ import"../../shared/9s0ypp87.js";
5
+ import"../../shared/qq3899ht.js";
6
6
  export {
7
7
  testing2 as testing
8
8
  };
@@ -5,15 +5,21 @@
5
5
  * writes as tenant A against that row's key. A returned row, or an update or
6
6
  * delete that touches it, is a leak. The row is deleted afterwards. Global
7
7
  * tables are skipped and listed.
8
- * Column tenancy is the strategy this version has. A table is tenant when its
9
- * predicate says so (D199).
8
+ * A table is tenant when its predicate says so (D199). Composite tenancy changes
9
+ * one key at a time. A path table is checked through a parent that belongs to
10
+ * tenant B.
11
+ * Tenant views and materialized views are read the same way. The rows are
12
+ * inserted into the underlying tables, never into the view. A global view is
13
+ * skipped and listed with its `global("reason")`.
10
14
  */
11
15
  import { type FactoryHost } from "./factories.js";
12
- /** What {@link isolation} checked, and the global tables it skipped. */
16
+ /** What {@link isolation} checked, and the global objects it skipped. */
13
17
  export type IsolationReport = {
14
18
  /** Tenant tables whose queries stayed inside tenant A. */
15
19
  readonly checked: readonly string[];
16
- /** Global tables, with the reason from `global("reason")`. */
20
+ /** Tenant views and materialized views whose reads stayed inside tenant A. */
21
+ readonly views: readonly string[];
22
+ /** Global tables and views, with the reason from `global("reason")`. */
17
23
  readonly skipped: readonly {
18
24
  readonly table: string;
19
25
  readonly reason: string;
@@ -26,6 +32,6 @@ export type IsolationReport = {
26
32
  * already inserted is not reused as tenant B's row.
27
33
  *
28
34
  * @param host - The open harness
29
- * @returns The tables that were checked and the global tables that were not
35
+ * @returns The tables and views that were checked, and the global objects that were not
30
36
  */
31
37
  export declare function isolation(host: FactoryHost): Promise<IsolationReport>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okmodel",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "okmodel is a catalog-first TypeScript ORM, PostgreSQL first.",
5
5
  "keywords": [
6
6
  "migrations",
@@ -126,6 +126,7 @@
126
126
  "compiler-api": "bun ./scripts/compiler-api.ts",
127
127
  "publint": "publint run . --strict --pack bun",
128
128
  "attw": "bun ./scripts/attw.ts",
129
+ "pack-tracked": "bun ./scripts/pack-tracked.ts",
129
130
  "prepack": "bun ./scripts/strip-workspaces.ts strip",
130
131
  "postpack": "bun ./scripts/strip-workspaces.ts restore",
131
132
  "size": "bun ./scripts/size.ts",
@@ -134,7 +135,7 @@
134
135
  "test:postgres": "bun ./scripts/postgres-suite.ts",
135
136
  "test:tarball": "bun ./scripts/tarball-smoke.ts",
136
137
  "verify": "bun ./scripts/verify.ts",
137
- "check": "bun run format:check && bun run lint && bun run typecheck && bun run editor-check && bun run type-cost && bun run layers-check && bun run core-purity && bun run okid-drift && bun run docs:check && bun run readme:check && bun run compiler-api && bun run bundle-purity && bun run build && bun test && bun run test:runtimes && bun run publint && bun run attw && bun run size",
138
+ "check": "bun run format:check && bun run lint && bun run typecheck && bun run editor-check && bun run type-cost && bun run layers-check && bun run core-purity && bun run okid-drift && bun run docs:check && bun run readme:check && bun run compiler-api && bun run bundle-purity && bun run build && bun test && bun run test:runtimes && bun run publint && bun run attw && bun run pack-tracked && bun run size",
138
139
  "bump": "bun ./scripts/bump-version.ts",
139
140
  "release-check": "bun ./scripts/release-check.ts",
140
141
  "db:up": "bun ./packages/harness/src/docker-cli.ts up",
@@ -142,6 +143,10 @@
142
143
  "bench": "bun ./packages/bench/src/run.ts",
143
144
  "catalog-bench": "bun ./scripts/catalog-bench.ts",
144
145
  "attest": "ATTEST_shouldFormat=0 ATTEST_updateSnapshots=0 bun ./packages/attest/src/measure.bench.ts",
146
+ "dev": "bun run site:dev",
147
+ "site:dev": "bun --cwd site dev",
148
+ "site:build": "bun --cwd site build",
149
+ "site:check": "bun --cwd site check",
145
150
  "publish:dry": "bun publish --dry-run",
146
151
  "prepublishOnly": "bun run build"
147
152
  },
@@ -178,6 +183,6 @@
178
183
  }
179
184
  },
180
185
  "engines": {
181
- "node": ">=22"
186
+ "node": ">=22.18"
182
187
  }
183
188
  }
@@ -1,45 +0,0 @@
1
- // src/runtime/trait-read.ts
2
- function touchFields(model) {
3
- const traits = model.traits;
4
- if (traits === undefined)
5
- return;
6
- const names = [];
7
- for (const trait of traits) {
8
- const touch = trait.touch;
9
- if (touch === undefined)
10
- continue;
11
- for (const field of touch)
12
- names.push(field);
13
- }
14
- return names.length === 0 ? undefined : names;
15
- }
16
- function fieldSealed(model, field) {
17
- const traits = model.traits;
18
- if (traits === undefined)
19
- return false;
20
- for (const trait of traits) {
21
- const sealed = trait.sealed;
22
- if (sealed === undefined)
23
- continue;
24
- for (const name of sealed)
25
- if (name === field)
26
- return true;
27
- }
28
- return false;
29
- }
30
- function sealingTrait(model, field) {
31
- const traits = model.traits;
32
- if (traits === undefined)
33
- return;
34
- for (const trait of traits) {
35
- const sealed = trait.sealed;
36
- if (sealed === undefined)
37
- continue;
38
- for (const name of sealed)
39
- if (name === field)
40
- return trait.name;
41
- }
42
- return;
43
- }
44
-
45
- export { touchFields, fieldSealed, sealingTrait };