@sequenceholdings/orm 0.1.3 → 2.1.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 (59) hide show
  1. package/README.md +108 -38
  2. package/dist/authoring.cjs +128 -16
  3. package/dist/authoring.cjs.map +1 -1
  4. package/dist/authoring.d.cts +21 -4
  5. package/dist/authoring.d.ts +21 -4
  6. package/dist/authoring.js +128 -16
  7. package/dist/authoring.js.map +1 -1
  8. package/dist/canonical.cjs +83 -9
  9. package/dist/canonical.cjs.map +1 -1
  10. package/dist/canonical.d.cts +47 -1
  11. package/dist/canonical.d.ts +47 -1
  12. package/dist/canonical.js +83 -10
  13. package/dist/canonical.js.map +1 -1
  14. package/dist/cli.cjs +816 -134
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.js +818 -136
  17. package/dist/cli.js.map +1 -1
  18. package/dist/client.cjs.map +1 -1
  19. package/dist/client.js.map +1 -1
  20. package/dist/compiler.cjs +488 -96
  21. package/dist/compiler.cjs.map +1 -1
  22. package/dist/compiler.d.cts +34 -2
  23. package/dist/compiler.d.ts +34 -2
  24. package/dist/compiler.js +489 -97
  25. package/dist/compiler.js.map +1 -1
  26. package/dist/index.cjs +420 -71
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +266 -9
  29. package/dist/index.d.ts +266 -9
  30. package/dist/index.js +410 -73
  31. package/dist/index.js.map +1 -1
  32. package/dist/ir.cjs +146 -12
  33. package/dist/ir.cjs.map +1 -1
  34. package/dist/ir.d.cts +161 -5
  35. package/dist/ir.d.ts +161 -5
  36. package/dist/ir.js +144 -13
  37. package/dist/ir.js.map +1 -1
  38. package/dist/{naming-CTvWSRTf.d.ts → naming-DCn94LJ4.d.ts} +15 -1
  39. package/dist/{naming-DRyinU4u.d.cts → naming-DPglwzkB.d.cts} +15 -1
  40. package/dist/predicate-v2.cjs +136 -11
  41. package/dist/predicate-v2.cjs.map +1 -1
  42. package/dist/predicate-v2.d.cts +3 -0
  43. package/dist/predicate-v2.d.ts +3 -0
  44. package/dist/predicate-v2.js +136 -11
  45. package/dist/predicate-v2.js.map +1 -1
  46. package/dist/sdl.cjs +460 -13
  47. package/dist/sdl.cjs.map +1 -1
  48. package/dist/sdl.d.cts +1 -1
  49. package/dist/sdl.d.ts +1 -1
  50. package/dist/sdl.js +459 -14
  51. package/dist/sdl.js.map +1 -1
  52. package/package.json +6 -4
  53. package/src/codegen-gql/preset.cjs +64 -0
  54. package/src/codegen-gql/server-fns.cjs +11 -6
  55. package/templates/orm-namespace/codegen.preset.cjs +17 -0
  56. package/templates/orm-namespace/codegen.ts +1 -1
  57. package/templates/orm-namespace/package.json +3 -0
  58. package/templates/orm-namespace/schema/tables.ts +1 -1
  59. package/templates/orm-namespace/sequence.config.ts +1 -1
