okmodel 0.6.0 → 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 (157) hide show
  1. package/README.md +100 -1131
  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 +11 -8
  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 +27 -11
  14. package/dist/adapters/pg/reserved.d.ts +42 -0
  15. package/dist/adapters/pg/session.d.ts +0 -18
  16. package/dist/contracts/connection.d.ts +7 -6
  17. package/dist/dialects/pg/floor.d.ts +68 -0
  18. package/dist/dialects/pg/index.d.ts +6 -1
  19. package/dist/dialects/pg/index.js +49 -159
  20. package/dist/dialects/pg/keys.d.ts +11 -8
  21. package/dist/dialects/pg/model.d.ts +40 -0
  22. package/dist/dialects/pg/morph.d.ts +43 -0
  23. package/dist/dialects/pg/operator-fit.d.ts +2 -2
  24. package/dist/dialects/pg/operators.d.ts +14 -7
  25. package/dist/dialects/pg/ops/bucket.d.ts +65 -0
  26. package/dist/dialects/pg/ops/inc.d.ts +2 -2
  27. package/dist/dialects/pg/ops/matches.d.ts +9 -12
  28. package/dist/dialects/pg/ops/relevance.d.ts +13 -0
  29. package/dist/dialects/pg/ops/search-query.d.ts +22 -0
  30. package/dist/dialects/pg/ops/window.d.ts +103 -0
  31. package/dist/dialects/pg/preset.d.ts +1 -1
  32. package/dist/dialects/pg/relations.d.ts +100 -3
  33. package/dist/dialects/pg/schema.d.ts +31 -3
  34. package/dist/dialects/pg/view/index.js +1 -1
  35. package/dist/runtime/aggregate.d.ts +8 -2
  36. package/dist/runtime/bucket-group.d.ts +70 -0
  37. package/dist/runtime/conflict.d.ts +22 -4
  38. package/dist/runtime/include.d.ts +0 -8
  39. package/dist/runtime/inflight.d.ts +1 -1
  40. package/dist/runtime/page.d.ts +4 -1
  41. package/dist/runtime/pg/bun.js +12 -6
  42. package/dist/runtime/pg/pg.js +5 -5
  43. package/dist/runtime/pg/pglite.d.ts +1 -0
  44. package/dist/runtime/pg/pglite.js +9 -9
  45. package/dist/runtime/pg/postgresjs.js +5 -5
  46. package/dist/runtime/plan.d.ts +95 -5
  47. package/dist/runtime/read-stream.d.ts +13 -16
  48. package/dist/runtime/result-name.d.ts +17 -0
  49. package/dist/runtime/server-check.d.ts +3 -3
  50. package/dist/runtime/sort-bind.d.ts +21 -0
  51. package/dist/runtime/sort.d.ts +56 -0
  52. package/dist/runtime/sync.d.ts +70 -0
  53. package/dist/runtime/tenancy/index.js +7 -5
  54. package/dist/runtime/text-search.d.ts +20 -0
  55. package/dist/runtime/traits/index.d.ts +80 -0
  56. package/dist/runtime/traits/index.js +175 -11
  57. package/dist/runtime/tree.d.ts +38 -0
  58. package/dist/runtime/types.d.ts +218 -22
  59. package/dist/runtime/validate/index.js +2 -2
  60. package/dist/runtime/version.d.ts +39 -0
  61. package/dist/runtime/window.d.ts +21 -0
  62. package/dist/runtime/write.d.ts +54 -2
  63. package/dist/shared/{wkme6tep.js → 14vx95q4.js} +8 -16
  64. package/dist/shared/1est4ezg.js +313 -0
  65. package/dist/shared/{4az561fn.js → 1qa0qajz.js} +8 -23
  66. package/dist/shared/{2cg3wnxc.js → 1w508jbr.js} +593 -130
  67. package/dist/shared/2c13q96h.js +18 -0
  68. package/dist/shared/{b4v57v3x.js → 2d3xq4ps.js} +2 -2
  69. package/dist/shared/{1nw1f3vs.js → 2shdbn8q.js} +7 -7
  70. package/dist/shared/3v7t1yrv.js +208 -0
  71. package/dist/shared/{x3jc53kg.js → 5e3tf63j.js} +2 -2
  72. package/dist/shared/5fe3kbsh.js +10 -0
  73. package/dist/shared/5v3xf80k.js +37 -0
  74. package/dist/shared/{c58secgj.js → 63qtkrca.js} +38 -4
  75. package/dist/shared/{2z7wv5tj.js → 67txcrcw.js} +55 -34
  76. package/dist/shared/79dt02vc.js +12 -0
  77. package/dist/shared/{8x72s86k.js → 7k9grvf6.js} +10 -4
  78. package/dist/shared/7kms6fvj.js +20 -0
  79. package/dist/shared/7mnme5tn.js +8 -0
  80. package/dist/shared/7n7ddwt4.js +6 -0
  81. package/dist/shared/{5j36z8dn.js → 81ebdx9p.js} +39 -70
  82. package/dist/shared/{knmes2kh.js → 8skf0cam.js} +1 -1
  83. package/dist/shared/9a4ae4p8.js +31 -0
  84. package/dist/shared/9y3mmmh1.js +436 -0
  85. package/dist/shared/ab9gmbwy.js +213 -0
  86. package/dist/shared/{f0f1n281.js → ax7qv55k.js} +2 -2
  87. package/dist/shared/{g90m9b0g.js → aytqh5y2.js} +6 -5
  88. package/dist/shared/{vjpnzwjz.js → b5pftnn2.js} +1 -1
  89. package/dist/shared/{ag4c7516.js → b76b8d95.js} +2 -2
  90. package/dist/shared/{vmfkhszw.js → bg3rym3g.js} +33 -26
  91. package/dist/shared/{mb2ycs1p.js → bm22fvzr.js} +15 -15
  92. package/dist/shared/{q3j1tq7a.js → bz84tkzm.js} +148 -23
  93. package/dist/shared/{31vm914h.js → cm3w0ywp.js} +15 -16
  94. package/dist/shared/cn957f8d.js +179 -0
  95. package/dist/shared/{gwn6v667.js → cnkky55j.js} +25 -14
  96. package/dist/shared/{ys0xzyaj.js → dkxgzaqd.js} +224 -19
  97. package/dist/shared/dzj09cye.js +10 -0
  98. package/dist/shared/exn3sd90.js +359 -0
  99. package/dist/shared/g6evj1j3.js +66 -0
  100. package/dist/shared/ga9j92qj.js +25 -0
  101. package/dist/shared/{t3g0k88x.js → gs74dbj5.js} +16 -12
  102. package/dist/shared/gzaveazc.js +285 -0
  103. package/dist/shared/{2jd1sn0e.js → hyh73qk6.js} +1 -1
  104. package/dist/shared/{r1fdd0f6.js → je4axnm8.js} +5 -2
  105. package/dist/shared/{1f0xa3cb.js → jvd0mqag.js} +3 -3
  106. package/dist/shared/jznfax0y.js +155 -0
  107. package/dist/shared/{cgbamx3e.js → kb2sdhfb.js} +7 -4
  108. package/dist/shared/{wt5rzv1h.js → kr0jzbw2.js} +5 -5
  109. package/dist/shared/{p6bjzq9q.js → ktz42yez.js} +12 -4
  110. package/dist/shared/{p248q79y.js → m6p12kbr.js} +2 -2
  111. package/dist/shared/{r6nwkxnt.js → m7n9h2a5.js} +4 -4
  112. package/dist/shared/{672t5vym.js → mss6ctgv.js} +2 -2
  113. package/dist/shared/{929h19xp.js → mtaszv5a.js} +40 -10
  114. package/dist/shared/{b3awxn7h.js → n816peh1.js} +1 -1
  115. package/dist/shared/nbw1z4yd.js +18 -0
  116. package/dist/shared/{nx9hh281.js → p6qc5gcp.js} +12 -11
  117. package/dist/shared/{pjr6xrm5.js → pbp1ss85.js} +20 -17
  118. package/dist/shared/pt94kz7f.js +6 -0
  119. package/dist/shared/q5c6ngn3.js +13 -0
  120. package/dist/shared/{xq0mvhts.js → rs73fca9.js} +4 -4
  121. package/dist/shared/{r11n8grd.js → sfz1ksn6.js} +7 -4
  122. package/dist/shared/{wynzeggs.js → svncdeh5.js} +6 -6
  123. package/dist/shared/{j60w0dvr.js → tbrvgw6z.js} +57 -38
  124. package/dist/shared/te5as7z7.js +622 -0
  125. package/dist/shared/{ttmg09vd.js → tsvww22q.js} +1 -1
  126. package/dist/shared/{y2t3jktd.js → ttsqgp4p.js} +19 -12
  127. package/dist/shared/{x72jb7ad.js → v8g1vgv8.js} +1 -1
  128. package/dist/shared/{sbdme3vy.js → vb6qfyve.js} +60 -10
  129. package/dist/shared/{5d8t84hg.js → vczs8gd4.js} +14 -14
  130. package/dist/shared/{5yv4k6a6.js → vqrjpcqn.js} +144 -2
  131. package/dist/shared/{3fqwmr09.js → w72kgg4q.js} +4 -4
  132. package/dist/shared/{1z04fa85.js → w79hsckn.js} +12 -57
  133. package/dist/shared/{09p049xa.js → wa07eas9.js} +42 -14
  134. package/dist/shared/{32cnm7kn.js → x933k9a3.js} +74 -38
  135. package/dist/shared/{n076ydsc.js → xhfsfkgk.js} +62 -28
  136. package/dist/shared/xjk7hnn5.js +272 -0
  137. package/dist/shared/{hazqqecq.js → xnxsed62.js} +50 -21
  138. package/dist/shared/y6njgyda.js +249 -0
  139. package/dist/shared/{8etn7d8w.js → z7s6fpxv.js} +1 -1
  140. package/dist/shared/{n7mcc1gk.js → zchaghkf.js} +4 -3
  141. package/dist/shared/zm0ptry0.js +40 -0
  142. package/dist/shared/{nsva2a6b.js → znm0bpp5.js} +3 -0
  143. package/dist/shared/zp9fmend.js +145 -0
  144. package/dist/tooling/cli.js +11 -11
  145. package/dist/tooling/migrate/engine.d.ts +3 -2
  146. package/dist/tooling/migrate/index.js +7 -7
  147. package/dist/tooling/testing/index.js +1 -1
  148. package/package.json +4 -2
  149. package/dist/shared/3qnhc7w5.js +0 -38
  150. package/dist/shared/7m88x3e9.js +0 -45
  151. package/dist/shared/8dqhth8c.js +0 -12
  152. package/dist/shared/d5azex6s.js +0 -6
  153. package/dist/shared/j3rkk835.js +0 -99
  154. package/dist/shared/k68eedmy.js +0 -85
  155. package/dist/shared/venqrjna.js +0 -216
  156. package/dist/shared/wxr8cwns.js +0 -6
  157. package/dist/shared/zm0mafk4.js +0 -92
