okmodel 0.1.1 → 0.3.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 (228) hide show
  1. package/README.md +727 -37
  2. package/dist/adapters/capabilities.d.ts +34 -0
  3. package/dist/adapters/pg/bunsql-extra.d.ts +17 -0
  4. package/dist/adapters/pg/bunsql.d.ts +60 -0
  5. package/dist/adapters/pg/call.d.ts +2 -12
  6. package/dist/adapters/pg/nodepostgres-extra.d.ts +18 -0
  7. package/dist/adapters/pg/nodepostgres.d.ts +57 -0
  8. package/dist/adapters/pg/postgres-extra.d.ts +50 -1
  9. package/dist/adapters/pg/postgresjs.d.ts +0 -4
  10. package/dist/adapters/pg/session.d.ts +94 -0
  11. package/dist/adapters/pg/watch.d.ts +18 -0
  12. package/dist/contracts/catalog/enum.d.ts +31 -4
  13. package/dist/contracts/catalog/extension.d.ts +61 -0
  14. package/dist/contracts/catalog/object.d.ts +1 -0
  15. package/dist/contracts/catalog/privilege.d.ts +64 -0
  16. package/dist/contracts/catalog/routine.d.ts +56 -0
  17. package/dist/contracts/catalog/types.d.ts +179 -18
  18. package/dist/contracts/catalog/view.d.ts +73 -0
  19. package/dist/contracts/connection.d.ts +13 -0
  20. package/dist/contracts/driver.d.ts +18 -5
  21. package/dist/contracts/error.d.ts +17 -1
  22. package/dist/contracts/generator.d.ts +63 -0
  23. package/dist/contracts/index.d.ts +2 -2
  24. package/dist/contracts/index.js +1 -1
  25. package/dist/contracts/internal.js +11 -9
  26. package/dist/contracts/location.d.ts +24 -0
  27. package/dist/contracts/rows.d.ts +15 -0
  28. package/dist/dialects/pg/archive-bind.d.ts +22 -0
  29. package/dist/dialects/pg/column.d.ts +129 -10
  30. package/dist/dialects/pg/compile.d.ts +1 -0
  31. package/dist/dialects/pg/custom.d.ts +6 -0
  32. package/dist/dialects/pg/ddl.d.ts +65 -1
  33. package/dist/dialects/pg/enum.d.ts +10 -8
  34. package/dist/dialects/pg/ext/citext.d.ts +14 -0
  35. package/dist/dialects/pg/ext/citext.js +11 -0
  36. package/dist/dialects/pg/ext/index.d.ts +52 -0
  37. package/dist/dialects/pg/ext/index.js +6 -0
  38. package/dist/dialects/pg/ext/pg-trgm.d.ts +53 -0
  39. package/dist/dialects/pg/ext/pg-trgm.js +42 -0
  40. package/dist/dialects/pg/filter-parse.d.ts +19 -0
  41. package/dist/dialects/pg/filters.d.ts +19 -0
  42. package/dist/dialects/pg/fn/index.d.ts +107 -0
  43. package/dist/dialects/pg/fn/index.js +175 -0
  44. package/dist/dialects/pg/fn/touch.d.ts +14 -0
  45. package/dist/dialects/pg/index.d.ts +11 -2
  46. package/dist/dialects/pg/index.js +243 -1062
  47. package/dist/dialects/pg/introspect.d.ts +10 -1
  48. package/dist/dialects/pg/keys.d.ts +19 -3
  49. package/dist/dialects/pg/model.d.ts +223 -2
  50. package/dist/dialects/pg/operator-fit.d.ts +86 -0
  51. package/dist/dialects/pg/operators.d.ts +46 -1
  52. package/dist/dialects/pg/ops/arr-append.d.ts +9 -0
  53. package/dist/dialects/pg/ops/arr-ns.d.ts +7 -0
  54. package/dist/dialects/pg/ops/arr-remove.d.ts +9 -0
  55. package/dist/dialects/pg/ops/containedBy.d.ts +9 -0
  56. package/dist/dialects/pg/ops/contains.d.ts +8 -4
  57. package/dist/dialects/pg/ops/hasAnyKey.d.ts +8 -0
  58. package/dist/dialects/pg/ops/hasKey.d.ts +8 -0
  59. package/dist/dialects/pg/ops/json-ns.d.ts +6 -0
  60. package/dist/dialects/pg/ops/json-set.d.ts +12 -0
  61. package/dist/dialects/pg/ops/matches.d.ts +16 -0
  62. package/dist/dialects/pg/ops/overlaps.d.ts +9 -0
  63. package/dist/dialects/pg/ops/path.d.ts +13 -0
  64. package/dist/dialects/pg/preset.d.ts +76 -0
  65. package/dist/dialects/pg/relations.d.ts +59 -2
  66. package/dist/dialects/pg/role/check.d.ts +45 -0
  67. package/dist/dialects/pg/role/index.d.ts +50 -0
  68. package/dist/dialects/pg/role/sql.d.ts +44 -0
  69. package/dist/dialects/pg/schema.d.ts +109 -5
  70. package/dist/dialects/pg/table.d.ts +137 -11
  71. package/dist/dialects/pg/temporal.d.ts +9 -7
  72. package/dist/dialects/pg/tenancy.d.ts +103 -0
  73. package/dist/dialects/pg/through.d.ts +21 -0
  74. package/dist/dialects/pg/trait.d.ts +141 -0
  75. package/dist/dialects/pg/view/client.d.ts +30 -0
  76. package/dist/dialects/pg/view/depend.d.ts +35 -0
  77. package/dist/dialects/pg/view/index.d.ts +114 -0
  78. package/dist/dialects/pg/view/index.js +289 -0
  79. package/dist/dialects/pg/view/scratch.d.ts +21 -0
  80. package/dist/dialects/pg/where.d.ts +37 -0
  81. package/dist/runtime/aggregate.d.ts +25 -0
  82. package/dist/runtime/archive-handle.d.ts +18 -0
  83. package/dist/runtime/archive-rules.d.ts +12 -0
  84. package/dist/runtime/archive.d.ts +73 -0
  85. package/dist/runtime/batch.d.ts +20 -0
  86. package/dist/runtime/client.d.ts +114 -5
  87. package/dist/runtime/conflict.d.ts +2 -1
  88. package/dist/runtime/exposure.d.ts +27 -0
  89. package/dist/runtime/hookm.d.ts +39 -0
  90. package/dist/runtime/ids/index.d.ts +11 -0
  91. package/dist/runtime/ids/index.js +193 -0
  92. package/dist/runtime/ids/okid-extended.d.ts +19 -0
  93. package/dist/runtime/ids/okid-generator.d.ts +21 -0
  94. package/dist/runtime/ids/okid-shared.d.ts +89 -0
  95. package/dist/runtime/ids/okid.d.ts +24 -0
  96. package/dist/runtime/ids/uuid.d.ts +21 -0
  97. package/dist/runtime/lock.d.ts +22 -0
  98. package/dist/runtime/operator-sql.d.ts +8 -0
  99. package/dist/runtime/page.d.ts +25 -0
  100. package/dist/runtime/pg/bun.d.ts +30 -0
  101. package/dist/runtime/pg/bun.js +52 -0
  102. package/dist/runtime/pg/pg.d.ts +29 -0
  103. package/dist/runtime/pg/pg.js +52 -0
  104. package/dist/runtime/pg/pglite.js +16 -17
  105. package/dist/runtime/pg/postgresjs.js +14 -24
  106. package/dist/runtime/plan.d.ts +146 -7
  107. package/dist/runtime/preset-stack.d.ts +17 -0
  108. package/dist/runtime/presets.d.ts +48 -0
  109. package/dist/runtime/read-stream.d.ts +26 -0
  110. package/dist/runtime/safety/index.d.ts +159 -0
  111. package/dist/runtime/safety/index.js +294 -0
  112. package/dist/runtime/safety-hook.d.ts +42 -0
  113. package/dist/runtime/server-check.d.ts +34 -0
  114. package/dist/runtime/tenancy/index.d.ts +37 -0
  115. package/dist/runtime/tenancy/index.js +368 -0
  116. package/dist/runtime/trait-read.d.ts +30 -0
  117. package/dist/runtime/traits/index.d.ts +133 -0
  118. package/dist/runtime/traits/index.js +646 -0
  119. package/dist/runtime/transaction.d.ts +19 -0
  120. package/dist/runtime/tx.d.ts +22 -7
  121. package/dist/runtime/types.d.ts +376 -27
  122. package/dist/runtime/validate/bind.d.ts +11 -0
  123. package/dist/runtime/validate/closed.d.ts +16 -0
  124. package/dist/runtime/validate/engine.d.ts +41 -0
  125. package/dist/runtime/validate/hook.d.ts +17 -0
  126. package/dist/runtime/validate/index.d.ts +21 -0
  127. package/dist/runtime/validate/index.js +175 -0
  128. package/dist/runtime/validate/load.d.ts +13 -0
  129. package/dist/runtime/validate/places.d.ts +41 -0
  130. package/dist/runtime/validate/rules.d.ts +108 -0
  131. package/dist/runtime/validate/surface.d.ts +102 -0
  132. package/dist/runtime/write.d.ts +30 -5
  133. package/dist/shared/01yr20s5.js +149 -0
  134. package/dist/shared/0jc3ffzf.js +154 -0
  135. package/dist/shared/0v1g424p.js +26 -0
  136. package/dist/shared/1g0drakv.js +225 -0
  137. package/dist/shared/{kprcwaha.js → 1tfdfvhh.js} +5 -3
  138. package/dist/shared/{05w44d8g.js → 2ssqrv66.js} +767 -715
  139. package/dist/shared/3ekj9x92.js +210 -0
  140. package/dist/shared/49ypnfwt.js +1122 -0
  141. package/dist/shared/4e4c6vq2.js +62 -0
  142. package/dist/shared/4m9fn52z.js +70 -0
  143. package/dist/shared/{ycwz42az.js → 52szzakm.js} +6 -26
  144. package/dist/shared/5nmdenb6.js +1229 -0
  145. package/dist/shared/672t5vym.js +12 -0
  146. package/dist/shared/6bazvqwm.js +86 -0
  147. package/dist/shared/6w5j844a.js +201 -0
  148. package/dist/shared/{fgqgsb5z.js → 75xkjv0t.js} +2 -2
  149. package/dist/shared/7fvtrkwr.js +84 -0
  150. package/dist/shared/7m88x3e9.js +45 -0
  151. package/dist/shared/{mtkwv8wx.js → 7p2wbz7f.js} +1 -1
  152. package/dist/shared/83eaefwr.js +10 -0
  153. package/dist/shared/94ez8kzh.js +19 -0
  154. package/dist/shared/96ps4g1z.js +32 -0
  155. package/dist/shared/{xqbhg6cn.js → 999ade2q.js} +95 -10
  156. package/dist/shared/9m80mkac.js +158 -0
  157. package/dist/shared/9x25fxhc.js +150 -0
  158. package/dist/shared/a5sxz52y.js +13 -0
  159. package/dist/shared/axhk06q1.js +156 -0
  160. package/dist/shared/{dynq16vb.js → b066g80h.js} +8 -6
  161. package/dist/shared/bqha5cg6.js +229 -0
  162. package/dist/shared/bryqk9k9.js +31 -0
  163. package/dist/shared/c8aghh05.js +442 -0
  164. package/dist/shared/c9z5g0fm.js +309 -0
  165. package/dist/shared/{m3ypagh5.js → dbjej1tw.js} +124 -15
  166. package/dist/shared/dyj86cmj.js +69 -0
  167. package/dist/shared/e6wg00wd.js +164 -0
  168. package/dist/shared/{hadrfb9h.js → edwqqryd.js} +17 -14
  169. package/dist/shared/{qk3hxfja.js → fptpmvxp.js} +5 -5
  170. package/dist/shared/fs0ex00p.js +76 -0
  171. package/dist/shared/{jjb7yht9.js → g4f5kcx9.js} +3 -3
  172. package/dist/shared/gjthds9j.js +48 -0
  173. package/dist/shared/hcmdtwgh.js +102 -0
  174. package/dist/shared/{g5fhqmwe.js → jkc6ws1p.js} +6 -56
  175. package/dist/shared/{yd1kzwn2.js → jns2wx4t.js} +55 -12
  176. package/dist/shared/k34e0xf2.js +450 -0
  177. package/dist/shared/k3ted12y.js +33 -0
  178. package/dist/shared/k7dwkhvq.js +31 -0
  179. package/dist/shared/{8b04d28c.js → kgnc8grt.js} +2 -2
  180. package/dist/shared/{hd293j9g.js → kyxb62mc.js} +14 -2
  181. package/dist/shared/m78s7898.js +376 -0
  182. package/dist/shared/m9tv7xn7.js +404 -0
  183. package/dist/shared/meck53jv.js +99 -0
  184. package/dist/shared/mt5wswjz.js +90 -0
  185. package/dist/shared/n0dgs0pb.js +75 -0
  186. package/dist/shared/n442h54c.js +14 -0
  187. package/dist/shared/n4jqhpqz.js +27 -0
  188. package/dist/shared/n7mcc1gk.js +132 -0
  189. package/dist/shared/ne02ng5c.js +68 -0
  190. package/dist/shared/{mkjmqjv4.js → nfzc5z0w.js} +2 -104
  191. package/dist/shared/nsva2a6b.js +42 -0
  192. package/dist/shared/p24x2334.js +195 -0
  193. package/dist/shared/qbxzvwwc.js +88 -0
  194. package/dist/shared/{w8samvk1.js → qybh48nd.js} +1 -1
  195. package/dist/shared/r6nwkxnt.js +86 -0
  196. package/dist/shared/{xy79j5hq.js → rrstp3kb.js} +25 -36
  197. package/dist/shared/rwmrejjz.js +26 -0
  198. package/dist/shared/{zhc5vmgf.js → s6gqfn5j.js} +2 -2
  199. package/dist/shared/{523ft3e8.js → scwxrpx2.js} +7 -5
  200. package/dist/shared/{j5cn2963.js → t4tbsy9h.js} +13 -64
  201. package/dist/shared/{y9m15dfv.js → t616ynfn.js} +544 -32
  202. package/dist/shared/{ngk8gj61.js → tbszx8mz.js} +15 -1
  203. package/dist/shared/th14ygv2.js +69 -0
  204. package/dist/shared/tmbdywx0.js +178 -0
  205. package/dist/shared/ty3v3hfk.js +64 -0
  206. package/dist/shared/wekze34d.js +246 -0
  207. package/dist/shared/x6wysh83.js +1132 -0
  208. package/dist/shared/{rgs0st28.js → xrfnq5k8.js} +237 -434
  209. package/dist/shared/{x5x59srr.js → xva8v7qk.js} +416 -83
  210. package/dist/shared/{dkn3y60a.js → xw1d69vd.js} +76 -112
  211. package/dist/shared/y005b761.js +112 -0
  212. package/dist/shared/ydaz1sv3.js +55 -0
  213. package/dist/shared/{p0cbr3g2.js → zwmqxb0g.js} +1 -1
  214. package/dist/tooling/cli.js +40 -12
  215. package/dist/tooling/migrate/apply.d.ts +16 -0
  216. package/dist/tooling/migrate/commands.d.ts +12 -1
  217. package/dist/tooling/migrate/config.d.ts +8 -0
  218. package/dist/tooling/migrate/doctor.d.ts +25 -0
  219. package/dist/tooling/migrate/drift.d.ts +19 -0
  220. package/dist/tooling/migrate/engine.d.ts +36 -0
  221. package/dist/tooling/migrate/ext.d.ts +17 -0
  222. package/dist/tooling/migrate/extensions.d.ts +51 -0
  223. package/dist/tooling/migrate/managed.d.ts +17 -0
  224. package/dist/tooling/migrate/plan.d.ts +14 -1
  225. package/dist/tooling/migrate/project.d.ts +25 -1
  226. package/dist/tooling/migrate/type-name.d.ts +19 -0
  227. package/package.json +61 -4
  228. package/dist/shared/gk7cs7sp.js +0 -566