package/dist/index.cjs CHANGED
@@ -36,6 +36,7 @@ var ColumnBuilder = class {
36
36
  hasDefault: false,
37
37
  defaultValue: void 0,
38
38
  defaultFn: void 0,
39
+ onUpdateFn: void 0,
39
40
  description: void 0,
40
41
  renamedFrom: void 0,
41
42
  cast: void 0,
@@ -71,6 +72,15 @@ var ColumnBuilder = class {
71
72
  this.state.defaultFn = void 0;
72
73
  return this;
73
74
  }
75
+ /**
76
+ * Stamp this column with Postgres `now()` on every UPDATE. Only valid on
77
+ * timestamptz/date; the compiler drops it from SetInput so callers cannot
78
+ * supply a value.
79
+ */
80
+ onUpdate(value) {
81
+ this.state.onUpdateFn = value;
82
+ return this;
83
+ }
74
84
  description(text4) {
75
85
  this.state.description = text4;
76
86
  return this;
@@ -114,6 +124,7 @@ var ColumnBuilder = class {
114
124
  };
115
125
  if (this.state.hasDefault) column.default = this.state.defaultValue ?? null;
116
126
  if (this.state.defaultFn !== void 0) column.defaultFn = this.state.defaultFn;
127
+ if (this.state.onUpdateFn !== void 0) column.onUpdateFn = this.state.onUpdateFn;
117
128
  if (this.state.description !== void 0) column.description = this.state.description;
118
129
  if (this.state.renamedFrom !== void 0) column.renamedFrom = this.state.renamedFrom;
119
130
  if (this.state.cast !== void 0) column.cast = this.state.cast;
@@ -141,6 +152,7 @@ var t = {
141
152
  // src/constants.ts
142
153
  var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
143
154
  var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
155
+ var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
144
156
  var MAX_IDENTIFIER_LENGTH = 63;
145
157
  var ORM_DATA_TOKEN_HEADER = "x-sequence-data-token";
146
158
  var ORM_SERVICE_DATA_TOKEN_HEADER = "x-sequence-data-token-service";
@@ -156,6 +168,8 @@ var DEFINITION_FILE_EXTENSIONS = [".yml", ".yaml"];
156
168
  var NAMESPACE_CONFIG_FILENAMES = /* @__PURE__ */ new Set(["namespace.yaml", "namespace.yml"]);
157
169
  var HASH_DOMAIN = "sequence-orm-definitions\0";
158
170
  var MAX_DEFINITION_FILE_BYTES = 1024 * 1024;
171
+ var MAX_GENERATED_SDL_BYTES = 16 * 1024 * 1024;
172
+ var ORM_REGISTRATION_MAX_BYTES = 64 * 1024 * 1024;
159
173
  var RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set(["actions", "query"]);
160
174
  var RESERVED_COLUMN_NAMES = /* @__PURE__ */ new Set(["select", "order", "limit", "offset"]);
161
175
 
@@ -264,10 +278,10 @@ function isSeqLink(value) {
264
278
  function isSeqTable(value) {
265
279
  return typeof value === "object" && value !== null && value.kind === TABLE_BRAND;
266
280
  }
267
- function assertIdentifier({ value, what, file }) {
268
- if (!IDENTIFIER_PATTERN.test(value) || value.length > MAX_IDENTIFIER_LENGTH) {
281
+ function assertIdentifier({ value, what, file, pattern = IDENTIFIER_PATTERN }) {
282
+ if (!pattern.test(value) || value.length > MAX_IDENTIFIER_LENGTH) {
269
283
  throw new OrmDefinitionError(
270
- `${what} "${value}" must match ${IDENTIFIER_PATTERN} and be at most ${MAX_IDENTIFIER_LENGTH} characters`,
284
+ `${what} "${value}" must match ${pattern} and be at most ${MAX_IDENTIFIER_LENGTH} characters`,
271
285
  file
272
286
  );
273
287
  }
@@ -288,7 +302,7 @@ function defineTable(name, columns, config = {}) {
288
302
  );
289
303
  }
290
304
  const columnName = builder.columnNameFor(propertyName);
291
- assertIdentifier({ value: columnName, what: `table "${name}": column "${propertyName}" column name`, file });
305
+ assertIdentifier({ value: columnName, what: `table "${name}": column "${propertyName}" column name`, file, pattern: COLUMN_IDENTIFIER_PATTERN });
292
306
  const existing = seenColumnNames.get(columnName);
293
307
  if (existing !== void 0) {
294
308
  throw new OrmDefinitionError(
@@ -328,7 +342,8 @@ function defineSyncedTable(name, columnsOrConfig, maybeConfig) {
328
342
  assertIdentifier({
329
343
  value: columnName,
330
344
  what: `synced table "${name}": column "${propertyName}" column name`,
331
- file
345
+ file,
346
+ pattern: COLUMN_IDENTIFIER_PATTERN
332
347
  });
333
348
  const existing = seenColumnNames.get(columnName);
334
349
  if (existing !== void 0) {
@@ -417,7 +432,7 @@ function defineView(name, columns, config) {
417
432
  );
418
433
  }
419
434
  const columnName = builder.columnNameFor(propertyName);
420
- if (!IDENTIFIER_PATTERN.test(columnName) || columnName.length > MAX_IDENTIFIER_LENGTH) {
435
+ if (!COLUMN_IDENTIFIER_PATTERN.test(columnName) || columnName.length > MAX_IDENTIFIER_LENGTH) {
421
436
  throw new OrmDefinitionError(`view "${name}": column "${propertyName}" has invalid column name "${columnName}"`, file);
422
437
  }
423
438
  const existing = seenColumnNames.get(columnName);
@@ -866,6 +881,7 @@ function scalarColumnType(table, property, helper) {
866
881
  var CANONICAL_FORMAT = 2;
867
882
  var IDENTIFIER_RE = /^[a-z][a-z0-9_]*$/;
868
883
  var identifier = zod.z.string().min(1).max(63).regex(IDENTIFIER_RE);
884
+ var columnIdentifier = zod.z.string().min(1).max(63).regex(COLUMN_IDENTIFIER_PATTERN);
869
885
  var COLUMN_TYPES = [
870
886
  "uuid",
871
887
  "text",
@@ -886,18 +902,33 @@ var canonicalEnumSchema = zod.z.object({
886
902
  var canonicalColumnSchema = zod.z.object({
887
903
  /** Property name in TS (camelCase); columnName is the Postgres name. */
888
904
  name: zod.z.string().min(1).max(63),
889
- columnName: identifier,
905
+ columnName: columnIdentifier,
890
906
  type: zod.z.union([columnTypeSchema, zod.z.object({ enum: identifier })]),
891
907
  nullable: zod.z.boolean().default(true),
892
908
  unique: zod.z.boolean().default(false),
893
909
  /** Literal default, or one of the allowlisted SQL functions. */
894
910
  default: zod.z.union([zod.z.string(), zod.z.number(), zod.z.boolean(), zod.z.null()]).optional(),
895
911
  defaultFn: zod.z.enum(["gen_random_uuid()", "now()"]).optional(),
912
+ /**
913
+ * Stamp this column from the database clock on UPDATE (`now()`). The
914
+ * column stays insertable (defaults fill gaps) but is omitted from
915
+ * SetInput / settable so callers cannot backdate it.
916
+ */
917
+ onUpdateFn: zod.z.enum(["now()"]).optional(),
896
918
  description: zod.z.string().max(500).optional(),
897
919
  /** Migration hints — same semantics as v1. */
898
- renamedFrom: identifier.optional(),
920
+ renamedFrom: columnIdentifier.optional(),
899
921
  cast: zod.z.string().max(200).optional(),
900
922
  deprecated: zod.z.boolean().default(false)
923
+ }).superRefine((column, ctx) => {
924
+ if (column.onUpdateFn === void 0) return;
925
+ if (typeof column.type !== "string" || column.type !== "timestamptz" && column.type !== "date") {
926
+ ctx.addIssue({
927
+ code: "custom",
928
+ path: ["onUpdateFn"],
929
+ message: `onUpdateFn '${column.onUpdateFn}' is only valid on timestamptz/date columns`
930
+ });
931
+ }
901
932
  });
902
933
  var canonicalLinkSchema = zod.z.object({
903
934
  name: zod.z.string().min(1).max(63),
@@ -905,15 +936,15 @@ var canonicalLinkSchema = zod.z.object({
905
936
  /** Target table name (namespace-local). Absent for toPlatformUser. */
906
937
  target: identifier.optional(),
907
938
  /** FK column on the owning side (toOne/toPlatformUser: on this table; toMany: on the target). */
908
- on: identifier,
939
+ on: columnIdentifier,
909
940
  /** Referenced column on the target (default: target's PK / platform user `sub`). */
910
- references: identifier.optional(),
941
+ references: columnIdentifier.optional(),
911
942
  /** enforce: true emits a real FK constraint (same-namespace toOne only). */
912
943
  enforce: zod.z.boolean().default(false),
913
944
  description: zod.z.string().max(500).optional()
914
945
  });
915
946
  var canonicalIndexSchema = zod.z.object({
916
- columns: zod.z.array(identifier).min(1),
947
+ columns: zod.z.array(columnIdentifier).min(1),
917
948
  unique: zod.z.boolean().default(false),
918
949
  name: identifier.optional()
919
950
  });
@@ -1161,6 +1192,13 @@ var canonicalCowMutationSchema = zod.z.object({
1161
1192
  }
1162
1193
  }
1163
1194
  });
1195
+ var canonicalForeignKeySchema = zod.z.object({
1196
+ name: identifier,
1197
+ columns: zod.z.array(columnIdentifier).min(1).max(8),
1198
+ target: identifier,
1199
+ references: zod.z.array(columnIdentifier).min(1).max(8),
1200
+ deferrable: zod.z.enum(["initially-immediate", "initially-deferred"]).optional()
1201
+ }).strict();
1164
1202
  var canonicalTableSchema = zod.z.object({
1165
1203
  table: identifier,
1166
1204
  description: zod.z.string().max(2e3).optional(),
@@ -1169,7 +1207,7 @@ var canonicalTableSchema = zod.z.object({
1169
1207
  /** Synced/reflected read-only tables (`source: gold.*`) — v1 semantics. */
1170
1208
  source: zod.z.string().regex(/^gold\.[a-z][a-z0-9_]*$/).optional(),
1171
1209
  columns: zod.z.array(canonicalColumnSchema).default([]),
1172
- primaryKey: zod.z.array(identifier).min(1).max(8).optional(),
1210
+ primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
1173
1211
  links: zod.z.array(canonicalLinkSchema).default([]),
1174
1212
  indexes: zod.z.array(canonicalIndexSchema).default([]),
1175
1213
  policies: canonicalPoliciesSchema.default({}),
@@ -1180,14 +1218,16 @@ var canonicalTableSchema = zod.z.object({
1180
1218
  */
1181
1219
  actions: zod.z.array(canonicalActionSchema).default([]),
1182
1220
  /** Optional (not defaulted) so pre-CoW canonical documents keep byte-identical hashes. */
1183
- cowMutations: zod.z.array(canonicalCowMutationSchema).optional()
1221
+ cowMutations: zod.z.array(canonicalCowMutationSchema).optional(),
1222
+ /** Omitted by old definitions, preserving their existing content hashes. */
1223
+ foreignKeys: zod.z.array(canonicalForeignKeySchema).max(100).optional()
1184
1224
  });
1185
1225
  var canonicalViewSchema = zod.z.object({
1186
1226
  view: identifier,
1187
1227
  description: zod.z.string().max(2e3).optional(),
1188
1228
  columns: zod.z.array(canonicalColumnSchema).min(1),
1189
1229
  /** Logical identity for GraphQL only; PostgreSQL views have no PK constraint. */
1190
- primaryKey: zod.z.array(identifier).min(1).max(8).optional(),
1230
+ primaryKey: zod.z.array(columnIdentifier).min(1).max(8).optional(),
1191
1231
  links: zod.z.array(canonicalLinkSchema).default([]),
1192
1232
  policies: zod.z.object({ read: policyExpressionSchema }).strict(),
1193
1233
  query: zod.z.string().min(1).max(1e5).refine(isSingleViewQuerySql, {
@@ -1200,6 +1240,9 @@ var canonicalViewSchema = zod.z.object({
1200
1240
  if (column.default !== void 0 || column.defaultFn !== void 0) {
1201
1241
  ctx.addIssue({ code: "custom", path: ["columns", index3], message: `view column '${column.name}' cannot declare a default` });
1202
1242
  }
1243
+ if (column.onUpdateFn !== void 0) {
1244
+ ctx.addIssue({ code: "custom", path: ["columns", index3], message: `view column '${column.name}' cannot declare onUpdateFn` });
1245
+ }
1203
1246
  if (column.unique) {
1204
1247
  ctx.addIssue({ code: "custom", path: ["columns", index3], message: `view column '${column.name}' cannot declare unique` });
1205
1248
  }
@@ -1233,6 +1276,45 @@ var canonicalDefinitionSchema = zod.z.object({
1233
1276
  ctx.addIssue({ code: "custom", path: ["tables", index3, "table"], message: `duplicate relation '${table.table}'` });
1234
1277
  }
1235
1278
  seen.add(table.table);
1279
+ if (table.source !== void 0) {
1280
+ for (const [columnIndex, column] of table.columns.entries()) {
1281
+ if (column.onUpdateFn !== void 0) {
1282
+ ctx.addIssue({
1283
+ code: "custom",
1284
+ path: ["tables", index3, "columns", columnIndex],
1285
+ message: `synced table '${table.table}' column '${column.name}' cannot declare onUpdateFn`
1286
+ });
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+ const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
1292
+ for (const [tableIndex, table] of definition.tables.entries()) {
1293
+ const names = /* @__PURE__ */ new Set([
1294
+ ...table.primaryKey?.length ? [`${table.table}_pkey`] : [],
1295
+ ...table.columns.filter((column) => column.unique && !(table.primaryKey?.length === 1 && table.primaryKey[0] === column.columnName)).map((column) => `${table.table}_${column.columnName}_unique`),
1296
+ ...table.links.filter((link) => link.enforce).map((link) => `fk_${table.table}_${link.name}`)
1297
+ ]);
1298
+ for (const [index3, fk] of (table.foreignKeys ?? []).entries()) {
1299
+ const fail = (message) => ctx.addIssue({ code: "custom", path: ["tables", tableIndex, "foreignKeys", index3], message });
1300
+ if (names.has(fk.name)) fail(`duplicate foreign key '${fk.name}'`);
1301
+ names.add(fk.name);
1302
+ const target = fkTables.get(fk.target);
1303
+ if (table.source || !target || target.source) {
1304
+ fail("foreign keys must connect owned tables in the same namespace");
1305
+ continue;
1306
+ }
1307
+ if (fk.columns.length !== fk.references.length) fail("foreign key columns and references must have the same number of columns");
1308
+ if (new Set(fk.columns).size !== fk.columns.length || new Set(fk.references).size !== fk.references.length) fail("foreign key columns must not repeat");
1309
+ for (const [position, name] of fk.columns.entries()) {
1310
+ const sourceColumn = table.columns.find((column) => column.columnName === name);
1311
+ const targetColumn = target.columns.find((column) => column.columnName === fk.references[position]);
1312
+ if (!sourceColumn || !targetColumn) fail("foreign key references an unknown column");
1313
+ else if (JSON.stringify(sourceColumn.type) !== JSON.stringify(targetColumn.type)) fail("foreign key column types must match");
1314
+ }
1315
+ const uniqueKeys = [target.primaryKey ?? [], ...target.indexes.filter((index4) => index4.unique).map((index4) => index4.columns), ...target.columns.filter((column) => column.unique).map((column) => [column.columnName])];
1316
+ if (!uniqueKeys.some((key) => key.length === fk.references.length && key.every((column) => fk.references.includes(column)))) fail("foreign key target columns must form a unique key");
1317
+ }
1236
1318
  }
1237
1319
  const tableByName = new Map(definition.tables.map((table) => [table.table, table]));
1238
1320
  for (const [tableIndex, table] of definition.tables.entries()) {
@@ -1368,12 +1450,13 @@ function normalizeCanonical(definition) {
1368
1450
  ...definition,
1369
1451
  enums: sortByName(definition.enums),
1370
1452
  tables: [...definition.tables].sort((a, b) => a.table.localeCompare(b.table)).map((t2) => {
1371
- const { cowMutations, ...rest } = t2;
1453
+ const { cowMutations, foreignKeys, ...rest } = t2;
1372
1454
  return {
1373
1455
  ...rest,
1374
1456
  links: sortByName(t2.links),
1375
1457
  indexes: [...t2.indexes].sort((a, b) => (a.name ?? a.columns.join("_")).localeCompare(b.name ?? b.columns.join("_"))),
1376
1458
  actions: sortByName(t2.actions),
1459
+ ...foreignKeys?.length ? { foreignKeys: sortByName(foreignKeys) } : {},
1377
1460
  // Omitted entirely when absent/empty so pre-CoW documents hash unchanged.
1378
1461
  ...cowMutations !== void 0 && cowMutations.length > 0 ? { cowMutations: sortByName(cowMutations) } : {}
1379
1462
  };
@@ -1647,6 +1730,22 @@ function buildCanonicalTable({ table, relationsByName, enumsByName }) {
1647
1730
  } else if (columnLevelPk.length > 0) {
1648
1731
  candidate.primaryKey = columnLevelPk;
1649
1732
  }
1733
+ if (table.config.foreignKeys?.length) {
1734
+ if (table.source) throw new OrmDefinitionError(`synced table "${table.tableName}" cannot enforce foreign keys`, table.file);
1735
+ candidate.foreignKeys = table.config.foreignKeys.map((fk) => {
1736
+ const target = resolveRelationRef({ ref: fk.target, fail: (message) => {
1737
+ throw new OrmDefinitionError(message, table.file);
1738
+ } });
1739
+ if (!isSeqTable(target) || !relationsByName.has(target.tableName)) throw new OrmDefinitionError("foreign key target must be a table in this namespace", table.file);
1740
+ return {
1741
+ name: fk.name,
1742
+ columns: fk.columns.map((ref) => resolveColumnRef({ relation: table, ref, role: `foreign key "${fk.name}" column` })),
1743
+ target: target.tableName,
1744
+ references: fk.references.map((ref) => resolveColumnRef({ relation: target, ref, role: `foreign key "${fk.name}" reference` })),
1745
+ ...fk.deferrable ? { deferrable: fk.deferrable } : {}
1746
+ };
1747
+ });
1748
+ }
1650
1749
  for (const index3 of table.config.indexes ?? []) {
1651
1750
  const entry = {
1652
1751
  columns: index3.columns.map((ref) => resolveColumnRef({ relation: table, ref, role: "index" }))
@@ -1699,6 +1798,12 @@ function buildCanonicalView({
1699
1798
  if (column.default !== void 0 || column.defaultFn !== void 0) {
1700
1799
  throw new OrmDefinitionError(`view "${view.viewName}": column "${propertyName}" cannot declare a default`, view.file);
1701
1800
  }
1801
+ if (column.onUpdateFn !== void 0) {
1802
+ throw new OrmDefinitionError(
1803
+ `view "${view.viewName}": column "${propertyName}" cannot declare onUpdateFn`,
1804
+ view.file
1805
+ );
1806
+ }
1702
1807
  if (column.unique) {
1703
1808
  throw new OrmDefinitionError(`view "${view.viewName}": column "${propertyName}" cannot declare unique`, view.file);
1704
1809
  }
@@ -1957,7 +2062,16 @@ async function loadNamespaceFromDir(dir, options = {}) {
1957
2062
  const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)), {
1958
2063
  interopDefault: true,
1959
2064
  fsCache: false,
1960
- ...options.ormModulePath !== void 0 ? { alias: { "@sequenceholdings/orm": options.ormModulePath } } : {}
2065
+ ...options.ormModulePath !== void 0 ? {
2066
+ alias: {
2067
+ // The public /drizzle barrel re-exports this pinned dependency.
2068
+ // Explicitly map it before the root alias: otherwise jiti appends
2069
+ // "/drizzle" to the overridden module's filename.
2070
+ "@sequenceholdings/orm/drizzle": module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))).resolve("drizzle-orm"),
2071
+ "@sequenceholdings/orm": options.ormModulePath,
2072
+ "@sequenceholdings/orm/authoring": options.ormModulePath
2073
+ }
2074
+ } : {}
1961
2075
  });
1962
2076
  const context = beginAuthoringContext();
1963
2077
  try {
@@ -2516,8 +2630,8 @@ var actionSchema = zod.z.strictObject({
2516
2630
  }
2517
2631
  }
2518
2632
  });
2519
- function extractNamedParams(sql4) {
2520
- const withoutStrings = sql4.replace(QUOTED_STRING_PATTERN, "''");
2633
+ function extractNamedParams(sql5) {
2634
+ const withoutStrings = sql5.replace(QUOTED_STRING_PATTERN, "''");
2521
2635
  const names = [...withoutStrings.matchAll(NAMED_PARAM_PATTERN)].map((match) => match[1]);
2522
2636
  return [...new Set(names)];
2523
2637
  }
@@ -2674,8 +2788,8 @@ var actionParamArg = (name) => `p_${name}`;
2674
2788
  function compileActionStatements(action, renderParam = actionParamArg) {
2675
2789
  return actionStatementSources(action.executes).map((statement) => compileStatement(statement, renderParam));
2676
2790
  }
2677
- function compileStatement(sql4, renderParam) {
2678
- const compiled = sql4.replace(TOKEN_PATTERN, (token, claimKey, capabilityKey, paramName) => {
2791
+ function compileStatement(sql5, renderParam) {
2792
+ const compiled = sql5.replace(TOKEN_PATTERN, (token, claimKey, capabilityKey, paramName) => {
2679
2793
  if (claimKey !== void 0) {
2680
2794
  if (!CLAIM_KEY_PATTERN.test(claimKey)) throw new OrmDefinitionError(`invalid claim key in executes: ${token}`);
2681
2795
  return claimExpression(claimKey);
@@ -2840,8 +2954,8 @@ function actionPrepareChecks(definition) {
2840
2954
  const order = actionParamOrder(action);
2841
2955
  const signature = order.length > 0 ? ` (${order.map((param) => sqlTypeName(action.params[param].type)).join(", ")})` : "";
2842
2956
  const compiled = compileActionStatements(action, (param) => `$${order.indexOf(param) + 1}`);
2843
- compiled.forEach((sql4, index3) => {
2844
- const checked = action.returns && index3 === compiled.length - 1 ? returnProjection(action.returns, sql4) : sql4;
2957
+ compiled.forEach((sql5, index3) => {
2958
+ const checked = action.returns && index3 === compiled.length - 1 ? returnProjection(action.returns, sql5) : sql5;
2845
2959
  statements.push(`PREPARE ${quoteIdentifier(`orm_check_${name}_${index3}`)}${signature} AS ${checked}`);
2846
2960
  });
2847
2961
  }
@@ -3295,7 +3409,8 @@ function syncedViewStatements({
3295
3409
  readPolicyIrByTable,
3296
3410
  columnNamesByTable,
3297
3411
  columnTypesByTable,
3298
- executionOwnerRole = SYNCED_VIEW_EXECUTION_OWNER_ROLE
3412
+ executionOwnerRole = SYNCED_VIEW_EXECUTION_OWNER_ROLE,
3413
+ backingPrivileges = "grant"
3299
3414
  }) {
3300
3415
  const schema = quoteIdentifier(ormSchemaName(definition.namespace));
3301
3416
  const role = quoteIdentifier(consumerRoleName(definition.namespace));
@@ -3329,8 +3444,10 @@ function syncedViewStatements({
3329
3444
  columnTypes,
3330
3445
  columnNames: columnNamesByTable?.get(table.table)
3331
3446
  })}` : readPolicy ? ` WHERE ${compilePredicate(readPolicy.ast, narrowToV1ColumnTypes(columnTypes))}` : " WHERE false";
3332
- statements.push(`GRANT USAGE ON SCHEMA ${quoteIdentifier(physical.schema)} TO ${owner}`);
3333
- statements.push(`GRANT SELECT ON ${physicalTarget} TO ${owner}`);
3447
+ if (backingPrivileges === "grant") {
3448
+ statements.push(`GRANT USAGE ON SCHEMA ${quoteIdentifier(physical.schema)} TO ${owner}`);
3449
+ statements.push(`GRANT SELECT ON ${physicalTarget} TO ${owner}`);
3450
+ }
3334
3451
  statements.push(
3335
3452
  `CREATE OR REPLACE VIEW ${viewName} AS SELECT * FROM ${physicalTarget}${whereClause}`
3336
3453
  );
@@ -3619,7 +3736,7 @@ var FACTORIES2 = {
3619
3736
  var SCHEMA_IMPORT_KEY2 = "$schema";
3620
3737
  var enumImportKey = (name) => `$enum_${name}`;
3621
3738
  var columnTablesV2 = (definition) => definition.tables.filter((table) => !table.source);
3622
- function buildDrizzleEntitiesV2(definition) {
3739
+ function buildDrizzleEntitiesV2(definition, options = {}) {
3623
3740
  const schemaName = ormSchemaName(definition.namespace);
3624
3741
  const schema = pgCore.pgSchema(schemaName);
3625
3742
  const imports = { [SCHEMA_IMPORT_KEY2]: schema };
@@ -3634,11 +3751,19 @@ function buildDrizzleEntitiesV2(definition) {
3634
3751
  }
3635
3752
  const byName = new Map(definition.tables.map((table) => [table.table, table]));
3636
3753
  for (const table of sortByEnforcedLinks2(columnTablesV2(definition))) {
3637
- const drizzleTable = buildTable2(schema, table, built, enums, byName);
3754
+ const drizzleTable = buildTable2(schema, table, built, enums, byName, options.introspection ?? false);
3638
3755
  built.set(table.table, drizzleTable);
3639
3756
  imports[table.table] = drizzleTable;
3640
3757
  tables[table.table] = drizzleTable;
3641
3758
  }
3759
+ if (options.introspection) {
3760
+ for (const table of definition.tables.filter((table2) => table2.source)) {
3761
+ const columns = Object.fromEntries(
3762
+ table.columns.map((column) => [column.columnName, buildViewColumnV2({ view: table.table, column, enums })])
3763
+ );
3764
+ imports[table.table] = schema.view(table.table, columns).existing();
3765
+ }
3766
+ }
3642
3767
  for (const view of definition.views ?? []) {
3643
3768
  const columns = Object.fromEntries(
3644
3769
  view.columns.map((column) => [column.columnName, buildViewColumnV2({ view: view.view, column, enums })])
@@ -3706,18 +3831,18 @@ function rewriteSyncedSourceRelationsInViewQuery({
3706
3831
  return rewritten;
3707
3832
  });
3708
3833
  }
3709
- function transformSqlOutsideLiterals(sql4, transform) {
3834
+ function transformSqlOutsideLiterals(sql5, transform) {
3710
3835
  const out = [];
3711
3836
  let state = { kind: "normal" };
3712
3837
  let i = 0;
3713
3838
  let codeStart = 0;
3714
3839
  const emitCode = (end) => {
3715
- if (end > codeStart) out.push(transform(sql4.slice(codeStart, end)));
3840
+ if (end > codeStart) out.push(transform(sql5.slice(codeStart, end)));
3716
3841
  codeStart = end;
3717
3842
  };
3718
- while (i < sql4.length) {
3719
- const c = sql4[i];
3720
- const next = i + 1 < sql4.length ? sql4[i + 1] : "";
3843
+ while (i < sql5.length) {
3844
+ const c = sql5[i];
3845
+ const next = i + 1 < sql5.length ? sql5[i + 1] : "";
3721
3846
  switch (state.kind) {
3722
3847
  case "normal": {
3723
3848
  if (c === "-" && next === "-") {
@@ -3737,7 +3862,7 @@ function transformSqlOutsideLiterals(sql4, transform) {
3737
3862
  break;
3738
3863
  }
3739
3864
  if ((c === "E" || c === "e") && next === "'") {
3740
- const prev = i > 0 ? sql4[i - 1] : "";
3865
+ const prev = i > 0 ? sql5[i - 1] : "";
3741
3866
  if (!/[A-Za-z0-9_]/.test(prev)) {
3742
3867
  emitCode(i);
3743
3868
  state = { kind: "e-single" };
@@ -3756,9 +3881,9 @@ function transformSqlOutsideLiterals(sql4, transform) {
3756
3881
  break;
3757
3882
  }
3758
3883
  if (c === "$") {
3759
- const prev = i > 0 ? sql4[i - 1] : "";
3884
+ const prev = i > 0 ? sql5[i - 1] : "";
3760
3885
  if (!/[A-Za-z0-9_$]/.test(prev)) {
3761
- const tagMatch = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/.exec(sql4.slice(i));
3886
+ const tagMatch = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/.exec(sql5.slice(i));
3762
3887
  if (tagMatch) {
3763
3888
  emitCode(i);
3764
3889
  state = { kind: "dollar", tag: tagMatch[1] ?? "" };
@@ -3790,8 +3915,8 @@ function transformSqlOutsideLiterals(sql4, transform) {
3790
3915
  break;
3791
3916
  }
3792
3917
  case "e-single": {
3793
- if (c === "\\" && i + 1 < sql4.length) {
3794
- out.push(c, sql4[i + 1]);
3918
+ if (c === "\\" && i + 1 < sql5.length) {
3919
+ out.push(c, sql5[i + 1]);
3795
3920
  i += 2;
3796
3921
  break;
3797
3922
  }
@@ -3813,7 +3938,7 @@ function transformSqlOutsideLiterals(sql4, transform) {
3813
3938
  }
3814
3939
  case "dollar": {
3815
3940
  const closer = `$${state.tag}$`;
3816
- if (sql4.startsWith(closer, i)) {
3941
+ if (sql5.startsWith(closer, i)) {
3817
3942
  out.push(closer);
3818
3943
  state = { kind: "normal" };
3819
3944
  i += closer.length;
@@ -3857,15 +3982,15 @@ function transformSqlOutsideLiterals(sql4, transform) {
3857
3982
  }
3858
3983
  }
3859
3984
  }
3860
- emitCode(sql4.length);
3985
+ emitCode(sql5.length);
3861
3986
  return out.join("");
3862
3987
  }
3863
3988
  function escapeRegExp(value) {
3864
3989
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3865
3990
  }
3866
- function sqlReferencesQualifiedRelation(sql4, sourceSchema, sourceName) {
3991
+ function sqlReferencesQualifiedRelation(sql5, sourceSchema, sourceName) {
3867
3992
  let referenced = false;
3868
- transformSqlOutsideLiterals(sql4, (segment) => {
3993
+ transformSqlOutsideLiterals(sql5, (segment) => {
3869
3994
  if (qualifiedRelationPattern(sourceSchema, sourceName).test(segment)) referenced = true;
3870
3995
  return segment;
3871
3996
  });
@@ -3876,15 +4001,16 @@ function qualifiedRelationPattern(sourceSchema, sourceName) {
3876
4001
  const namePattern = `(?:"${escapeRegExp(sourceName)}"|${escapeRegExp(sourceName)})`;
3877
4002
  return new RegExp(`(?<![\\w."])${schemaPattern}\\.${namePattern}(?![\\w"])`, "g");
3878
4003
  }
3879
- function replaceQualifiedRelation(sql4, sourceSchema, sourceName, boundSchema, boundTable) {
3880
- return sql4.replace(qualifiedRelationPattern(sourceSchema, sourceName), `"${boundSchema}"."${boundTable}"`);
4004
+ function replaceQualifiedRelation(sql5, sourceSchema, sourceName, boundSchema, boundTable) {
4005
+ return sql5.replace(qualifiedRelationPattern(sourceSchema, sourceName), `"${boundSchema}"."${boundTable}"`);
3881
4006
  }
3882
4007
  function generateSnapshotV2(definition, previousId3) {
3883
4008
  const { imports, schemaName } = buildDrizzleEntitiesV2(definition);
3884
4009
  const snapshot = api.generateDrizzleJson(imports, previousId3, [schemaName]);
3885
- if ((definition.views?.length ?? 0) > 0) {
4010
+ if ((definition.views?.length ?? 0) > 0 || definition.tables.some((table) => table.foreignKeys?.length)) {
3886
4011
  const extended = snapshot;
3887
4012
  extended._sequenceOrm = {
4013
+ ...definition.tables.some((table) => table.foreignKeys?.length) ? { foreignKeys: Object.fromEntries(definition.tables.flatMap((table) => (table.foreignKeys ?? []).map((fk) => [`${table.table}.${fk.name}`, structuredClone(fk)]))) } : {},
3888
4014
  viewDependencies: Object.fromEntries(
3889
4015
  (definition.views ?? []).map((view) => [view.view, [...view.dependencies].sort()])
3890
4016
  )
@@ -3902,7 +4028,7 @@ function buildViewColumnV2({
3902
4028
  if (!column.nullable) builder = builder.notNull();
3903
4029
  return builder;
3904
4030
  }
3905
- function buildTable2(schema, table, built, enums, byName) {
4031
+ function buildTable2(schema, table, built, enums, byName, introspection) {
3906
4032
  const primaryKeyColumns = table.primaryKey ?? [];
3907
4033
  if (primaryKeyColumns.length === 0) {
3908
4034
  throw new OrmDefinitionError(`table '${table.table}' declares no primaryKey`);
@@ -3918,13 +4044,22 @@ function buildTable2(schema, table, built, enums, byName) {
3918
4044
  const columns = Object.fromEntries(
3919
4045
  table.columns.map((column) => [
3920
4046
  column.columnName,
3921
- buildColumnV2({ table: table.table, column, singlePrimaryKey, compositeMembers, enums })
4047
+ buildColumnV2({ table: table.table, column, singlePrimaryKey, compositeMembers, enums, introspection })
3922
4048
  ])
3923
4049
  );
3924
4050
  const drizzleTable = schema.table(table.table, columns, (self) => [
3925
4051
  ...buildCompositePrimaryKey(table, primaryKeyColumns, self),
3926
4052
  ...buildIndexes2(table, self),
3927
- ...buildForeignKeys2(table, self, built, byName)
4053
+ ...buildForeignKeys2(table, self, built, byName),
4054
+ ...(table.foreignKeys ?? []).map((fk) => {
4055
+ const target = fk.target === table.table ? self : built.get(fk.target);
4056
+ if (!target) throw new OrmDefinitionError(`foreign key '${fk.name}' has no target '${fk.target}'`);
4057
+ return pgCore.foreignKey({
4058
+ name: fk.name,
4059
+ columns: fk.columns.map((column) => self[column]),
4060
+ foreignColumns: fk.references.map((column) => target[column])
4061
+ });
4062
+ })
3928
4063
  ]);
3929
4064
  return drizzleTable.enableRLS();
3930
4065
  }
@@ -3941,7 +4076,8 @@ function buildColumnV2({
3941
4076
  column,
3942
4077
  singlePrimaryKey,
3943
4078
  compositeMembers,
3944
- enums
4079
+ enums,
4080
+ introspection
3945
4081
  }) {
3946
4082
  const factory = resolveColumnFactory(table, column, enums);
3947
4083
  let builder = factory(column.columnName);
@@ -3962,7 +4098,7 @@ function buildColumnV2({
3962
4098
  }
3963
4099
  builder = builder.default(drizzleOrm.sql.raw(column.defaultFn));
3964
4100
  } else if (column.default !== void 0 && column.default !== null) {
3965
- builder = builder.default(column.default);
4101
+ builder = introspection && column.type === "jsonb" && typeof column.default === "string" ? builder.default(drizzleOrm.sql.raw(`${quoteLiteral(column.default)}::jsonb`)) : builder.default(column.default);
3966
4102
  }
3967
4103
  return builder;
3968
4104
  }
@@ -4147,7 +4283,8 @@ async function planMigrationV2({
4147
4283
  assertValidViewDependencies(canonical);
4148
4284
  const hints = applyMigrationHintsV2(previous, canonical);
4149
4285
  const snapshot = generateSnapshotV2(canonical, previousId(previous));
4150
- const baseDdl = await diffStatements(withoutViews(hints.adjusted), withoutViews(snapshot));
4286
+ const generatedBaseDdl = await diffStatements(withoutViews(hints.adjusted), withoutViews(snapshot));
4287
+ const baseDdl = orderForeignKeyAdditions(canonical, generatedBaseDdl);
4151
4288
  const previousViews = snapshotViews(hints.adjusted);
4152
4289
  const currentViews = snapshotViews(snapshot);
4153
4290
  const previousDependencies = snapshotViewDependencies(hints.adjusted);
@@ -4184,6 +4321,7 @@ async function planMigrationV2({
4184
4321
  ...dropOrder.map((name) => ({ kind: "ddl", sql: requiredViewStatement(dropDdl, name, schema, "DROP") })),
4185
4322
  ...hints.statements.map((statement) => ({ kind: "hint", sql: statement })),
4186
4323
  ...baseDdl.map((statement) => ({ kind: "ddl", sql: statement.replace(/;\s*$/, "") })),
4324
+ ...foreignKeyTimingStatements(canonical, previous, baseDdl).map((sql5) => ({ kind: "ddl", sql: sql5 })),
4187
4325
  ...createOrder.map((name) => ({ kind: "ddl", sql: requiredViewStatement(createDdl, name, schema, "CREATE") })),
4188
4326
  ...createOrder.map((name) => {
4189
4327
  const view = currentViewDefinitions.get(name);
@@ -4193,6 +4331,29 @@ async function planMigrationV2({
4193
4331
  ];
4194
4332
  return { namespace: canonical.namespace, schema, statements, snapshot };
4195
4333
  }
4334
+ function orderForeignKeyAdditions(canonical, statements) {
4335
+ if (!canonical.tables.some((table) => table.foreignKeys?.length)) return [...statements];
4336
+ const addsForeignKey = (statement) => /^ALTER TABLE[\s\S]* ADD CONSTRAINT[\s\S]* FOREIGN KEY\b/.test(statement);
4337
+ return [...statements.filter((statement) => !addsForeignKey(statement)), ...statements.filter(addsForeignKey)];
4338
+ }
4339
+ function foreignKeyTimingStatements(canonical, previous, baseDdl) {
4340
+ const prior = previous._sequenceOrm?.foreignKeys ?? {};
4341
+ const result = [];
4342
+ for (const table of canonical.tables) {
4343
+ for (const fk of table.foreignKeys ?? []) {
4344
+ const before = prior[`${table.table}.${fk.name}`];
4345
+ const recreated = baseDdl.some((statement) => statement.includes(`ALTER TABLE ${quoteIdentifier(ormSchemaName(canonical.namespace))}.${quoteIdentifier(table.table)} ADD CONSTRAINT ${quoteIdentifier(fk.name)}`));
4346
+ if (fk.deferrable ? !before || before.deferrable !== fk.deferrable || recreated : before?.deferrable && !recreated) {
4347
+ result.push(foreignKeyTimingSql(ormSchemaName(canonical.namespace), table.table, fk.name, fk.deferrable));
4348
+ }
4349
+ }
4350
+ }
4351
+ return result;
4352
+ }
4353
+ function foreignKeyTimingSql(schema, table, name, timing) {
4354
+ const clause = timing === void 0 ? "NOT DEFERRABLE" : timing === "initially-deferred" ? "DEFERRABLE INITIALLY DEFERRED" : "DEFERRABLE INITIALLY IMMEDIATE";
4355
+ return `ALTER TABLE ${quoteIdentifier(schema)}.${quoteIdentifier(table)} ALTER CONSTRAINT ${quoteIdentifier(name)} ${clause}`;
4356
+ }
4196
4357
  function validateViewCatalogStatement({
4197
4358
  canonical,
4198
4359
  view,
@@ -4447,7 +4608,63 @@ async function pendingKitStatementsV2({
4447
4608
  canonical,
4448
4609
  db
4449
4610
  }) {
4450
- return pendingStatements({ entities: buildDrizzleEntitiesV2(canonical), db, owned: V2_OWNED_STATEMENT });
4611
+ const { desired, defaultDrift } = await normalizeJsonDefaultsForIntrospection(canonical, db);
4612
+ const entities = buildDrizzleEntitiesV2(desired, { introspection: true });
4613
+ const pending = await pendingStatements({ entities, db, owned: V2_OWNED_STATEMENT });
4614
+ return [...orderForeignKeyAdditions(canonical, pending), ...defaultDrift, ...await pendingForeignKeyTimingStatements(canonical, db)];
4615
+ }
4616
+ async function normalizeJsonDefaultsForIntrospection(canonical, db) {
4617
+ const defaults = canonical.tables.flatMap((table, tableIndex) => table.source ? [] : table.columns.flatMap((column, columnIndex) => column.type === "jsonb" && typeof column.default === "string" ? [{ tableIndex, columnIndex, table: table.table, column: column.columnName, value: column.default }] : []));
4618
+ if (defaults.length === 0) return { desired: canonical, defaultDrift: [] };
4619
+ const array = (values) => drizzleOrm.sql`ARRAY[${drizzleOrm.sql.join(values.map((value) => drizzleOrm.sql`${value}`), drizzleOrm.sql`, `)}]::text[]`;
4620
+ const schema = ormSchemaName(canonical.namespace);
4621
+ const result = await shimExecute(db).execute(drizzleOrm.sql`
4622
+ SELECT desired.ordinal, desired.value::jsonb::text AS normalized,
4623
+ attribute.attnum IS NOT NULL AS column_exists,
4624
+ coalesce(pg_get_expr(ad.adbin, ad.adrelid) = quote_literal(desired.value::jsonb::text) || '::jsonb', false) AS matches
4625
+ FROM unnest(${array(defaults.map((item) => item.table))}, ${array(defaults.map((item) => item.column))}, ${array(defaults.map((item) => item.value))})
4626
+ WITH ORDINALITY AS desired(table_name, column_name, value, ordinal)
4627
+ LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.nspname = ${schema}
4628
+ LEFT JOIN pg_catalog.pg_class relation ON relation.relnamespace = namespace.oid AND relation.relname = desired.table_name
4629
+ LEFT JOIN pg_catalog.pg_attribute attribute ON attribute.attrelid = relation.oid AND attribute.attname = desired.column_name AND NOT attribute.attisdropped
4630
+ LEFT JOIN pg_catalog.pg_attrdef ad ON ad.adrelid = relation.oid AND ad.adnum = attribute.attnum
4631
+ ORDER BY desired.ordinal
4632
+ `);
4633
+ const rows = result.rows;
4634
+ if (!Array.isArray(rows) || rows.length !== defaults.length || rows.some((row, index3) => Number(row.ordinal) !== index3 + 1 || typeof row.normalized !== "string" || typeof row.column_exists !== "boolean" || typeof row.matches !== "boolean")) {
4635
+ throw new Error("invalid JSON default introspection result");
4636
+ }
4637
+ const desired = structuredClone(canonical);
4638
+ const defaultDrift = [];
4639
+ defaults.forEach((item, index3) => {
4640
+ const row = rows[index3];
4641
+ desired.tables[item.tableIndex].columns[item.columnIndex].default = JSON.stringify(JSON.parse(row.normalized));
4642
+ if (row.column_exists && !row.matches) defaultDrift.push(
4643
+ `ALTER TABLE ${quoteIdentifier(schema)}.${quoteIdentifier(item.table)} ALTER COLUMN ${quoteIdentifier(item.column)} SET DEFAULT ${quoteLiteral(item.value)}::jsonb;`
4644
+ );
4645
+ });
4646
+ return { desired, defaultDrift };
4647
+ }
4648
+ async function pendingForeignKeyTimingStatements(canonical, db) {
4649
+ const keys = canonical.tables.flatMap((table) => (table.foreignKeys ?? []).map((fk) => ({ table: table.table, fk })));
4650
+ if (keys.length === 0) return [];
4651
+ const schema = ormSchemaName(canonical.namespace);
4652
+ const result = await shimExecute(db).execute(drizzleOrm.sql`
4653
+ SELECT relation.relname AS table_name, constraint_row.conname AS name,
4654
+ constraint_row.condeferrable AS deferrable, constraint_row.condeferred AS deferred
4655
+ FROM pg_catalog.pg_constraint AS constraint_row
4656
+ JOIN pg_catalog.pg_class AS relation ON relation.oid = constraint_row.conrelid
4657
+ JOIN pg_catalog.pg_namespace AS namespace ON namespace.oid = relation.relnamespace
4658
+ WHERE namespace.nspname = ${schema} AND constraint_row.contype = 'f'
4659
+ `);
4660
+ const rows = result.rows;
4661
+ return keys.flatMap(({ table, fk }) => {
4662
+ const actual = rows.find((row) => row.table_name === table && row.name === fk.name);
4663
+ const deferrable = fk.deferrable !== void 0;
4664
+ const deferred = fk.deferrable === "initially-deferred";
4665
+ if (actual ? actual.deferrable === deferrable && actual.deferred === deferred : !deferrable) return [];
4666
+ return [foreignKeyTimingSql(schema, table, fk.name, fk.deferrable)];
4667
+ });
4451
4668
  }
4452
4669
  async function pendingStatements({
4453
4670
  entities,
@@ -4460,11 +4677,31 @@ async function pendingStatements({
4460
4677
  );
4461
4678
  return statementsToExecute.filter((statement) => !owned.test(statement));
4462
4679
  }
4680
+ function correctIntrospectionQuery(query) {
4681
+ if (!drizzleOrm.is(query, drizzleOrm.SQL)) return query;
4682
+ const compiled = new pgCore.PgDialect().sqlToQuery(query);
4683
+ let text4 = compiled.sql;
4684
+ const indexJoin = "pg_constraint con ON con.conindid = idx.indexrelid";
4685
+ if (text4.includes("AS generated_by_constraint") && text4.includes(indexJoin)) {
4686
+ text4 = text4.replace(indexJoin, `${indexJoin} AND con.contype IN ('p', 'u', 'x')`);
4687
+ }
4688
+ const sourceJoin = "LEFT JOIN pg_catalog.pg_attribute att ON att.attnum = ANY (con.conkey)";
4689
+ const targetJoin = "LEFT JOIN pg_catalog.pg_attribute fatt ON fatt.attnum = ANY (con.confkey)";
4690
+ if (text4.includes(sourceJoin) && text4.includes(targetJoin) && text4.includes("AND con.contype IN ('f')")) {
4691
+ text4 = text4.replace(
4692
+ sourceJoin,
4693
+ "JOIN LATERAL unnest(con.conkey, con.confkey) WITH ORDINALITY AS fk_key(source_num, target_num, ordinal) ON true LEFT JOIN pg_catalog.pg_attribute att ON att.attnum = fk_key.source_num"
4694
+ ).replace(targetJoin, "LEFT JOIN pg_catalog.pg_attribute fatt ON fatt.attnum = fk_key.target_num").replace(/;\s*$/, "") + " ORDER BY con.conname, fk_key.ordinal";
4695
+ }
4696
+ if (text4 === compiled.sql) return query;
4697
+ if (compiled.params.length !== 0) throw new Error("parameterized Drizzle catalog query cannot be normalized");
4698
+ return drizzleOrm.sql.raw(text4);
4699
+ }
4463
4700
  function shimExecute(db) {
4464
4701
  const execute = db.execute.bind(db);
4465
4702
  return {
4466
4703
  execute: async (query) => {
4467
- const result = await execute(query);
4704
+ const result = await execute(correctIntrospectionQuery(query));
4468
4705
  if (result && typeof result === "object" && "rows" in result) return result;
4469
4706
  return { rows: result };
4470
4707
  }
@@ -4504,21 +4741,73 @@ async function planMigration({
4504
4741
  const ddl = await diffStatements(hints.adjusted, snapshot);
4505
4742
  const policyDrops = policyDropStatements(schema, snapshotTableNames(previous, schema));
4506
4743
  const statements = [
4507
- ...policyDrops.map((sql4) => ({ kind: "security", sql: sql4 })),
4508
- ...hints.statements.map((sql4) => ({ kind: "hint", sql: sql4 })),
4509
- ...ddl.map((sql4) => ({ kind: "ddl", sql: sql4.replace(/;\s*$/, "") })),
4510
- ...securityStatements(definition).map((sql4) => ({ kind: "security", sql: sql4 })),
4744
+ ...policyDrops.map((sql5) => ({ kind: "security", sql: sql5 })),
4745
+ ...hints.statements.map((sql5) => ({ kind: "hint", sql: sql5 })),
4746
+ ...ddl.map((sql5) => ({ kind: "ddl", sql: sql5.replace(/;\s*$/, "") })),
4747
+ ...securityStatements(definition).map((sql5) => ({ kind: "security", sql: sql5 })),
4511
4748
  // PREPARE each action's executes first (plpgsql bodies don't check columns
4512
4749
  // at CREATE), then create the functions. Both reference the tables the DDL
4513
4750
  // above creates, so they close the plan.
4514
- ...actionPrepareChecks(definition).map((sql4) => ({ kind: "function", sql: sql4 })),
4515
- ...actionFunctionStatements(definition).map((sql4) => ({ kind: "function", sql: sql4 }))
4751
+ ...actionPrepareChecks(definition).map((sql5) => ({ kind: "function", sql: sql5 })),
4752
+ ...actionFunctionStatements(definition).map((sql5) => ({ kind: "function", sql: sql5 }))
4516
4753
  ];
4517
4754
  return { namespace: definition.namespace, schema, statements, snapshot };
4518
4755
  }
4519
4756
  var compileNamespace = (definition) => planMigration({ definition });
4520
4757
  var previousId2 = (snapshot) => snapshot.id;
4521
- var IR_VERSION = 1;
4758
+ var ORM_MIGRATION_EXPORT_FILE = "orm.migration.json";
4759
+ var ORM_MIGRATION_EXPORT_MAX_BYTES = ORM_REGISTRATION_MAX_BYTES;
4760
+ var hash = zod.z.string().regex(/^sha256:[0-9a-f]{64}$/);
4761
+ var ormMigrationPayloadSchema = zod.z.object({
4762
+ canonical_definition: canonicalDefinitionSchema,
4763
+ documents: zod.z.array(zod.z.object({ path: zod.z.string().min(1).max(2048), contents: zod.z.string().max(1e6) }).strict()).max(5e3),
4764
+ client_manifest: zod.z.object({ ops_hash: hash, operations: zod.z.record(zod.z.string(), hash) }).strict(),
4765
+ sdl: zod.z.string().refine((value) => Buffer.byteLength(value, "utf8") <= MAX_GENERATED_SDL_BYTES, {
4766
+ message: `sdl exceeds ${MAX_GENERATED_SDL_BYTES} bytes`
4767
+ }),
4768
+ schema_snapshot: zod.z.json(),
4769
+ // The existing ORM committed-migration validator and replay engine remain
4770
+ // authoritative. This envelope hashes the provenance, never authorizes SQL.
4771
+ migration: zod.z.json().optional()
4772
+ }).strict();
4773
+ var ormMigrationExportSchema = zod.z.object({
4774
+ schema_version: zod.z.literal(1),
4775
+ schema_hash: hash,
4776
+ payload: ormMigrationPayloadSchema,
4777
+ checksum: zod.z.string().regex(/^[0-9a-f]{64}$/)
4778
+ }).strict();
4779
+ function checksum(value) {
4780
+ return crypto.createHash("sha256").update(stableJson(value)).digest("hex");
4781
+ }
4782
+ function createOrmMigrationExport({ schemaHash, payload }) {
4783
+ const contents = { schema_version: 1, schema_hash: hash.parse(schemaHash), payload: ormMigrationPayloadSchema.parse(payload) };
4784
+ return { ...contents, checksum: checksum(contents) };
4785
+ }
4786
+ function parseOrmMigrationExport(text4) {
4787
+ if (Buffer.byteLength(text4, "utf8") > ORM_MIGRATION_EXPORT_MAX_BYTES) throw new Error("ORM migration export exceeds the size limit");
4788
+ const exported = ormMigrationExportSchema.parse(JSON.parse(text4));
4789
+ const { checksum: expected, ...contents } = exported;
4790
+ if (checksum(contents) !== expected) throw new Error("ORM migration export checksum mismatch; regenerate and commit it");
4791
+ return exported;
4792
+ }
4793
+ function renderOrmMigrationExport(exported) {
4794
+ const text4 = `${JSON.stringify(exported, null, 2)}
4795
+ `;
4796
+ if (Buffer.byteLength(text4, "utf8") > ORM_MIGRATION_EXPORT_MAX_BYTES) throw new Error("ORM migration export exceeds the size limit");
4797
+ return text4;
4798
+ }
4799
+ var IR_VERSION = 2;
4800
+ var LEGACY_IR_VERSION = 1;
4801
+ var irVersionSchema = zod.z.union([zod.z.literal(LEGACY_IR_VERSION), zod.z.literal(IR_VERSION)]);
4802
+ var operationVersionSchema = zod.z.object({ irVersion: irVersionSchema });
4803
+ function requiredArtifactIrVersion(operations) {
4804
+ let required = LEGACY_IR_VERSION;
4805
+ for (const operation of operations) {
4806
+ const { irVersion } = operationVersionSchema.parse(operation);
4807
+ if (irVersion > required) required = irVersion;
4808
+ }
4809
+ return required;
4810
+ }
4522
4811
  var CLAIMS_CONTRACT = {
4523
4812
  sub: "string",
4524
4813
  org: "string?",
@@ -4645,6 +4934,33 @@ var aggregateRootSchema = zod.z.object({
4645
4934
  nodes: selectionIrSchema.optional(),
4646
4935
  includeIf: includeIfSchema.optional()
4647
4936
  });
4937
+ var DATE_BUCKETS = ["year", "quarter", "month", "week", "day", "hour"];
4938
+ var groupByKeyIrSchema = zod.z.object({
4939
+ column: zod.z.string(),
4940
+ bucket: zod.z.enum(DATE_BUCKETS).optional()
4941
+ });
4942
+ var aggregateGroupsRootSchema = zod.z.object({
4943
+ kind: zod.z.literal("aggregateGroups"),
4944
+ alias: zod.z.string(),
4945
+ table: zod.z.string(),
4946
+ /** Composed at compile time: AND(policy, documentWhere?, dynamicFilter?). */
4947
+ where: predIrSchema,
4948
+ groupBy: zod.z.array(groupByKeyIrSchema).min(1),
4949
+ /**
4950
+ * The `key { … }` projection: which group columns appear in each entry's key
4951
+ * object, in selection order. A subset of `groupBy` (the compiler rejects a
4952
+ * key field that is not a group key — it would be indeterminate within the
4953
+ * group). Empty when the document selects only `aggregate`.
4954
+ */
4955
+ key: zod.z.array(zod.z.object({ alias: zod.z.string(), column: zod.z.string() })).default([]),
4956
+ count: zod.z.object({ columns: zod.z.array(zod.z.string()).optional(), distinct: zod.z.boolean().optional() }).optional(),
4957
+ sum: zod.z.array(zod.z.string()).optional(),
4958
+ avg: zod.z.array(zod.z.string()).optional(),
4959
+ /** Bounds the GROUP count, not the scanned rows — see MAX_GROUPS. */
4960
+ limit: limitIrSchema,
4961
+ offset: zod.z.object({ variable: zod.z.string().optional(), value: zod.z.number().int().optional() }).optional(),
4962
+ includeIf: includeIfSchema.optional()
4963
+ });
4648
4964
  var writeValuesSchema = zod.z.union([
4649
4965
  zod.z.object({ slot: zod.z.string() }),
4650
4966
  zod.z.object({ entries: zod.z.array(zod.z.object({ column: zod.z.string(), value: valueIrSchema })) })
@@ -4690,12 +5006,15 @@ var mutationRootSchema = zod.z.object({
4690
5006
  insertCheck: predIrSchema.optional(),
4691
5007
  returning: selectionIrSchema.nullable(),
4692
5008
  affectedRows: zod.z.boolean().default(false),
5009
+ /** v2: abort the transaction when the actual write count differs, regardless of selection. */
5010
+ assertAffectedRows: zod.z.number().int().min(0).max(2147483647).optional(),
4693
5011
  includeIf: includeIfSchema.optional()
4694
5012
  });
4695
5013
  var rootIrSchema = zod.z.discriminatedUnion("kind", [
4696
5014
  selectRootSchema,
4697
5015
  byPkRootSchema,
4698
5016
  aggregateRootSchema,
5017
+ aggregateGroupsRootSchema,
4699
5018
  mutationRootSchema
4700
5019
  ]);
4701
5020
  var INPUT_REF_KINDS = [
@@ -4725,7 +5044,7 @@ var variableIrSchema = zod.z.object({
4725
5044
  defaultValue: variableDefaultIrSchema.optional()
4726
5045
  });
4727
5046
  var compiledOperationSchema = zod.z.object({
4728
- irVersion: zod.z.literal(IR_VERSION),
5047
+ irVersion: irVersionSchema,
4729
5048
  name: zod.z.string(),
4730
5049
  opHash: zod.z.string().regex(/^sha256:[0-9a-f]{64}$/),
4731
5050
  kind: zod.z.enum(["query", "mutation"]),
@@ -4737,6 +5056,13 @@ var compiledOperationSchema = zod.z.object({
4737
5056
  /** Every table the op touches — data-token scoping + audit. */
4738
5057
  tableSet: zod.z.array(zod.z.string()).min(1),
4739
5058
  roots: zod.z.array(rootIrSchema).min(1)
5059
+ }).superRefine((operation, ctx) => {
5060
+ for (const [index3, root] of operation.roots.entries()) {
5061
+ if (root.kind !== "mutation" || root.assertAffectedRows === void 0) continue;
5062
+ if (operation.irVersion < 2 || operation.kind !== "mutation" || root.includeIf !== void 0) {
5063
+ ctx.addIssue({ code: "custom", path: ["roots", index3], message: "affected-row assertions require unconditional mutation roots and IR v2" });
5064
+ }
5065
+ }
4740
5066
  });
4741
5067
  var tableMetaIrSchema = zod.z.object({
4742
5068
  table: zod.z.string(),
@@ -4773,18 +5099,29 @@ var tableMetaIrSchema = zod.z.object({
4773
5099
  insertable: zod.z.array(zod.z.string()),
4774
5100
  settable: zod.z.array(zod.z.string()),
4775
5101
  appendable: zod.z.array(zod.z.string()),
5102
+ /**
5103
+ * Logical columns stamped with Postgres `now()` on UPDATE (canonical
5104
+ * `onUpdateFn`). Omitted when empty so pre-onUpdate artifacts still parse.
5105
+ */
5106
+ touchOnUpdate: zod.z.array(zod.z.string()).optional(),
4776
5107
  constraints: zod.z.array(zod.z.object({ name: zod.z.string(), columns: zod.z.array(zod.z.string()) })),
4777
5108
  /** Depth/node caps for dynamic filter trees on this table. */
4778
5109
  dynamicFilterMaxDepth: zod.z.number().int().positive().default(6),
4779
5110
  dynamicFilterMaxNodes: zod.z.number().int().positive().default(64)
4780
5111
  });
4781
5112
  var compiledArtifactSchema = zod.z.object({
4782
- irVersion: zod.z.literal(IR_VERSION),
5113
+ irVersion: irVersionSchema,
4783
5114
  namespace: zod.z.string(),
4784
5115
  schemaHash: zod.z.string(),
4785
5116
  opsHash: zod.z.string(),
4786
5117
  tables: zod.z.record(zod.z.string(), tableMetaIrSchema),
4787
5118
  operations: zod.z.record(zod.z.string(), compiledOperationSchema)
5119
+ }).superRefine((artifact, ctx) => {
5120
+ for (const [name, operation] of Object.entries(artifact.operations)) {
5121
+ if (operation.irVersion > artifact.irVersion) {
5122
+ ctx.addIssue({ code: "custom", path: ["operations", name, "irVersion"], message: "operation requires a newer IR version than its artifact" });
5123
+ }
5124
+ }
4788
5125
  });
4789
5126
  var IrVersionError = class extends Error {
4790
5127
  constructor(found) {
@@ -4795,7 +5132,7 @@ var IrVersionError = class extends Error {
4795
5132
  function normalizeIr(raw) {
4796
5133
  if (!raw || typeof raw !== "object") throw new IrVersionError(void 0);
4797
5134
  const version = raw.irVersion;
4798
- if (version !== IR_VERSION) throw new IrVersionError(version);
5135
+ if (version !== LEGACY_IR_VERSION && version !== IR_VERSION) throw new IrVersionError(version);
4799
5136
  return compiledArtifactSchema.parse(raw);
4800
5137
  }
4801
5138
  function indexByHash(artifact) {
@@ -5111,12 +5448,12 @@ async function writeMigration({
5111
5448
  const tip = workspace.journal.entries.at(-1);
5112
5449
  const ordinal = (tip?.ordinal ?? 0) + 1;
5113
5450
  const name = migrationName(ordinal, contentHash);
5114
- const sql4 = renderMigrationSql({ name, namespace: workspace.journal.namespace, contentHash, plan });
5451
+ const sql5 = renderMigrationSql({ name, namespace: workspace.journal.namespace, contentHash, plan });
5115
5452
  const metaDir = path.join(dir, MIGRATIONS_DIRNAME, META_DIRNAME);
5116
5453
  await promises.mkdir(metaDir, { recursive: true });
5117
5454
  const snapshotText = `${JSON.stringify(plan.snapshot, null, 2)}
5118
5455
  `;
5119
- await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name}.sql`), sql4);
5456
+ await promises.writeFile(path.join(dir, MIGRATIONS_DIRNAME, `${name}.sql`), sql5);
5120
5457
  await promises.writeFile(path.join(metaDir, `${pad(ordinal)}.snapshot.json`), snapshotText);
5121
5458
  const journal = {
5122
5459
  ...workspace.journal,
@@ -5127,7 +5464,7 @@ async function writeMigration({
5127
5464
  name,
5128
5465
  content_hash: contentHash,
5129
5466
  previous_content_hash: tip?.content_hash ?? null,
5130
- checksum: checksumOf(sql4),
5467
+ checksum: checksumOf(sql5),
5131
5468
  snapshot_checksum: checksumOf(snapshotText),
5132
5469
  destructive
5133
5470
  }
@@ -5242,8 +5579,8 @@ async function checkWorkspace({
5242
5579
  let previousId3;
5243
5580
  let previousHash = null;
5244
5581
  for (const entry of workspace.journal.entries) {
5245
- const sql4 = await readMigrationSql(dir, entry);
5246
- if (checksumOf(sql4) !== entry.checksum) {
5582
+ const sql5 = await readMigrationSql(dir, entry);
5583
+ if (checksumOf(sql5) !== entry.checksum) {
5247
5584
  log(`${MIGRATIONS_DIRNAME}/${entry.name}.sql does not match its journal checksum \u2014 committed migrations must not be edited`);
5248
5585
  return 1;
5249
5586
  }
@@ -5283,7 +5620,7 @@ async function checkWorkspace({
5283
5620
  log(`migrations in sync \u2014 ${workspace.journal.entries.length} committed, tip ${tip.name}`);
5284
5621
  return 0;
5285
5622
  }
5286
- var firstLine = (sql4) => sql4.split("\n")[0] ?? sql4;
5623
+ var firstLine = (sql5) => sql5.split("\n")[0] ?? sql5;
5287
5624
 
5288
5625
  // src/migrations/from-yaml.ts
5289
5626
  function convertV1DefinitionToCanonical(definition) {
@@ -5389,7 +5726,7 @@ function buildRebaseJournalEntry({ namespace, previousHash, newHash, ordinal, sn
5389
5726
  throw new OrmDefinitionError(`rebase ordinal must be an integer \u2265 2 (a rebase sits on an existing journal tip); got ${ordinal}`);
5390
5727
  }
5391
5728
  const name = migrationName(ordinal, newHash);
5392
- const sql4 = renderRebaseMigrationSql({ name, namespace, previousHash, newHash });
5729
+ const sql5 = renderRebaseMigrationSql({ name, namespace, previousHash, newHash });
5393
5730
  const snapshotText = `${JSON.stringify(snapshot, null, 2)}
5394
5731
  `;
5395
5732
  const entry = {
@@ -5397,11 +5734,11 @@ function buildRebaseJournalEntry({ namespace, previousHash, newHash, ordinal, sn
5397
5734
  name,
5398
5735
  content_hash: newHash,
5399
5736
  previous_content_hash: previousHash,
5400
- checksum: checksumOf(sql4),
5737
+ checksum: checksumOf(sql5),
5401
5738
  snapshot_checksum: checksumOf(snapshotText),
5402
5739
  destructive: false
5403
5740
  };
5404
- return { name, entry, sql: sql4, snapshotText };
5741
+ return { name, entry, sql: sql5, snapshotText };
5405
5742
  }
5406
5743
  function renderRebaseMigrationSql({
5407
5744
  name,
@@ -5531,10 +5868,12 @@ exports.CLAIM_KEY_PATTERN = CLAIM_KEY_PATTERN;
5531
5868
  exports.CMP_OPS = CMP_OPS;
5532
5869
  exports.COLUMN_BRAND = COLUMN_BRAND;
5533
5870
  exports.COLUMN_DEFAULT_FNS = COLUMN_DEFAULT_FNS;
5871
+ exports.COLUMN_IDENTIFIER_PATTERN = COLUMN_IDENTIFIER_PATTERN;
5534
5872
  exports.COLUMN_TYPES = COLUMN_TYPES2;
5535
5873
  exports.COMPARE_OPS = COMPARE_OPS;
5536
5874
  exports.CONSUMER_ROLE_SUFFIX = CONSUMER_ROLE_SUFFIX;
5537
5875
  exports.ColumnBuilder = ColumnBuilder;
5876
+ exports.DATE_BUCKETS = DATE_BUCKETS;
5538
5877
  exports.DEFINITION_FILE_EXTENSIONS = DEFINITION_FILE_EXTENSIONS;
5539
5878
  exports.ENUM_BRAND = ENUM_BRAND;
5540
5879
  exports.HASH_DOMAIN = HASH_DOMAIN;
@@ -5543,8 +5882,10 @@ exports.IDENTIFIER_RE = IDENTIFIER_RE;
5543
5882
  exports.INPUT_REF_KINDS = INPUT_REF_KINDS;
5544
5883
  exports.IR_VERSION = IR_VERSION;
5545
5884
  exports.IrVersionError = IrVersionError;
5885
+ exports.LEGACY_IR_VERSION = LEGACY_IR_VERSION;
5546
5886
  exports.LINK_BRAND = LINK_BRAND;
5547
5887
  exports.MAX_DEFINITION_FILE_BYTES = MAX_DEFINITION_FILE_BYTES;
5888
+ exports.MAX_GENERATED_SDL_BYTES = MAX_GENERATED_SDL_BYTES;
5548
5889
  exports.MAX_IDENTIFIER_LENGTH = MAX_IDENTIFIER_LENGTH;
5549
5890
  exports.MIGRATIONS_DIRNAME = MIGRATIONS_DIRNAME;
5550
5891
  exports.NAMESPACE_CONFIG_BRAND = NAMESPACE_CONFIG_BRAND;
@@ -5552,6 +5893,9 @@ exports.NAMESPACE_CONFIG_FILE = NAMESPACE_CONFIG_FILE;
5552
5893
  exports.NAMESPACE_CONFIG_FILENAMES = NAMESPACE_CONFIG_FILENAMES;
5553
5894
  exports.NAMESPACE_PATTERN = NAMESPACE_PATTERN;
5554
5895
  exports.ORM_DATA_TOKEN_HEADER = ORM_DATA_TOKEN_HEADER;
5896
+ exports.ORM_MIGRATION_EXPORT_FILE = ORM_MIGRATION_EXPORT_FILE;
5897
+ exports.ORM_MIGRATION_EXPORT_MAX_BYTES = ORM_MIGRATION_EXPORT_MAX_BYTES;
5898
+ exports.ORM_REGISTRATION_MAX_BYTES = ORM_REGISTRATION_MAX_BYTES;
5555
5899
  exports.ORM_SCHEMA_PREFIX = ORM_SCHEMA_PREFIX;
5556
5900
  exports.ORM_SERVICE_DATA_TOKEN_HEADER = ORM_SERVICE_DATA_TOKEN_HEADER;
5557
5901
  exports.ORM_TO_PIPELINE_TYPE = ORM_TO_PIPELINE_TYPE;
@@ -5616,6 +5960,7 @@ exports.computeDefinitionHash = computeDefinitionHash;
5616
5960
  exports.computeSyncedContractHash = computeSyncedContractHash;
5617
5961
  exports.consumerRoleName = consumerRoleName;
5618
5962
  exports.convertV1DefinitionToCanonical = convertV1DefinitionToCanonical;
5963
+ exports.createOrmMigrationExport = createOrmMigrationExport;
5619
5964
  exports.declaredCapabilityKeys = declaredCapabilityKeys;
5620
5965
  exports.defineEnum = defineEnum;
5621
5966
  exports.defineNamespace = defineNamespace;
@@ -5657,11 +6002,13 @@ exports.normalizeCanonical = normalizeCanonical;
5657
6002
  exports.normalizeIr = normalizeIr;
5658
6003
  exports.normalizeSnapshot = normalizeSnapshot;
5659
6004
  exports.orderIrSchema = orderIrSchema;
6005
+ exports.ormMigrationExportSchema = ormMigrationExportSchema;
5660
6006
  exports.ormSchemaName = ormSchemaName;
5661
6007
  exports.overlayWinsUnion = overlayWinsUnion;
5662
6008
  exports.overrideRowMutation = overrideRowMutation;
5663
6009
  exports.parseCanonicalDefinition = parseCanonicalDefinition;
5664
6010
  exports.parseDefinitionSources = parseDefinitionSources;
6011
+ exports.parseOrmMigrationExport = parseOrmMigrationExport;
5665
6012
  exports.parsePredicate = parsePredicate;
5666
6013
  exports.parseTableFile = parseTableFile;
5667
6014
  exports.parsedPredicateSchema = parsedPredicateSchema;
@@ -5682,6 +6029,8 @@ exports.rebaseViolations = rebaseViolations;
5682
6029
  exports.referencedCapabilities = referencedCapabilities;
5683
6030
  exports.referencedColumns = referencedColumns;
5684
6031
  exports.renderMigrationSql = renderMigrationSql;
6032
+ exports.renderOrmMigrationExport = renderOrmMigrationExport;
6033
+ exports.requiredArtifactIrVersion = requiredArtifactIrVersion;
5685
6034
  exports.revertOverlayMutation = revertOverlayMutation;
5686
6035
  exports.rewriteSyncedSourceRelationsInViewQuery = rewriteSyncedSourceRelationsInViewQuery;
5687
6036
  exports.roleExpression = roleExpression;