@@ -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 {};
@@ -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
+ };
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import type { Catalog } from "../../contracts/catalog/types.js";
7
7
  import { type ClientGenerator } from "../../contracts/generator.js";
8
+ import { type PostgresMajor } from "./floor.js";
8
9
  import { type SchemaHook, type TableModel } from "./model.js";
9
10
  import type { FieldsOfList, HasArchive, PresetsOfList, Trait } from "./trait.js";
10
11
  import { type ColumnTenancy, type TenantFields } from "./tenancy.js";
@@ -15,8 +16,16 @@ export type SchemaCodecs = {
15
16
  readonly numeric: "string" | "number";
16
17
  readonly timestamps: "temporal";
17
18
  };
18
- /** Engine requirement recorded for connect. */
19
+ /**
20
+ * Engine requirement recorded for connect.
21
+ *
22
+ * The stored value is `>=` and a major. `minPostgres` and the deprecated
23
+ * string form normalise to the same object.
24
+ */
19
25
  export type SchemaRequires = {
26
+ /**
27
+ * @deprecated Use `minPostgres`. `">=17"` is the same floor as `minPostgres: 17`.
28
+ */
20
29
  readonly postgres?: string;
21
30
  };
22
31
  /**
@@ -28,6 +37,15 @@ export type SchemaRequires = {
28
37
  */