@@ -0,0 +1,646 @@
1
+ import {
2
+ checkPresetNames,
3
+ duplicatePreset
4
+ } from "../../shared/nsva2a6b.js";
5
+ import {
6
+ checkTrait
7
+ } from "../../shared/n0dgs0pb.js";
8
+ import {
9
+ quoteIdent
10
+ } from "../../shared/wekze34d.js";
11
+ import {
12
+ functionObject,
13
+ triggerObject
14
+ } from "../../shared/9x25fxhc.js";
15
+ import {
16
+ timestamptz2
17
+ } from "../../shared/1g0drakv.js";
18
+ import {
19
+ uuid2
20
+ } from "../../shared/dyj86cmj.js";
21
+ import {
22
+ snakeCase
23
+ } from "../../shared/6w5j844a.js";
24
+ import {
25
+ ColumnBuilder2,
26
+ retarget
27
+ } from "../../shared/c9z5g0fm.js";
28
+ import {
29
+ definition,
30
+ unavailable
31
+ } from "../../shared/tmbdywx0.js";
32
+ import {
33
+ staticNamespace2,
34
+ compareText
35
+ } from "../../shared/t4tbsy9h.js";
36
+ import {
37
+ queryHandle,
38
+ attachHttp,
39
+ settleCall
40
+ } from "../../shared/k34e0xf2.js";
41
+ import {
42
+ installArchiveInspect
43
+ } from "../../shared/xrfnq5k8.js";
44
+ import {
45
+ fitIdentifier2
46
+ } from "../../shared/nfzc5z0w.js";
47
+ import {
48
+ OkmError2,
49
+ catalogError2,
50
+ throwNamed2
51
+ } from "../../shared/52szzakm.js";
52
+
53
+ // src/dialects/pg/archive-bind.ts
54
+ function rewriteArchivable(self, tables, casing, schemaTraits, cascade) {
55
+ const byName = new Map(tables.map((item) => [item.name, item]));
56
+ const accepted = tables.map((item) => item.name);
57
+ const edges = foreignKeys(tables, casing, byName);
58
+ const archiveSql = casing === "snake" ? "archived_at" : "archivedAt";
59
+ const idSql = casing === "snake" ? "archive_id" : "archiveId";
60
+ const predicate = `"${archiveSql.replaceAll('"', '""')}" is null`;
61
+ return tables.map((item) => {
62
+ if (!applies(self, item, schemaTraits))
63
+ return item;
64
+ return rewriteOne(item, cascade, byName, accepted, edges, casing, schemaTraits, archiveSql, idSql, predicate);
65
+ });
66
+ }
67
+ function rewriteOne(item, cascade, byName, accepted, edges, casing, schemaTraits, archiveSql, idSql, predicate) {
68
+ const links = childLinks(item, cascade, byName, accepted, edges, casing, schemaTraits, archiveSql, idSql);
69
+ const parents = parentLinks(item, byName, edges, casing, schemaTraits, archiveSql, idSql);
70
+ const primary = primaryFields(item);
71
+ if ((links.length > 0 || parents.length > 0) && primary.length === 0) {
72
+ catalogError2("OKM1020", `Table ${item.name} is archivable and needs a primary key.`);
73
+ }
74
+ const options = item.options;
75
+ const partials = [];
76
+ const named = options?.unique;
77
+ if (named !== undefined) {
78
+ for (const fields of Object.values(named)) {
79
+ partials.push(partialIndex(fields.map((field) => fieldSql(field, item.columns[field], casing)), predicate));
80
+ }
81
+ }
82
+ let columns;
83
+ for (const [field, builder] of Object.entries(item.columns)) {
84
+ if (!(builder instanceof ColumnBuilder2) || builder.state.unique === undefined)
85
+ continue;
86
+ columns ??= { ...item.columns };
87
+ columns[field] = retarget(builder, { dropUnique: true });
88
+ partials.push(partialIndex([fieldSql(field, builder, casing)], predicate));
89
+ }
90
+ const prior = options?.indexes;
91
+ const indexes = partials.length === 0 ? undefined : (handles) => {
92
+ const calls = prior === undefined ? [] : prior(handles);
93
+ return [...partials, ...Array.isArray(calls) ? calls : []];
94
+ };
95
+ const archiveModel = {
96
+ at: archiveSql,
97
+ id: idSql,
98
+ atField: "archivedAt",
99
+ idField: "archiveId",
100
+ cascade: links,
101
+ parents
102
+ };
103
+ return {
104
+ ...item,
105
+ ...columns !== undefined ? { columns } : {},
106
+ ...named !== undefined || indexes !== undefined ? { options: nextOptions(item.options, indexes) } : {},
107
+ archiveModel
108
+ };
109
+ }
110
+ function childLinks(item, cascade, byName, accepted, edges, casing, schemaTraits, archiveSql, idSql) {
111
+ const seen = new Set;
112
+ const links = [];
113
+ for (const name of cascade) {
114
+ if (seen.has(name))
115
+ catalogError2("OKM1020", `Cascade ${item.name} names ${name} more than once.`);
116
+ seen.add(name);
117
+ if (name === item.name)
118
+ catalogError2("OKM1020", `Cascade ${item.name} names itself.`);
119
+ const child = byName.get(name);
120
+ if (child === undefined) {
121
+ throwNamed2("OKM1020", name, accepted, `Cascade ${item.name} names ${name}, which is not a table. Accepted names: ${list(accepted)}.`);
122
+ }
123
+ if (!isArchivable(child, schemaTraits)) {
124
+ catalogError2("OKM1020", `Cascade ${item.name} names ${name}, which is not archivable.`);
125
+ }
126
+ const matches = edges.filter((edge) => edge.from === name && edge.to === item.name);
127
+ if (matches.length !== 1) {
128
+ const hint = matches.map((edge) => edge.field).sort();
129
+ const which = hint.length === 0 ? "none" : hint.join(", ");
130
+ catalogError2("OKM1021", `Cascade ${item.name} names ${name}, which has ${matches.length === 0 ? "no" : "more than one"} foreign key to ${item.name}. Accepted columns: ${which}.`);
131
+ }
132
+ const edge = matches[0];
133
+ if (edge === undefined) {
134
+ catalogError2("OKM1021", `Cascade ${item.name} names ${name}, which has no foreign key to ${item.name}. Accepted columns: none.`);
135
+ }
136
+ links.push({
137
+ table: name,
138
+ sql: tableSql(child, casing),
139
+ at: archiveSql,
140
+ id: idSql,
141
+ local: edge.local,
142
+ remote: edge.remote
143
+ });
144
+ }
145
+ return links;
146
+ }
147
+ function parentLinks(item, byName, edges, casing, schemaTraits, archiveSql, idSql) {
148
+ const parents = [];
149
+ for (const edge of edges) {
150
+ if (edge.from !== item.name)
151
+ continue;
152
+ const parent = byName.get(edge.to);
153
+ if (parent === undefined || !isArchivable(parent, schemaTraits))
154
+ continue;
155
+ parents.push({
156
+ table: parent.name,
157
+ sql: tableSql(parent, casing),
158
+ at: archiveSql,
159
+ id: idSql,
160
+ local: edge.local,
161
+ remote: edge.remote
162
+ });
163
+ }
164
+ parents.sort((left, right) => compareText(left.table, right.table));
165
+ return parents;
166
+ }
167
+ function foreignKeys(tables, casing, byName) {
168
+ const edges = [];
169
+ for (const item of tables) {
170
+ for (const [field, builder] of Object.entries(item.columns)) {
171
+ if (!(builder instanceof ColumnBuilder2))
172
+ continue;
173
+ const reference = builder.state.references;
174
+ if (reference === undefined)
175
+ continue;
176
+ const target = byName.get(reference.table);
177
+ if (target === undefined)
178
+ continue;
179
+ edges.push({
180
+ from: item.name,
181
+ field,
182
+ to: reference.table,
183
+ local: localNames(item, field, builder, reference, casing),
184
+ remote: remoteNames(target, reference, casing)
185
+ });
186
+ }
187
+ }
188
+ return edges;
189
+ }
190
+ function localNames(item, field, builder, reference, casing) {
191
+ const names = [fieldSql(field, builder, casing)];
192
+ for (const extra of reference.along ?? [])
193
+ names.push(fieldSql(extra, item.columns[extra], casing));
194
+ return names;
195
+ }
196
+ function remoteNames(target, reference, casing) {
197
+ if (reference.columns !== undefined) {
198
+ return reference.columns.map((name) => fieldSql(name, target.columns[name], casing));
199
+ }
200
+ return primaryFields(target).map((name) => fieldSql(name, target.columns[name], casing));
201
+ }
202
+ function applies(self, item, schemaTraits) {
203
+ const options = item.options;
204
+ const own = Array.isArray(options?.traits) ? options.traits : [];
205
+ if (own.includes(self))
206
+ return true;
207
+ if (options?.omitDefaults !== undefined)
208
+ return false;
209
+ return schemaTraits?.includes(self) ?? false;
210
+ }
211
+ function isArchivable(item, schemaTraits) {
212
+ const options = item.options;
213
+ const own = Array.isArray(options?.traits) ? options.traits : [];
214
+ for (const trait of own)
215
+ if (marked(trait))
216
+ return true;
217
+ if (options?.omitDefaults !== undefined)
218
+ return false;
219
+ if (schemaTraits === undefined)
220
+ return false;
221
+ for (const trait of schemaTraits)
222
+ if (marked(trait))
223
+ return true;
224
+ return false;
225
+ }
226
+ function marked(value) {
227
+ return value["~archive"] === true;
228
+ }
229
+ function nextOptions(options, indexes) {
230
+ const record = { ...options };
231
+ delete record.unique;
232
+ if (indexes !== undefined)
233
+ record.indexes = indexes;
234
+ return record;
235
+ }
236
+ function partialIndex(columns, predicate) {
237
+ return {
238
+ columns,
239
+ isUnique: true,
240
+ predicate,
241
+ unique() {
242
+ return partialIndex(columns, predicate);
243
+ }
244
+ };
245
+ }
246
+ function primaryFields(item) {
247
+ const listed = item.options?.primaryKey;
248
+ if (listed !== undefined && listed.length > 0)
249
+ return [...listed];
250
+ const fields = [];
251
+ for (const [field, builder] of Object.entries(item.columns)) {
252
+ if (builder instanceof ColumnBuilder2 && builder.state.primaryKey === true)
253
+ fields.push(field);
254
+ }
255
+ return fields;
256
+ }
257
+ function fieldSql(field, builder, casing) {
258
+ if (builder instanceof ColumnBuilder2 && builder.state.sqlName !== undefined)
259
+ return builder.state.sqlName;
260
+ return casing === "snake" ? snakeCase(field) : field;
261
+ }
262
+ function tableSql(item, casing) {
263
+ const named = item.options?.sqlName;
264
+ return named ?? (casing === "snake" ? snakeCase(item.name) : item.name);
265
+ }
266
+ function list(names) {
267
+ return names.join(", ");
268
+ }
269
+
270
+ // src/dialects/pg/fn/touch.ts
271
+ function timestampRecords(built) {
272
+ const columns = updatedColumns(built);
273
+ if (columns.length === 0)
274
+ return [];
275
+ const namespace = staticNamespace2("public");
276
+ const byColumn = new Map;
277
+ for (const column of columns) {
278
+ const list = byColumn.get(column.name) ?? [];
279
+ list.push(column.parent);
280
+ byColumn.set(column.name, list);
281
+ }
282
+ const records = [];
283
+ for (const [column, tables] of byColumn) {
284
+ const name = fitIdentifier2(`okm_touch_${column}`);
285
+ const present = hasFunction(built, name) || records.some((object) => object.kind === "function" && object.identity.name === name);
286
+ if (!present) {
287
+ records.push(functionObject({
288
+ namespace,
289
+ name,
290
+ returns: "trigger",
291
+ language: "plpgsql",
292
+ volatility: "volatile",
293
+ body: `begin new.${quoteIdent(column)} = now(); return new; end`,
294
+ provenance: { origin: "trait", name: "timestamps" },
295
+ dependencies: []
296
+ }));
297
+ }
298
+ for (const parent of tables) {
299
+ const triggerName = fitIdentifier2(`${parent.name}_touch`);
300
+ if (hasTrigger(built, parent.name, triggerName))
301
+ continue;
302
+ if (records.some((object) => object.kind === "trigger" && object.identity.name === triggerName && object.identity.parent.name === parent.name)) {
303
+ continue;
304
+ }
305
+ records.push(triggerObject({
306
+ parent,
307
+ name: triggerName,
308
+ timing: "before",
309
+ events: ["update"],
310
+ level: "row",
311
+ calls: { namespace, name, argTypes: [] },
312
+ provenance: { origin: "trait", name: "timestamps" }
313
+ }));
314
+ }
315
+ }
316
+ return records;
317
+ }
318
+ function updatedColumns(built) {
319
+ if (!Array.isArray(built))
320
+ return [];
321
+ const found = [];
322
+ for (const object of built) {
323
+ if (typeof object !== "object" || object === null)
324
+ continue;
325
+ if (!("kind" in object) || object.kind !== "column")
326
+ continue;
327
+ if (!("provenance" in object) || !("identity" in object))
328
+ continue;
329
+ const provenance = object.provenance;
330
+ const identity = object.identity;
331
+ if (typeof provenance !== "object" || provenance === null)
332
+ continue;
333
+ if (typeof identity !== "object" || identity === null)
334
+ continue;
335
+ if (!("origin" in provenance) || provenance.origin !== "trait")
336
+ continue;
337
+ if (!("name" in provenance) || provenance.name !== "timestamps")
338
+ continue;
339
+ if (!("name" in identity) || identity.name !== "updated_at" && identity.name !== "updatedAt")
340
+ continue;
341
+ if (!("parent" in identity) || typeof identity.parent !== "object" || identity.parent === null)
342
+ continue;
343
+ const parent = identity.parent;
344
+ if (!("name" in parent) || typeof parent.name !== "string")
345
+ continue;
346
+ if (!("namespace" in parent) || typeof parent.namespace !== "object" || parent.namespace === null)
347
+ continue;
348
+ const namespace = parent.namespace;
349
+ if (!("form" in namespace) || namespace.form !== "static")
350
+ continue;
351
+ if (!("name" in namespace) || typeof namespace.name !== "string")
352
+ continue;
353
+ found.push({
354
+ parent: { namespace: staticNamespace2(namespace.name), name: parent.name },
355
+ name: identity.name
356
+ });
357
+ }
358
+ return found;
359
+ }
360
+ function hasFunction(built, name) {
361
+ return named(built, "function", name);
362
+ }
363
+ function hasTrigger(built, table, name) {
364
+ if (!Array.isArray(built))
365
+ return false;
366
+ return built.some((object) => {
367
+ if (!isNamed(object, "trigger", name))
368
+ return false;
369
+ const identity = object.identity;
370
+ return typeof identity === "object" && identity !== null && "parent" in identity && typeof identity.parent === "object" && identity.parent !== null && "name" in identity.parent && identity.parent.name === table;
371
+ });
372
+ }
373
+ function named(built, kind, name) {
374
+ if (!Array.isArray(built))
375
+ return false;
376
+ return built.some((object) => isNamed(object, kind, name));
377
+ }
378
+ function isNamed(object, kind, name) {
379
+ if (typeof object !== "object" || object === null)
380
+ return false;
381
+ if (!("kind" in object) || object.kind !== kind)
382
+ return false;
383
+ if (!("identity" in object) || typeof object.identity !== "object" || object.identity === null)
384
+ return false;
385
+ return "name" in object.identity && object.identity.name === name;
386
+ }
387
+
388
+ // src/runtime/archive-rules.ts
389
+ function installArchiveContributions() {
390
+ installArchiveInspect(archiveContributions);
391
+ }
392
+ function archiveContributions(model, view) {
393
+ const archive = model?.archive;
394
+ if (archive === undefined)
395
+ return;
396
+ const rules = [
397
+ view === "with" ? { rule: "archive", contribution: "with archived", provenance: "caller" } : view === "only" ? { rule: "archive", contribution: "only archived", provenance: "caller" } : { rule: "archive", contribution: "active set", provenance: "planner" }
398
+ ];
399
+ for (const child of archive.cascade) {
400
+ rules.push({
401
+ rule: "archive",
402
+ contribution: `cascade ${child.table}`,
403
+ provenance: "catalog"
404
+ });
405
+ }
406
+ return rules;
407
+ }
408
+
409
+ // src/runtime/archive-handle.ts
410
+ function attachArchive(target, ctx) {
411
+ const table = ctx.table;
412
+ const reopen = ctx.reopen;
413
+ const session = ctx.session;
414
+ if (table === undefined || reopen === undefined || session === undefined)
415
+ return;
416
+ const host = session;
417
+ const mods = { uses: ctx.uses };
418
+ target.archive = (input, options = {}) => lifecycle(host, "archive", table, input, options, mods);
419
+ target.restore = (input, options = {}) => lifecycle(host, "restore", table, input, options, mods);
420
+ target.withArchived = () => {
421
+ refuse(host, table);
422
+ return reopen("with");
423
+ };
424
+ target.onlyArchived = () => {
425
+ refuse(host, table);
426
+ return reopen("only");
427
+ };
428
+ }
429
+ function lifecycle(host, op, table, input, options, mods) {
430
+ refuse(host, table);
431
+ return queryHandle(() => run(host, op, table, input, options, mods), {
432
+ "~plan": async () => {
433
+ await host.connected;
434
+ const [mod, planned] = await Promise.all([loadArchive(), settle(host, table, mods)]);
435
+ try {
436
+ return mod.prepareArchive(host.schema, op, table, input, options, planned, host.scope);
437
+ } catch (error) {
438
+ return settleCall(host, error);
439
+ }
440
+ },
441
+ sql() {
442
+ return Promise.all([loadArchive(), settle(host, table, mods)]).then(([mod, planned]) => mod.explainArchive(host.schema, op, table, input, options, planned, host.scope));
443
+ },
444
+ expect(count) {
445
+ return lifecycle(host, op, table, input, options, { ...mods, expect: count });
446
+ },
447
+ all(reason) {
448
+ return lifecycle(host, op, table, input, options, { ...mods, all: reason });
449
+ }
450
+ });
451
+ }
452
+ function refuse(host, table) {
453
+ if (host.schema.model[table]?.archive !== undefined)
454
+ return;
455
+ throw attachHttp(host.http, new OkmError2("OKM1052", `Table ${table} is not archivable.`, {
456
+ fix: { summary: "Call archive and restore only on an archivable table." }
457
+ }));
458
+ }
459
+ var archiveMod;
460
+ function loadArchive() {
461
+ archiveMod ??= import("../../shared/m9tv7xn7.js");
462
+ return archiveMod;
463
+ }
464
+ async function settle(host, table, mods) {
465
+ if (mods.uses === undefined)
466
+ return mods;
467
+ const { resolve } = await import("../../shared/r6nwkxnt.js");
468
+ return { ...mods, presets: resolve(host.schema, table, mods.uses).wheres };
469
+ }
470
+ async function run(host, op, table, input, options, mods) {
471
+ await host.connected;
472
+ const mod = await loadArchive();
473
+ try {
474
+ return await mod.executeArchive(host, op, table, input, options, await settle(host, table, mods), host.scope);
475
+ } catch (error) {
476
+ return settleCall(host, error);
477
+ }
478
+ }
479
+
480
+ // src/runtime/traits/index.ts
481
+ function trait(name, input) {
482
+ if (input.presets !== undefined)
483
+ checkPresetNames(Object.keys(input.presets), `trait ${name}`);
484
+ if (input.methods !== undefined) {
485
+ unavailable("Trait option methods is not available yet. It arrives in 0.2.");
486
+ }
487
+ if (input.requires !== undefined) {
488
+ unavailable("Trait option requires is not available yet. It arrives in 0.2.");
489
+ }
490
+ const checked = checkTrait({
491
+ name,
492
+ fields: input.fields,
493
+ ...input.touch !== undefined ? { touch: input.touch } : {},
494
+ ...input.sealed !== undefined ? { sealed: input.sealed } : {}
495
+ }, `trait(${name})`);
496
+ markFields(checked.fields, name);
497
+ const sealed = sealTouch(checked.sealed, checked.touch);
498
+ return {
499
+ name,
500
+ fields: checked.fields,
501
+ ...checked.touch !== undefined ? { touch: checked.touch } : {},
502
+ ...sealed !== undefined ? { sealed } : {},
503
+ ...input.presets !== undefined ? { presets: input.presets } : {},
504
+ apply(model, ctx) {
505
+ addFields(name, checked.fields, model, ctx);
506
+ if (input.presets !== undefined)
507
+ addPresets(name, input.presets, model, ctx);
508
+ },
509
+ contribute() {
510
+ return [];
511
+ }
512
+ };
513
+ }
514
+ function addPresets(name, presets, model, ctx) {
515
+ const merged = model.presets = { ...model.presets };
516
+ const from = model.presetFrom ??= {};
517
+ for (const key of Object.keys(presets)) {
518
+ if (Object.hasOwn(merged, key)) {
519
+ const first = from[key];
520
+ duplicatePreset(key, ctx.table, first === undefined ? `table ${ctx.table}` : `trait ${first}`, `trait ${name}`);
521
+ }
522
+ merged[key] = presets[key];
523
+ from[key] = name;
524
+ }
525
+ }
526
+ function timestamps(options) {
527
+ if (options !== undefined) {
528
+ for (const key of Object.keys(options)) {
529
+ if (key !== "enforce") {
530
+ definition(`timestamps() option ${key} is not supported. Accepted options: enforce.`);
531
+ }
532
+ }
533
+ if (options.enforce !== undefined && options.enforce !== "trigger") {
534
+ definition(`timestamps() enforce ${String(options.enforce)} must be trigger.`);
535
+ }
536
+ }
537
+ const base = trait("timestamps", {
538
+ fields: {
539
+ createdAt: stamped(),
540
+ updatedAt: stamped()
541
+ },
542
+ touch: ["updatedAt"],
543
+ sealed: ["createdAt", "updatedAt"]
544
+ });
545
+ if (options?.enforce !== "trigger")
546
+ return base;
547
+ return {
548
+ ...base,
549
+ contribute(_peers, built) {
550
+ return timestampRecords(built);
551
+ }
552
+ };
553
+ }
554
+ function stamped() {
555
+ return timestamptz2().defaultSql("now()").guarded();
556
+ }
557
+ function archivable(options) {
558
+ installArchiveContributions();
559
+ const cascade = readCascade(options);
560
+ const base = trait("archivable", {
561
+ fields: {
562
+ archivedAt: timestamptz2().nullable().guarded(),
563
+ archiveId: uuid2().nullable().guarded()
564
+ },
565
+ sealed: ["archivedAt", "archiveId"]
566
+ });
567
+ const self = {
568
+ ...base,
569
+ "~archive": true,
570
+ apply(model, ctx) {
571
+ base.apply(model, ctx);
572
+ model.archive = { at: "archivedAt", id: "archiveId", cascade };
573
+ },
574
+ rewrite(tables, casing, schemaTraits) {
575
+ return rewriteArchivable(self, tables, casing, schemaTraits, cascade);
576
+ },
577
+ hook: attachArchive
578
+ };
579
+ return self;
580
+ }
581
+ function readCascade(options) {
582
+ if (options === undefined)
583
+ return [];
584
+ for (const key of Object.keys(options)) {
585
+ if (key !== "strategy" && key !== "cascade") {
586
+ definition(`archivable() option ${key} is not supported. Accepted options: strategy, cascade.`);
587
+ }
588
+ }
589
+ if (options.strategy === "table") {
590
+ unavailable('archivable({ strategy: "table" }) is not available yet. It arrives once archived snapshots can follow migrations.');
591
+ }
592
+ if (options.strategy !== undefined && options.strategy !== "column") {
593
+ definition(`archivable() strategy ${String(options.strategy)} must be column.`);
594
+ }
595
+ const cascade = options.cascade;
596
+ if (cascade === undefined)
597
+ return [];
598
+ if (!Array.isArray(cascade))
599
+ definition("archivable() cascade must be a list of table names.");
600
+ const names = [];
601
+ for (const name of cascade) {
602
+ if (typeof name !== "string" || name.length === 0) {
603
+ definition("archivable() cascade must name tables.");
604
+ }
605
+ names.push(name);
606
+ }
607
+ return names;
608
+ }
609
+ function markFields(fields, name) {
610
+ for (const field of Object.keys(fields)) {
611
+ const builder = fields[field];
612
+ if (typeof builder === "object" && builder !== null)
613
+ Object.assign(builder, { trait: name });
614
+ }
615
+ }
616
+ function sealTouch(sealed, touch) {
617
+ if (touch === undefined)
618
+ return sealed;
619
+ if (sealed === undefined)
620
+ return touch;
621
+ const names = [...sealed];
622
+ for (const field of touch)
623
+ if (!names.includes(field))
624
+ names.push(field);
625
+ return names;
626
+ }
627
+ function addFields(name, fields, model, ctx) {
628
+ for (const field of Object.keys(fields)) {
629
+ const builder = fields[field];
630
+ if (builder === undefined)
631
+ continue;
632
+ if (Object.hasOwn(model.columns, field)) {
633
+ const previous = model.columns[field].trait;
634
+ const which = typeof previous === "string" ? `trait ${previous} already adds it` : `${ctx.table} already declares it`;
635
+ throw new OkmError2("OKM1012", `Trait ${name} adds ${ctx.table}.${field}, and ${which}.`, {
636
+ fix: { summary: "Rename the table field or drop one of the traits." }
637
+ });
638
+ }
639
+ model.columns[field] = builder;
640
+ }
641
+ }
642
+ export {
643
+ archivable,
644
+ timestamps,
645
+ trait
646
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public `tx()` (spec §15, §15.2).
3
+ *
4
+ * One transaction reserves one connection of the primary. Every statement of
5
+ * the callback, its savepoints, and its batches run on that connection, and it
6
+ * goes back to the pool at commit, rollback, or cancellation. The callback gets
7
+ * a client built on a pool that is a facade over that connection, so reads,
8
+ * writes, includes, presets, tenancy, and archive handling are the ones the
9
+ * caller's client already has. Loaded the first time `tx()` is called.
10
+ */
11
+ import { type Session } from "./client.js";
12
+ /**
13
+ * Runs `fn` in a transaction, or in a savepoint when one is already open.
14
+ *
15
+ * @param session - Client session
16
+ * @param args - `[fn]` or `[options, fn]`
17
+ * @returns What `fn` returned
18
+ */
19
+ export declare function tx(session: Session, args: readonly unknown[]): Promise<unknown>;