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
@@ -15,6 +15,13 @@ export type IntrospectOptions = {
15
15
  * When omitted, roles, grants, and default privileges are not read.
16
16
  */
17
17
  readonly managedRoles?: readonly string[];
18
+ /**
19
+ * Read-only role.
20
+ *
21
+ * Schema `USAGE` is read for this role only. Other roles keep the schema
22
+ * privileges they already have.
23
+ */
24
+ readonly reportingRole?: string;
18
25
  };
19
26
  /** A connection that can run one query. Parameters are `$1`, `$2`, … */
20
27
  export type CatalogQuery = {
@@ -8,15 +8,18 @@ export type IdDefault = "uuidv7" | "uuidv4" | "none";
8
8
  /**
9
9
  * Primary key.
10
10
  *
11
- * With no options, the database default is `uuidv7()` unless
12
- * `schema({ defaults: { id } })` says otherwise. `uuidv4` stores
13
- * `gen_random_uuid()` (built in from Postgres 13). `none` takes the id on
14
- * insert. A client generator (`uuidv4`, `uuidv7`, or `okid(...)` from
15
- * `okmodel/ids`) is filled on insert and stored with no database default.
16
- * OKID is `text` with collation `C`. A database default is omitted from
17
- * insert and update. `none` is required on insert and omitted from update.
11
+ * With no options, the database default is `gen_random_uuid()` unless
12
+ * `schema({ defaults: { id } })` says otherwise. That function is built in
13
+ * from Postgres 13, so a bare call works on every supported major. `uuidv7`
14
+ * stores `uuidv7()` and needs Postgres 18 (`minPostgres: 18`). Pick it for a large write-heavy
15
+ * table: the ids are time-ordered and the index stays local. Random ids are
16
+ * fine elsewhere. `none` takes the id on insert. A client generator
17
+ * (`uuidv4`, `uuidv7`, or `okid(...)` from `okmodel/ids`) is filled on insert
18
+ * and stored with no database default. OKID is `text` with collation `C`. A
19
+ * database default is omitted from insert and update. `none` is required on
20
+ * insert and omitted from update.
18
21
  *
19
- * @param options - Which default to store. Omitted means the schema default, or `uuidv7()`
22
+ * @param options - Which default to store. Omitted means the schema default, or `gen_random_uuid()`
20
23
  * @returns An id column
21
24
  */
22
25
  export declare function id(): ColumnBuilder<string, IdFlags>;
@@ -21,8 +21,13 @@ export type ColumnModel = {
21
21
  * call a codec it does not need.
22
22
  */
23
23
  readonly decode: ((wire: string) => unknown) | undefined;
24
- /** Excluded from a default select. Named selects still return it. Includes never return it. */
25
- readonly hidden: boolean;
24
+ /**
25
+ * Excluded from a default select. Named selects still return it. Includes never return it.
26
+ *
27
+ * `"filter"` is still excluded, and `where` and `orderBy` may name it.
28
+ * `true` is excluded and refused there (OKM1120).
29
+ */
30
+ readonly hidden: boolean | "filter";
26
31
  /**
27
32
  * Redacted in logs, errors, and `inspect()`.
28
33
  *
@@ -58,6 +63,39 @@ export type ColumnModel = {
58
63
  */
59
64
  readonly accepts?: readonly string[] | undefined;
60
65
  };
66
+ /**
67
+ * One table a morph include can return.
68
+ *
69
+ * `type` is the table's TypeScript name, which is what the type column stores.
70
+ */
71
+ export type MorphTarget = {
72
+ readonly type: string;
73
+ readonly table: string;
74
+ /** SQL name of the target table. */
75
+ readonly sql: string;
76
+ /** SQL name of the target's single primary-key column. */
77
+ readonly keySql: string;
78
+ };
79
+ /**
80
+ * A polymorphic pair: a type column and an id column.
81
+ *
82
+ * `to` is the owner side (one of several tables). `many` is the reverse on a target.
83
+ * Absent on every other relation, so a normal relation does not carry it.
84
+ */
85
+ export type MorphModel = {
86
+ readonly direction: "to" | "many";
87
+ /** Column stem. The fields are `${name}Type` and `${name}Id`. */
88
+ readonly name: string;
89
+ readonly typeField: string;
90
+ readonly idField: string;
91
+ /** SQL name of the type column. */
92
+ readonly typeSql: string;
93
+ /** SQL name of the id column. */
94
+ readonly idSql: string;
95
+ /** On a reverse many, the table name stored in the type column. */
96
+ readonly typeValue?: string;
97
+ readonly targets: readonly MorphTarget[];
98
+ };
61
99
  /**
62
100
  * A resolved relation.
63
101
  *
@@ -72,6 +110,13 @@ export type RelationModel = {
72
110
  readonly local: readonly string[];
73
111
  /** SQL names on the related table. */
74
112
  readonly remote: readonly string[];
113
+ /**
114
+ * Set on a morph relation.
115
+ *
116
+ * The include planner reads `to`. A reverse many reads `many` and emits
117
+ * through {@link RelationModel.through}.
118
+ */
119
+ readonly morph?: MorphModel;
75
120
  /**
76
121
  * Set on a `manyThrough` relation.
77
122
  *
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Resolver and emitters of a `morph` relation.
3
+ *
4
+ * The relation object carries both. `schema()` calls the resolver, and the
5
+ * planner calls the emitter with its own helpers, so a schema that never
6
+ * calls `morph` or `morphMany` does not ship this module. A target in another
7
+ * tenant or archived never shows: the include planner applies those predicates
8
+ * to each target, the same way it does for any relation.
9
+ */
10
+ import type { RelationModel } from "./model.js";
11
+ import type { RelationScope } from "./relations.js";
12
+ /**
13
+ * Resolves `morph(name, targets)` on the table that holds the type and id columns.
14
+ *
15
+ * @param scope - What `schema()` knows
16
+ * @param name - Column stem: `${name}Type` and `${name}Id`
17
+ * @param targets - Closed list of target table names
18
+ * @returns The resolved to-one relation
19
+ */
20
+ export declare function resolveMorph(scope: RelationScope, name: string, targets: readonly string[]): RelationModel;
21
+ /**
22
+ * Resolves `morphMany(table, name)` on a target table.
23
+ *
24
+ * The many reads the owner table's type and id columns. The owner must declare
25
+ * `morph(name, targets)` and list this table.
26
+ *
27
+ * @param scope - What `schema()` knows. `owner` is the target table
28
+ * @param table - Table that holds the type and id columns
29
+ * @param name - Column stem declared on that table
30
+ * @returns The resolved to-many relation
31
+ */
32
+ export declare function resolveMorphMany(scope: RelationScope, table: string, name: string): RelationModel;
33
+ /**
34
+ * Refuses `morphTo` when the name, type, or id is missing.
35
+ *
36
+ * `null` used to throw a TypeError on `.length`. An empty name or type stays
37
+ * OKM1020. A null or non-string id, or a null type, is OKM1120.
38
+ *
39
+ * @param name - Column stem
40
+ * @param type - Target table name
41
+ * @param id - That table's primary key
42
+ */
43
+ export declare function assertMorphTo(name: unknown, type: unknown, id: unknown): void;
@@ -58,9 +58,9 @@ export declare function assertNoControl(value: string, role: string): void;
58
58
  */
59
59
  export declare function assertBoundText(value: string, role: string): void;
60
60
  /**
61
- * Rejects a regconfig name that is not an identifier.
61
+ * Rejects a text search language that is not an identifier.
62
62
  *
63
- * @param config - Text search configuration
63
+ * @param config - Language name, such as `english`
64
64
  */
65
65
  export declare function assertRegconfig(config: string): void;
66
66
  /**
@@ -7,7 +7,7 @@
7
7
  declare const brand: unique symbol;
8
8
  declare const RUNTIME: unique symbol;
9
9
  /** Operator names the read path compiles. */
10
- export type OperatorName = "eq" | "lt" | "lte" | "gt" | "gte" | "between" | "startsWith" | "contains" | "endsWith" | "like" | "ilike" | "inList" | "notIn" | "not" | "or" | "and" | "has" | "none" | "every" | "inc" | "containedBy" | "overlaps" | "hasKey" | "hasAnyKey" | "path" | "matches" | "similar" | "wordSimilar" | "json.set" | "arr.append" | "arr.remove";
10
+ export type OperatorName = "eq" | "lt" | "lte" | "gt" | "gte" | "between" | "startsWith" | "contains" | "endsWith" | "like" | "ilike" | "inList" | "notIn" | "not" | "or" | "and" | "has" | "none" | "every" | "inc" | "containedBy" | "overlaps" | "hasKey" | "hasAnyKey" | "path" | "matches" | "relevance" | "similar" | "wordSimilar" | "json.set" | "arr.append" | "arr.remove";
11
11
  /** A tagged operator. `value` is the operand the helper stored. */
12
12
  export type Tagged<Name extends OperatorName, V> = {
13
13
  readonly [brand]: Name;
@@ -38,16 +38,23 @@ export type PathValue<V> = {
38
38
  };
39
39
  /** `col #>> segments` compared with `op`. */
40
40
  export type Path<V extends string | number | boolean> = Tagged<"path", PathValue<V>>;
41
- /** How `matches` turns query text into a tsquery. */
42
- export type MatchMode = "websearch" | "plain" | "phrase";
43
- /** Full-text query. `config` is a regconfig name when set. */
41
+ /**
42
+ * How search text is matched.
43
+ *
44
+ * `natural` is web-search style. `all-words` requires every word. `phrase`
45
+ * keeps the words in order. `advanced` is PostgreSQL query syntax.
46
+ */
47
+ export type SearchMatch = "natural" | "all-words" | "phrase" | "advanced";
48
+ /** Text to look for, how to match it, and the text search language when one was passed. */
44
49
  export type MatchValue = {
45
50
  readonly query: string;
46
- readonly mode: MatchMode;
47
- readonly config: string | undefined;
51
+ readonly match: SearchMatch;
52
+ readonly language: string | undefined;
48
53
  };
49
- /** `@@` against a tsvector column. */
54
+ /** `@@` against a search column. */
50
55
  export type Matches = Tagged<"matches", MatchValue>;
56
+ /** Order by how well a search column matches. Most relevant first. */
57
+ export type Relevance = Tagged<"relevance", MatchValue>;
51
58
  /** Text stored on a `pg_trgm` operator. `schema` is the extension's install schema. */
52
59
  export type TrigramQuery = {
53
60
  readonly query: string;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Time bucket for `aggregate` `groupBy` (spec §10, §13 tool 4).
3
+ *
4
+ * The brand is a symbol. JSON cannot create one, so a request cannot add a
5
+ * bucket. A plain object in `groupBy` stays OKM1120. The SQL loads with the
6
+ * first `aggregate()` whose `groupBy` contains a bucket.
7
+ */
8
+ declare const brand: unique symbol;
9
+ /** Calendar and clock units `bucket` accepts. */
10
+ export type BucketUnit = "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year";
11
+ /** Week that starts on Monday (ISO), Sunday, or Saturday. */
12
+ export type WeekStart = "monday" | "sunday" | "saturday";
13
+ /**
14
+ * A `bucket()` call.
15
+ *
16
+ * `C` is the column, `U` the unit, and `A` the result key.
17
+ */
18
+ export type Bucket<C extends string, U extends string, A extends string> = {
19
+ readonly [brand]: C;
20
+ readonly unit: U;
21
+ readonly as: A;
22
+ };
23
+ /** What {@link bucket} stores. The aggregate chunk reads this. */
24
+ export type BucketInput = {
25
+ readonly column: unknown;
26
+ readonly unit: unknown;
27
+ readonly as: unknown;
28
+ readonly tz: unknown;
29
+ readonly weekStart: unknown;
30
+ };
31
+ /**
32
+ * Groups a timestamp or date column by a calendar or clock unit.
33
+ *
34
+ * `tz` is required for `timestamptz` and refused for `date`. `timestamp`
35
+ * without a zone is refused. `as` is the result key. `__proto__`, `constructor`,
36
+ * `toString`, and `hasOwnProperty` are refused when the aggregate runs.
37
+ * `weekStart` applies only
38
+ * to `week` and defaults to Monday. A NULL timestamp is its own group: the
39
+ * `as` key is present and the value is null.
40
+ *
41
+ * Day, week, month, quarter, and year come back as `Temporal.PlainDate` (the
42
+ * local date the period starts). Second, minute, and hour come back as
43
+ * `Temporal.Instant` (the period start).
44
+ *
45
+ * @typeParam C - Column name
46
+ * @typeParam U - Unit
47
+ * @typeParam A - Result key
48
+ * @param column - Field to bucket
49
+ * @param unit - Period
50
+ * @param options - Zone, result key, and week start
51
+ * @returns A tagged bucket. Pass it in `groupBy`
52
+ */
53
+ export declare function bucket<const C extends string, const U extends BucketUnit, const A extends string>(column: C, unit: U, options: {
54
+ readonly tz?: string;
55
+ readonly as: A;
56
+ readonly weekStart?: WeekStart;
57
+ }): Bucket<C, U, A>;
58
+ /**
59
+ * Reports whether `value` is a {@link bucket} call.
60
+ *
61
+ * @param value - One `groupBy` entry
62
+ * @returns `true` when {@link bucket} created it
63
+ */
64
+ export declare function isBucket(value: unknown): value is BucketInput;
65
+ export {};
@@ -2,9 +2,9 @@ import { type Tagged } from "../operators.js";
2
2
  /** Adds to the stored number. `undefined` in `set` still leaves the field unchanged. */
3
3
  export type Inc<V> = Tagged<"inc", V>;
4
4
  /**
5
- * Atomic increment used in `update` `set` (spec §11).
5
+ * Adds to a stored number in `update` `set` (spec §11).
6
6
  *
7
- * JSON and array operators are not this helper.
7
+ * A null number stays null. JSON and array operators are not this helper.
8
8
  *
9
9
  * @typeParam V - Amount
10
10
  * @param value - Amount to add
@@ -1,16 +1,13 @@
1
- import { type MatchMode, type Matches } from "../operators.js";
1
+ import { type Matches } from "../operators.js";
2
+ import { type SearchOptions } from "./search-query.js";
2
3
  /**
3
- * Full-text match (`@@`) for a tsvector column.
4
+ * Full-text match for a search column.
4
5
  *
5
- * The default mode is `websearch_to_tsquery`, which does not throw on user
6
- * input. `"plain"` uses `plainto_tsquery` and `"phrase"` uses `phraseto_tsquery`.
7
- * A text column is not searched here.
6
+ * The default match is natural, which does not throw on user input. A plain
7
+ * text column is not searched here. `relevance` orders by the same match.
8
8
  *
9
- * @param query - Search text
10
- * @param options - Mode and regconfig name
11
- * @returns A tagged operator
9
+ * @param query - Text to look for
10
+ * @param options - How to match, and the text search language
11
+ * @returns A tagged operator for `where`
12
12
  */
13
- export declare function matches(query: string, options?: {
14
- readonly mode?: MatchMode;
15
- readonly config?: string;
16
- }): Matches;
13
+ export declare function matches(query: string, options?: SearchOptions): Matches;
@@ -0,0 +1,13 @@
1
+ import { type Relevance } from "../operators.js";
2
+ import { type SearchOptions } from "./search-query.js";
3
+ /**
4
+ * Orders a search column by how well it matches.
5
+ *
6
+ * Most relevant first. Pass it as an `orderBy` value. `find({ search })`
7
+ * compiles to `matches` plus this, so the SQL is the same.
8
+ *
9
+ * @param query - Text to look for
10
+ * @param options - How to match, and the text search language. Same words as `matches`
11
+ * @returns A tagged order
12
+ */
13
+ export declare function relevance(query: string, options?: SearchOptions): Relevance;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared operand for `matches` and `relevance`.
3
+ *
4
+ * Both helpers store this shape. The SQL compiler reads it once, so `search`
5
+ * and the two helpers emit the same text.
6
+ */
7
+ import type { MatchValue, SearchMatch } from "../operators.js";
8
+ /** Options `matches` and `relevance` take. */
9
+ export type SearchOptions = {
10
+ /** How to match. Omitted means `natural`. */
11
+ readonly match?: SearchMatch;
12
+ /** Text search language, such as `english`. Omitted uses the database default. */
13
+ readonly language?: string;
14
+ };
15
+ /**
16
+ * Stores the text, the match, and the language.
17
+ *
18
+ * @param query - Text to look for
19
+ * @param options - Match and language. Omitted means natural, database language
20
+ * @returns The operand both helpers tag
21
+ */
22
+ export declare function searchValue(query: string, options?: SearchOptions): MatchValue;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Window helpers for `select` (spec §10, §13 tool 12).
3
+ *
4
+ * The brand is a symbol. JSON cannot create one, so a request cannot add a
5
+ * window. A plain object in `select` stays OKM1120. The SQL loads on the first
6
+ * `find` or `one` whose `select` contains one.
7
+ */
8
+ declare const brand: unique symbol;
9
+ /** `asc` is nulls last and `desc` is nulls first unless `nulls` is set. */
10
+ type SortDir = "asc" | "desc" | {
11
+ readonly dir: "asc" | "desc";
12
+ readonly nulls?: "first" | "last";
13
+ };
14
+ /** Columns the window orders by. Names are checked when the call runs. */
15
+ export type WindowOrder = {
16
+ readonly [field: string]: SortDir | undefined;
17
+ };
18
+ /** What a window helper stores. The planner reads this. */
19
+ export type WindowCall = {
20
+ readonly label: "rowNumber" | "rank" | "denseRank" | "runningTotal";
21
+ readonly fn: "row_number" | "rank" | "dense_rank" | "sum";
22
+ readonly column: string | undefined;
23
+ readonly partitionBy: readonly string[] | undefined;
24
+ readonly orderBy: unknown;
25
+ readonly as: string;
26
+ };
27
+ /**
28
+ * A window helper.
29
+ *
30
+ * `A` is the result key. `V` is `number` for a rank, or the source column for
31
+ * a running total.
32
+ */
33
+ export type Window<A extends string, V extends string | number> = {
34
+ readonly [brand]: V;
35
+ readonly as: A;
36
+ };
37
+ /**
38
+ * Options every window helper takes.
39
+ *
40
+ * `partitionBy` is the group. Omit it to number the whole result. `orderBy`
41
+ * is the order inside that group. The primary key breaks ties. `as` is the
42
+ * result key. `__proto__`, `constructor`, `toString`, and `hasOwnProperty`
43
+ * are refused when the call runs.
44
+ */
45
+ type WindowOptions<A extends string> = {
46
+ readonly partitionBy?: readonly string[];
47
+ readonly orderBy: WindowOrder;
48
+ readonly as: A;
49
+ };
50
+ /**
51
+ * Reports whether `value` is a window helper.
52
+ *
53
+ * @param value - One `select` entry
54
+ * @returns `true` when a helper in this module created it
55
+ */
56
+ export declare function isWindow(value: unknown): value is WindowCall;
57
+ /**
58
+ * Row number inside a group, starting at 1.
59
+ *
60
+ * Ties get distinct numbers. The primary key breaks them.
61
+ *
62
+ * @typeParam A - Result key
63
+ * @param options - Group, order, and result key
64
+ * @returns A tagged window. Pass it in `select` on `find` or `one`
65
+ */
66
+ export declare function rowNumber<const A extends string>(options: WindowOptions<A>): Window<A, number>;
67
+ /**
68
+ * Rank inside a group, with gaps after a tie.
69
+ *
70
+ * Two rows with the same order share a rank. The next rank skips. The primary
71
+ * key breaks the order when you need a stable row, and it does not split the
72
+ * rank.
73
+ *
74
+ * @typeParam A - Result key
75
+ * @param options - Group, order, and result key
76
+ * @returns A tagged window. Pass it in `select` on `find` or `one`
77
+ */
78
+ export declare function rank<const A extends string>(options: WindowOptions<A>): Window<A, number>;
79
+ /**
80
+ * Rank inside a group, without gaps after a tie.
81
+ *
82
+ * Two rows with the same order share a rank. The next rank is the next number.
83
+ *
84
+ * @typeParam A - Result key
85
+ * @param options - Group, order, and result key
86
+ * @returns A tagged window. Pass it in `select` on `find` or `one`
87
+ */
88
+ export declare function denseRank<const A extends string>(options: WindowOptions<A>): Window<A, number>;
89
+ /**
90
+ * Running total of a number column.
91
+ *
92
+ * The total follows `orderBy` inside the group. A null number does not add.
93
+ * The result uses the column's value type: a number, or the exact decimal
94
+ * string of a `numeric` column.
95
+ *
96
+ * @typeParam C - Column
97
+ * @typeParam A - Result key
98
+ * @param column - Field to total
99
+ * @param options - Group, order, and result key
100
+ * @returns A tagged window. Pass it in `select` on `find` or `one`
101
+ */
102
+ export declare function runningTotal<const C extends string, const A extends string>(column: C, options: WindowOptions<A>): Window<A, C>;
103
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Table ownership marks (`external` and `ignored`).
3
+ *
4
+ * The mark lives on the table value, not in `table()` options. `schema()` does
5
+ * not read it, so a featureless app does not load this module. Tooling stamps
6
+ * the catalog before it plans.
7
+ */
8
+ import type { Catalog, Owner } from "../../contracts/catalog/types.js";
9
+ import type { AnyTable } from "./table.js";
10
+ /** Owners a declaration may set. `managed` stays the default. */
11
+ export type DeclaredOwner = Exclude<Owner, "managed">;
12
+ /**
13
+ * Marks a table `external` or `ignored`.
14
+ *
15
+ * `external` is known and queryable, and a plan never creates, alters, or
16
+ * drops it. `ignored` is invisible to diffs, plans, and `okm check`. The
17
+ * table stays on the schema, so the client can still name it.
18
+ *
19
+ * @param table - A `table()` value
20
+ * @param owner - `external` or `ignored`
21
+ * @returns The same table
22
+ */
23
+ export declare function withOwner<T extends AnyTable>(table: T, owner: DeclaredOwner): T;
24
+ /**
25
+ * Reads the mark {@link withOwner} stored.
26
+ *
27
+ * @param table - A table value
28
+ * @returns The mark, or `undefined` when the table is managed
29
+ */
30
+ export declare function tableOwner(table: object): DeclaredOwner | undefined;
31
+ /**
32
+ * Copies `owner` onto a table and the objects that belong to it.
33
+ *
34
+ * Columns, indexes, constraints, triggers, policies, and sequences that
35
+ * depend on the table follow the table. A catalog with no marks is returned
36
+ * as itself.
37
+ *
38
+ * @param source - Catalog from `schema()`
39
+ * @param marks - SQL table name to owner
40
+ * @returns The catalog planning and drift should read
41
+ */
42
+ export declare function stampOwnership(source: Catalog, marks: ReadonlyMap<string, DeclaredOwner>): Catalog;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Marks the table a path ends on.
3
+ *
4
+ * The symbol lives here so a column-only app and a featureless app do not
5
+ * load it. `archivable()` reads it. Compile hashes named fields, so the mark
6
+ * stays out of the catalog.
7
+ */
8
+ /**
9
+ * Property set on the tenant table a path ends on.
10
+ *
11
+ * An options spread does not copy it. The rewrite sets it on the table object.
12
+ */
13
+ export declare const pathEndpoint: unique symbol;
14
+ /**
15
+ * Records that `table` is the end of a path.
16
+ *
17
+ * @param table - The rewritten tenant table
18
+ * @returns The same table, marked
19
+ */
20
+ export declare function markPathEndpoint<T extends object>(table: T): T;
@@ -44,7 +44,7 @@ export type Preset<Row> = (q: PresetQuery<Row>, ...args: never[]) => PresetQuery
44
44
  * The first group are client methods. The second is reserved for later
45
45
  * releases. `then` would make a table handle look like a promise.
46
46
  */
47
- export type ReservedPreset = "find" | "one" | "page" | "aggregate" | "count" | "exists" | "insert" | "update" | "delete" | "archive" | "restore" | "withArchived" | "onlyArchived" | "then" | "lock" | "watch" | "subscribe" | "stream" | "inspect" | "explain" | "with" | "for" | "as";
47
+ export type ReservedPreset = "find" | "one" | "page" | "aggregate" | "count" | "exists" | "insert" | "update" | "delete" | "descendants" | "ancestors" | "sync" | "archive" | "restore" | "withArchived" | "onlyArchived" | "then" | "lock" | "watch" | "subscribe" | "stream" | "inspect" | "explain" | "with" | "for" | "as";
48
48
  /**
49
49
  * The `presets` option. A reserved name is a type error here, and OKM1040 when
50
50
  * the schema is used.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * `one`, `many`, and `manyThrough` relations.
2
+ * `one`, `many`, `manyThrough`, and `morph` relations.
3
3
  *
4
4
  * They name a table. `schema()` resolves the foreign key. An ambiguous key
5
- * is OKM1021. `manyThrough` names the join table as well and carries its own
6
- * resolver, so a schema without one does not pay for it. `morph` stays reserved.
5
+ * is OKM1021. `manyThrough` and `morph` carry their own resolvers, so a schema
6
+ * that never calls one does not pay for it.
7
7
  */
8
8
  import type { RelationModel } from "./model.js";
9
9
  /** A to-one relation. `field` is the local foreign key when the table has several. */
@@ -28,6 +28,26 @@ export type RelationEdge = {
28
28
  /** Referenced SQL names, in the same order. */
29
29
  readonly remote: readonly string[];
30
30
  };
31
+ /** A table as a morph resolver reads it. Foreign-key resolvers ignore this. */
32
+ export type RelationDescribed = {
33
+ readonly tsName: string;
34
+ readonly sqlName: string;
35
+ /** Primary-key SQL names, in catalog order. */
36
+ readonly primary: readonly string[];
37
+ readonly byField: ReadonlyMap<string, {
38
+ readonly field: string;
39
+ readonly sqlName: string;
40
+ readonly dataType: string;
41
+ readonly nullable: boolean;
42
+ }>;
43
+ readonly bySql: ReadonlyMap<string, {
44
+ readonly field: string;
45
+ readonly sqlName: string;
46
+ readonly dataType: string;
47
+ }>;
48
+ /** Relation calls stored on the table, before they are resolved. */
49
+ readonly relationOptions: unknown;
50
+ };
31
51
  /** What a relation's own resolver reads from `schema()`. */
32
52
  export type RelationScope = {
33
53
  /** The table that declares the relation. */
@@ -37,6 +57,19 @@ export type RelationScope = {
37
57
  readonly edges: readonly RelationEdge[];
38
58
  /** Every table name in the schema, sorted. */
39
59
  readonly tables: readonly string[];
60
+ /**
61
+ * Looks up a table's columns.
62
+ *
63
+ * Present when `schema()` resolves relations. A resolver that only needs
64
+ * foreign keys ignores it. The value is the prepared table; morph narrows it.
65
+ */
66
+ readonly describe?: (table: string) => unknown;
67
+ /**
68
+ * Tenant fields tenancy added to a primary key.
69
+ *
70
+ * A morph id matches the key that remains. Absent when the schema has no tenancy.
71
+ */
72
+ readonly scopeFields?: readonly string[];
40
73
  };
41
74
  /**
42
75
  * A to-many relation through a join table.
@@ -100,3 +133,67 @@ export declare function isRelationCall(value: unknown): value is RelationCall;
100
133
  export declare function manyThrough<const TTable extends string>(table: TTable, options: {
101
134
  readonly through: string;
102
135
  } & ThroughKeys): ManyThroughRelation<TTable>;
136
+ /**
137
+ * A polymorphic to-one relation.
138
+ *
139
+ * `name` is the column stem: the table declares `${name}Type` and `${name}Id`.
140
+ * The type column stores a target table name. The id column stores that
141
+ * table's primary key. Include returns one row of the matching target, or
142
+ * null, as a flat union discriminated by the type field.
143
+ *
144
+ * @typeParam TName - Column stem
145
+ * @typeParam TTargets - Closed list of target tables
146
+ * @param name - Column stem
147
+ * @param targets - Target table names, each with one primary-key column
148
+ * @returns The relation `schema()` resolves
149
+ */
150
+ export declare function morph<const TName extends string, const TTargets extends readonly [string, ...string[]]>(name: TName, targets: TTargets): MorphRelation<TName, TTargets>;
151
+ /**
152
+ * The reverse of {@link morph}: many owner rows that point at this table.
153
+ *
154
+ * Declare it on each target. `table` is the table that holds the type and id
155
+ * columns, and `name` is the stem passed to `morph`.
156
+ *
157
+ * @typeParam TTable - Table that holds the type and id columns
158
+ * @param table - That table
159
+ * @param name - Column stem
160
+ * @returns The relation `schema()` resolves
161
+ */
162
+ export declare function morphMany<const TTable extends string>(table: TTable, name: string): MorphManyRelation<TTable>;
163
+ /**
164
+ * A polymorphic relation declared with {@link morph}.
165
+ *
166
+ * It is a {@link OneRelation} so the relation map stays assignable. `morph`
167
+ * is what include reads to build the union.
168
+ */
169
+ export type MorphRelation<TName extends string = string, TTargets extends readonly string[] = readonly string[]> = OneRelation<TTargets[number]> & {
170
+ readonly morph: {
171
+ readonly name: TName;
172
+ readonly targets: TTargets;
173
+ readonly typeField: `${TName}Type`;
174
+ };
175
+ readonly resolve: (scope: RelationScope) => RelationModel;
176
+ };
177
+ /**
178
+ * The reverse many declared with {@link morphMany}.
179
+ *
180
+ * It is a {@link ManyRelation}, so include, `has`, `none`, and `every` read it as one.
181
+ */
182
+ export type MorphManyRelation<TTable extends string = string> = ManyRelation<TTable> & {
183
+ readonly resolve: (scope: RelationScope) => RelationModel;
184
+ };
185
+ /**
186
+ * Sets a morph's type and id columns together.
187
+ *
188
+ * @typeParam TName - Column stem
189
+ * @typeParam TType - Target table name
190
+ * @param name - Column stem passed to `morph`
191
+ * @param type - Target table name
192
+ * @param id - That table's primary key
193
+ * @returns The two fields an insert or update spreads in
194
+ */
195
+ export declare function morphTo<const TName extends string, const TType extends string>(name: TName, type: TType, id: string): {
196
+ readonly [K in `${TName}Type`]: TType;
197
+ } & {
198
+ readonly [K in `${TName}Id`]: string;
199
+ };