29
38
  export type SchemaInput<TTables extends readonly AnyTable[]> = {
30
39
  readonly tables: TTables;
40
+ /**
41
+ * Oldest Postgres major this schema runs on.
42
+ *
43
+ * Omitted means 15. A feature that needs a newer major is refused here.
44
+ */
45
+ readonly minPostgres?: PostgresMajor;
46
+ /**
47
+ * @deprecated Use {@link SchemaInput.minPostgres}. `">=17"` is the same floor as `minPostgres: 17`.
48
+ */
31
49
  readonly requires?: SchemaRequires;
32
50
  readonly casing?: "snake";
33
51
  readonly codecs?: {
@@ -39,8 +57,13 @@ export type SchemaInput<TTables extends readonly AnyTable[]> = {
39
57
  /**
40
58
  * What a bare `t.id()` means.
41
59
  *
42
- * `"uuidv7"` and `"uuidv4"` are database defaults. A client generator is
43
- * filled on insert and stays out of the catalog. A column option wins.
60
+ * Omitted, the database default is `gen_random_uuid()`. `"uuidv4"` stores
61
+ * the same function. `"uuidv7"` stores `uuidv7()` and needs Postgres 18
62
+ * (`minPostgres: 18`).
63
+ * Pick `uuidv7` for a large write-heavy table: the ids are time-ordered
64
+ * and the index stays local. Random ids are fine elsewhere. A client
65
+ * generator is filled on insert and stays out of the catalog. A column
66
+ * option wins.
44
67
  */
45
68
  readonly defaults?: {
46
69
  readonly id?: "uuidv7" | "uuidv4" | ClientGenerator<string>;
@@ -80,6 +103,11 @@ export type BuiltSchema<TTables extends readonly AnyTable[]> = {
80
103
  readonly types: "emitted" | "inferred";
81
104
  readonly casing: "snake" | undefined;
82
105
  readonly codecs: SchemaCodecs;
106
+ /**
107
+ * Declared floor, normalised to `>=` and a major.
108
+ *
109
+ * Absent when the schema names no floor. Connect then uses 15.
110
+ */
83
111
  readonly requires: SchemaRequires | undefined;
84
112
  readonly tables: TTables;
85
113
  /**
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  viewClient
3
- } from "../../../shared/x3jc53kg.js";
3
+ } from "../../../shared/5e3tf63j.js";
4
4
  import {
5
5
  viewObject,
6
6
  materializedViewObject,
@@ -7,8 +7,14 @@
7
7
  * every aggregate exactly as they apply to a `find`. This module loads on the
8
8
  * first `aggregate()`.
9
9
  *
10
- * Not here: `having`, `bucket`, and ordering by an aggregate. A hidden column
11
- * cannot be grouped or aggregated, so an aggregate never shows what a read hides.
10
+ * Not here: `having`, ordering by an aggregate, and the time-zone date helpers
11
+ * (tool 5). A hidden column cannot be grouped or aggregated, so an aggregate
12
+ * never shows what a read hides.
13
+ *
14
+ * `bucket()` is a tagged helper. Its validation and SQL load in their own
15
+ * chunk, and only when `groupBy` contains one. A request object cannot create
16
+ * one. A NULL timestamp is one group: the result key is present and the value
17
+ * is null.
12
18
  */
13
19
  import { type Mods, type Session } from "./client.js";
14
20
  import { type ArchiveView } from "./plan.js";
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Time buckets inside `aggregate` `groupBy` (spec §10, §13 tool 4).
3
+ *
4
+ * This module loads on the first `aggregate()` whose `groupBy` contains a
5
+ * `bucket()`. A plain aggregate does not import it. A NULL timestamp is one
6
+ * group: the `as` key is present and the value is null.
7
+ */
8
+ import type { ColumnModel } from "../dialects/pg/model.js";
9
+ import { type BucketUnit } from "../dialects/pg/ops/bucket.js";
10
+ import { type Built, type Indexed, type Sink } from "./plan.js";
11
+ /** One bucket in a group list. */
12
+ export type BucketGroup = {
13
+ readonly kind: "bucket";
14
+ readonly column: ColumnModel;
15
+ readonly unit: BucketUnit;
16
+ readonly tz: string | undefined;
17
+ readonly as: string;
18
+ readonly shift: 0 | 1 | 2;
19
+ readonly clock: boolean;
20
+ };
21
+ /**
22
+ * What the aggregate chunk calls after this module loads.
23
+ *
24
+ * The aggregate chunk does not import this file. It receives the functions
25
+ * from `import()`.
26
+ */
27
+ export type BucketChunk = {
28
+ readBucket(table: Indexed, value: unknown, fields: ReadonlySet<string>, aliases: Set<string>): BucketGroup;
29
+ writeBucket(sink: Sink, outputs: Built | undefined, wrote: {
30
+ at: number;
31
+ }, group: BucketGroup): void;
32
+ writeGrouped(sink: Sink, names: readonly string[], orderBy: unknown): void;
33
+ };
34
+ /**
35
+ * Reads one `bucket()` group.
36
+ *
37
+ * Refuses a bad unit, zone, week start, or result name before any SQL.
38
+ * `__proto__`, `constructor`, `toString`, and `hasOwnProperty` are refused.
39
+ * `timestamptz` needs an IANA `tz`. `date` refuses `tz`. `timestamp` without
40
+ * a zone is refused.
41
+ *
42
+ * @param table - The grouped table
43
+ * @param value - One `groupBy` entry
44
+ * @param fields - Plain group fields already seen
45
+ * @param aliases - Bucket result names already seen
46
+ * @returns The group the statement writes
47
+ */
48
+ export declare function readBucket(table: Indexed, value: unknown, fields: ReadonlySet<string>, aliases: Set<string>): BucketGroup;
49
+ /**
50
+ * Writes one bucket expression into the select list.
51
+ *
52
+ * @param sink - Statement buffer
53
+ * @param outputs - Decode plan, absent while only marking
54
+ * @param wrote - How many select items are already written
55
+ * @param group - The bucket
56
+ */
57
+ export declare function writeBucket(sink: Sink, outputs: Built | undefined, wrote: {
58
+ at: number;
59
+ }, group: BucketGroup): void;
60
+ /**
61
+ * Groups and orders by select-list ordinals.
62
+ *
63
+ * The bucket expression is written once, in the select list. A second copy
64
+ * would bind a new `$n`, and Postgres treats that as a different expression.
65
+ *
66
+ * @param sink - Statement buffer
67
+ * @param names - Group names, in select order
68
+ * @param orderBy - Caller order, or the default group order
69
+ */
70
+ export declare function writeGrouped(sink: Sink, names: readonly string[], orderBy: unknown): void;
@@ -23,18 +23,36 @@ export type ConflictPlan = {
23
23
  */
24
24
  export declare function readConflict(table: Indexed, value: unknown, allow?: ReadonlySet<string>, tenantKey?: string | readonly string[]): ConflictPlan | undefined;
25
25
  /**
26
- * Appends the conflict clause, or wraps a first-or-create insert.
26
+ * Appends the conflict clause.
27
+ *
28
+ * First-or-create is `on conflict do nothing`. It does not read the existing
29
+ * row here: that lookup is a later statement, so it sees a row another
30
+ * transaction committed while this insert waited (D246).
27
31
  *
28
32
  * @param head - `insert into … values …` without `returning`
29
33
  * @param returning - ` returning …`, including the leading space
30
34
  * @param params - Insert parameters
31
35
  * @param plan - Conflict plan
32
36
  * @param table - Target table
33
- * @param returningColumns - Columns in `returning`
34
- * @param keys - Encoded conflict-key tuples, one per inserted row. Used by `return`
35
37
  * @returns Statement text and parameters
36
38
  */
37
- export declare function finishInsert(head: string, returning: string, params: readonly (string | null)[], plan: ConflictPlan, table: Indexed, returningColumns: readonly ColumnModel[], keys: readonly (readonly (string | null)[])[]): {
39
+ export declare function finishInsert(head: string, returning: string, params: readonly (string | null)[], plan: ConflictPlan, table: Indexed): {
40
+ readonly text: string;
41
+ readonly params: (string | null)[];
42
+ };
43
+ /**
44
+ * Reads rows a first-or-create insert did not return.
45
+ *
46
+ * The conflict target is the same unique, including the tenant key. A partial
47
+ * unique on an archivable table only matches the active row.
48
+ *
49
+ * @param table - Target table
50
+ * @param keys - Conflict columns, in constraint order
51
+ * @param returningColumns - Columns the insert returns, in that order
52
+ * @param keyRows - Encoded conflict-key tuples that the insert did not return
53
+ * @returns One select
54
+ */
55
+ export declare function lookupExisting(table: Indexed, keys: readonly ColumnModel[], returningColumns: readonly ColumnModel[], keyRows: readonly (readonly (string | null)[])[]): {
38
56
  readonly text: string;
39
57
  readonly params: (string | null)[];
40
58
  };
@@ -2,14 +2,6 @@
2
2
  * LATERAL include planner. Loaded on the first include.
3
3
  */
4
4
  import { type IncludeHooks, type Plan } from "./plan.js";
5
- /**
6
- * Decodes a result that has includes.
7
- *
8
- * @param plan - Compiled plan
9
- * @param rows - Wire rows
10
- * @param table - Table the call named
11
- * @returns The call's value
12
- */
13
5
  export declare function decodeIncluded(plan: Plan, rows: readonly (readonly (string | null)[])[], table: string): unknown;
14
6
  /** Hooks the read planner calls after this module has loaded. */
15
7
  export declare const includeHooks: IncludeHooks;
@@ -2,7 +2,7 @@
2
2
  * Refuses a positive timeout on a driver that cannot cancel.
3
3
  *
4
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.
5
+ * connect graph does not. The OKM1120 text loads with the lazy error module.
6
6
  */
7
7
  import type { DriverPool } from "../contracts/driver.js";
8
8
  /**
@@ -20,6 +20,9 @@ import { type ArchiveView } from "./plan.js";
20
20
  * @param options - `where`, `select`, `orderBy`, `limit`, `include`, and `after`
21
21
  * @param mods - Signal and timeout
22
22
  * @param view - Archive visibility
23
+ * @param pin - Endpoint a stream already chose. Absent for `page()`
23
24
  * @returns A handle that resolves to `{ items, next }`
24
25
  */
25
- export declare function build(session: Session, table: string, options: object, mods: Mods, view: ArchiveView | undefined): Promise<unknown> & Record<string, unknown>;
26
+ export declare function build(session: Session, table: string, options: object, mods: Mods, view: ArchiveView | undefined, pin?: {
27
+ name?: string;
28
+ }): Promise<unknown> & Record<string, unknown>;
@@ -1,23 +1,27 @@
1
- import"../../shared/8dqhth8c.js";
2
1
  import {
3
2
  DriverError2
4
- } from "../../shared/31vm914h.js";
3
+ } from "../../shared/cm3w0ywp.js";
5
4
  import {
5
+ markClientPool,
6
6
  open5
7
- } from "../../shared/32cnm7kn.js";
7
+ } from "../../shared/x933k9a3.js";
8
8
  import {
9
9
  BUNSQL_CAPABILITIES,
10
10
  readCapability2,
11
11
  hasCapability2
12
- } from "../../shared/cgbamx3e.js";
12
+ } from "../../shared/kb2sdhfb.js";
13
13
  import {
14
14
  createClient
15
- } from "../../shared/j60w0dvr.js";
15
+ } from "../../shared/tbrvgw6z.js";
16
16
 
17
17
  // src/runtime/pg/bun.ts
18
18
  function connect(target, options) {
19
19
  if (typeof target === "object" && !isPool(target)) {
20
- return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open5));
20
+ return import("../../shared/mtaszv5a.js").then((mod) => mod.default(target, options, (config) => {
21
+ const pool = open5(config);
22
+ markClientPool(pool);
23
+ return pool;
24
+ }));
21
25
  }
22
26
  const owned = !isPool(target);
23
27
  const pool = isPool(target) ? target : open5({
@@ -28,6 +32,8 @@ function connect(target, options) {
28
32
  ...options.searchPath !== undefined ? { searchPath: options.searchPath } : {},
29
33
  ...options.ssl !== undefined ? { ssl: options.ssl } : {}
30
34
  });
35
+ if (!isPool(target))
36
+ markClientPool(pool);
31
37
  return createClient(options.schema, pool, {
32
38
  ownsPool: owned,
33
39
  http: options.errors?.http,
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  DriverError2
3
- } from "../../shared/31vm914h.js";
3
+ } from "../../shared/cm3w0ywp.js";
4
4
  import {
5
5
  open4
6
- } from "../../shared/1z04fa85.js";
6
+ } from "../../shared/w79hsckn.js";
7
7
  import {
8
8
  NODE_POSTGRES_CAPABILITIES,
9
9
  readCapability2,
10
10
  hasCapability2
11
- } from "../../shared/cgbamx3e.js";
11
+ } from "../../shared/kb2sdhfb.js";
12
12
  import {
13
13
  createClient
14
- } from "../../shared/j60w0dvr.js";
14
+ } from "../../shared/tbrvgw6z.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/929h19xp.js").then((mod) => mod.default(target, options, open4));
19
+ return import("../../shared/mtaszv5a.js").then((mod) => mod.default(target, options, open4));
20
20
  }
21
21
  const owned = !isPool(target);
22
22
  const pool = isPool(target) ? target : open4({
@@ -2,6 +2,7 @@
2
2
  * `connect` for PGlite (`okmodel/pg/pglite`).
3
3
  *
4
4
  * Opening a database is async. An existing pool is reused and not closed.
5
+ * Closing that client marks the client closed.
5
6
  * A `{ primary, replicas }` object loads the topology module. A replica URL is
6
7
  * that endpoint's data directory.
7
8
  */
@@ -1,30 +1,30 @@
1
- import"../../shared/8dqhth8c.js";
2
1
  import {
3
2
  DriverError2
4
- } from "../../shared/31vm914h.js";
3
+ } from "../../shared/cm3w0ywp.js";
5
4
  import {
6
- open3
7
- } from "../../shared/5j36z8dn.js";
5
+ open3,
6
+ seal2
7
+ } from "../../shared/81ebdx9p.js";
8
8
  import {
9
9
  PGLITE_CAPABILITIES,
10
10
  readCapability2,
11
11
  hasCapability2
12
- } from "../../shared/cgbamx3e.js";
12
+ } from "../../shared/kb2sdhfb.js";
13
13
  import {
14
14
  createClient
15
- } from "../../shared/j60w0dvr.js";
15
+ } from "../../shared/tbrvgw6z.js";
16
16
 
17
17
  // src/runtime/pg/pglite.ts
18
18
  async function connect(target, options) {
19
19
  if (typeof target === "object" && !isPool(target)) {
20
- return import("../../shared/929h19xp.js").then((mod) => mod.default(target, options, open3));
20
+ return import("../../shared/mtaszv5a.js").then((mod) => mod.default(target, options, open3));
21
21
  }
22
- const pool = isPool(target) ? target : await open3({
22
+ const pool = isPool(target) ? seal2(target) : await open3({
23
23
  ...target !== undefined ? { dataDir: target } : {},
24
24
  ...options.timeouts !== undefined ? { timeouts: options.timeouts } : {}
25
25
  });
26
26
  return createClient(options.schema, pool, {
27
- ownsPool: !isPool(target),
27
+ ownsPool: true,
28
28
  http: options.errors?.http,
29
29
  includeValues: options.errors?.includeValues,
30
30
  logger: options.logger,
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  DriverError2
3
- } from "../../shared/31vm914h.js";
3
+ } from "../../shared/cm3w0ywp.js";
4
4
  import {
5
5
  open2
6
- } from "../../shared/wkme6tep.js";
6
+ } from "../../shared/14vx95q4.js";
7
7
  import {
8
8
  POSTGRESJS_CAPABILITIES,
9
9
  readCapability2,
10
10
  hasCapability2
11
- } from "../../shared/cgbamx3e.js";
11
+ } from "../../shared/kb2sdhfb.js";
12
12
  import {
13
13
  createClient
14
- } from "../../shared/j60w0dvr.js";
14
+ } from "../../shared/tbrvgw6z.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/929h19xp.js").then((mod) => mod.default(target, options, open2));
19
+ return import("../../shared/mtaszv5a.js").then((mod) => mod.default(target, options, open2));
20
20
  }
21
21
  const owned = !isPool(target);
22
22
  const pool = isPool(target) ? target : open2({