@atscript/db 0.1.136 → 0.1.137

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.
package/dist/sync.cjs CHANGED
@@ -1,315 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_db_view = require("./db-view-BAzhEUxB.cjs");
3
- //#region src/schema/schema-hash.ts
4
- /** Extracts sorted field snapshots from a readable's field descriptors. */
5
- function extractFieldSnapshots(fields, typeMapper) {
6
- return fields.filter((f) => !f.ignored).map((f) => {
7
- const snap = {
8
- physicalName: f.physicalName,
9
- designType: f.designType,
10
- optional: f.optional,
11
- isPrimaryKey: f.isPrimaryKey,
12
- storage: f.storage
13
- };
14
- if (f.defaultValue) snap.defaultValue = f.defaultValue;
15
- if (typeMapper) snap.mappedType = typeMapper(f);
16
- if (f.encrypted) snap.encrypted = true;
17
- return snap;
18
- }).toSorted((a, b) => a.physicalName.localeCompare(b.physicalName));
19
- }
20
- /**
21
- * Extracts a canonical, serializable snapshot from a readable's metadata.
22
- * Sorted deterministically so the hash is stable across runs.
23
- *
24
- * @param readable - The table/view readable.
25
- * @param typeMapper - Optional adapter-specific type mapper. When provided,
26
- * each field's mapped type (e.g., "VARCHAR(255)") is stored in the snapshot
27
- * for precise type change detection.
28
- */
29
- function computeTableSnapshot(readable, typeMapper, tableOptions) {
30
- const fields = extractFieldSnapshots(readable.fieldDescriptors, typeMapper);
31
- const indexes = [...readable.indexes.values()].map((idx) => ({
32
- key: idx.key,
33
- type: idx.type,
34
- fields: idx.fields.map((f) => ({
35
- name: f.name,
36
- sort: f.sort
37
- }))
38
- })).toSorted((a, b) => a.key.localeCompare(b.key));
39
- const foreignKeys = [...readable.foreignKeys.values()].map((fk) => ({
40
- fields: [...fk.fields].toSorted(),
41
- targetTable: fk.targetTable,
42
- targetFields: [...fk.targetFields].toSorted(),
43
- onDelete: fk.onDelete,
44
- onUpdate: fk.onUpdate
45
- })).toSorted((a, b) => a.fields.join(",").localeCompare(b.fields.join(",")));
46
- const snapshot = {
47
- tableName: readable.tableName,
48
- fields,
49
- indexes,
50
- foreignKeys
51
- };
52
- if (tableOptions?.length) snapshot.tableOptions = [...tableOptions].toSorted((a, b) => a.key.localeCompare(b.key));
53
- return snapshot;
54
- }
55
- /**
56
- * Extracts a canonical, serializable snapshot from a view's metadata.
57
- * Captures view plan (entry table, joins, filter, materialization) for
58
- * detecting view definition changes.
59
- */
60
- function computeViewSnapshot(view) {
61
- const fields = extractFieldSnapshots(view.fieldDescriptors);
62
- if (view.isExternal) return {
63
- tableName: view.tableName,
64
- viewType: "E",
65
- fields
66
- };
67
- const plan = view.viewPlan;
68
- const qualify = (ref) => view.resolveFieldRef(ref, (n) => n);
69
- const canonical = (node) => JSON.stringify(canonicalizeQueryNode(node, qualify));
70
- const columns = view.getViewColumnMappings().map((m) => {
71
- const col = {
72
- column: m.viewColumn,
73
- sourceTable: m.sourceTable,
74
- sourceColumn: m.sourceColumn
75
- };
76
- if (m.json) {
77
- col.jsonPath = JSON.stringify(m.json.path);
78
- col.jsonType = m.json.type;
79
- }
80
- if (m.aggFn) col.aggFn = m.aggFn;
81
- if (m.aggField) col.aggField = m.aggField;
82
- if (m.aggFilter) col.aggFilter = canonical(m.aggFilter);
83
- return col;
84
- }).toSorted((a, b) => a.column < b.column ? -1 : a.column > b.column ? 1 : 0);
85
- const result = {
86
- tableName: view.tableName,
87
- viewType: plan.materialized ? "M" : "V",
88
- entryTable: plan.entryTable,
89
- joinTables: plan.joins.map((j) => {
90
- const join = {
91
- targetTable: j.targetTable,
92
- condition: canonical(j.condition)
93
- };
94
- if (j.kind === "left") join.kind = "left";
95
- return join;
96
- }),
97
- columns
98
- };
99
- if (plan.filter) result.filterHash = fnv1a(canonical(plan.filter));
100
- if (plan.having) result.havingHash = fnv1a(canonical(plan.having));
101
- if (plan.materialized) result.materialized = true;
102
- return {
103
- ...result,
104
- fields
105
- };
106
- }
107
- /**
108
- * Converts a view predicate (join condition, `@db.view.filter`,
109
- * `@db.view.having`) into a serializable structure whose JSON is a stable
110
- * function of its MEANING: field refs become `qualify(ref)` — the view's
111
- * `resolveFieldRef(ref, (n) => n)`, i.e. `"<table>.<field>"`, so a predicate
112
- * retargeted to another table with the same field name changes — operators
113
- * and literal values are kept as-is, `$and`/`$or` keep declaration order, and
114
- * no function references survive. Two identical models produce byte-identical
115
- * JSON.
116
- * @since 0.1.128
117
- */
118
- function canonicalizeQueryNode(node, qualify) {
119
- if ("$and" in node) return { and: node.$and.map((n) => canonicalizeQueryNode(n, qualify)) };
120
- if ("$or" in node) return { or: node.$or.map((n) => canonicalizeQueryNode(n, qualify)) };
121
- if ("$not" in node) return { not: canonicalizeQueryNode(node.$not, qualify) };
122
- const comp = node;
123
- const out = {
124
- l: qualify(comp.left),
125
- op: comp.op
126
- };
127
- if (comp.right !== void 0) out.r = comp.right !== null && typeof comp.right === "object" && "field" in comp.right ? { f: qualify(comp.right) } : comp.right;
128
- return out;
129
- }
130
- /**
131
- * Computes a deterministic hash string from multiple table snapshots.
132
- * Uses FNV-1a for speed — not cryptographic, just needs stability + collision resistance.
133
- */
134
- function computeSchemaHash(snapshots) {
135
- const sorted = [...snapshots].toSorted((a, b) => a.tableName.localeCompare(b.tableName));
136
- return fnv1a(JSON.stringify(sorted));
137
- }
138
- /**
139
- * Computes a hash for a single table/view snapshot.
140
- * Used for per-table change detection via stored snapshots.
141
- */
142
- function computeTableHash(snapshot) {
143
- return fnv1a(JSON.stringify(snapshot));
144
- }
145
- /**
146
- * Converts stored snapshot fields to `TExistingColumn[]` format
147
- * for use with `computeColumnDiff`. Used by adapters that lack
148
- * native column introspection (e.g., MongoDB).
149
- *
150
- * The `type` field uses `mappedType` when available (adapter-specific),
151
- * falling back to `designType`.
152
- */
153
- function snapshotToExistingColumns(snapshot) {
154
- return snapshot.fields.map((f) => ({
155
- name: f.physicalName,
156
- type: f.mappedType ?? f.designType,
157
- notnull: !f.optional,
158
- pk: f.isPrimaryKey,
159
- dflt_value: serializeDefaultValue(f.defaultValue)
160
- }));
161
- }
162
- /**
163
- * Extracts table options from a stored snapshot for diff comparison.
164
- * Used as fallback when an adapter lacks native table option introspection.
165
- */
166
- function snapshotToExistingTableOptions(snapshot) {
167
- return snapshot.tableOptions ?? [];
168
- }
169
- /** Serializes a TDbDefaultValue to a comparable string. */
170
- function serializeDefaultValue(dv) {
171
- if (!dv) return;
172
- if (dv.kind === "value") return dv.value;
173
- return `fn:${dv.fn}`;
174
- }
175
- /** FNV-1a 32-bit hash → hex string */
176
- function fnv1a(str) {
177
- let hash = 2166136261;
178
- for (let i = 0; i < str.length; i++) {
179
- hash ^= str.codePointAt(i);
180
- hash = Math.imul(hash, 16777619);
181
- }
182
- return Math.trunc(hash).toString(16).padStart(8, "0");
183
- }
184
- //#endregion
185
- //#region src/schema/fk-diff.ts
186
- /** Canonical key for an FK: sorted local field names, comma-joined. */
187
- function fkKey(fields) {
188
- return [...fields].toSorted().join(",");
189
- }
190
- /**
191
- * Compares desired FK constraints against stored snapshot to detect
192
- * additions, removals, and property changes (target table, target fields,
193
- * onDelete, onUpdate).
194
- */
195
- function computeForeignKeyDiff(desired, existingSnapshot) {
196
- const added = [];
197
- const removed = [];
198
- const changed = [];
199
- const existingByKey = /* @__PURE__ */ new Map();
200
- for (const fk of existingSnapshot) existingByKey.set(fkKey(fk.fields), fk);
201
- const desiredKeys = /* @__PURE__ */ new Set();
202
- for (const fk of desired.values()) {
203
- const key = fkKey(fk.fields);
204
- desiredKeys.add(key);
205
- const existing = existingByKey.get(key);
206
- if (!existing) added.push(fk);
207
- else if (fkPropertiesDiffer(fk, existing)) changed.push({
208
- desired: fk,
209
- existing
210
- });
211
- }
212
- for (const [key, fk] of existingByKey) if (!desiredKeys.has(key)) removed.push(fk);
213
- return {
214
- added,
215
- removed,
216
- changed
217
- };
218
- }
219
- /** Whether the FK diff contains any changes. */
220
- function hasForeignKeyChanges(diff) {
221
- return diff.added.length > 0 || diff.removed.length > 0 || diff.changed.length > 0;
222
- }
223
- function fkPropertiesDiffer(desired, existing) {
224
- if (desired.targetTable !== existing.targetTable) return true;
225
- if (fkKey(desired.targetFields) !== fkKey(existing.targetFields)) return true;
226
- if ((desired.onDelete ?? void 0) !== (existing.onDelete ?? void 0)) return true;
227
- if ((desired.onUpdate ?? void 0) !== (existing.onUpdate ?? void 0)) return true;
228
- return false;
229
- }
230
- //#endregion
231
- //#region src/schema/column-diff.ts
232
- /**
233
- * Computes the difference between desired schema fields and existing database columns.
234
- *
235
- * @param desired - Field descriptors from the Atscript type (after flattening).
236
- * @param existing - Columns currently in the database (from introspection).
237
- * @param typeMapper - Optional function to map field metadata to DB-native type strings.
238
- * Receives the full field meta (design type, annotations, PK status, etc.)
239
- * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
240
- * Required for type change detection.
241
- */
242
- function computeColumnDiff(desired, existing, typeMapper) {
243
- const existingByName = new Map(existing.map((c) => [c.name, c]));
244
- const desiredByName = /* @__PURE__ */ new Map();
245
- const renamedOldNames = /* @__PURE__ */ new Set();
246
- const added = [];
247
- const renamed = [];
248
- const typeChanged = [];
249
- const nullableChanged = [];
250
- const defaultChanged = [];
251
- const conflicts = [];
252
- for (const field of desired) {
253
- if (field.ignored) continue;
254
- desiredByName.set(field.physicalName, field);
255
- const existingCol = existingByName.get(field.physicalName);
256
- if (existingCol) if (field.renamedFrom && existingByName.has(field.renamedFrom)) {
257
- conflicts.push({
258
- field,
259
- oldName: field.renamedFrom,
260
- conflictsWith: field.physicalName
261
- });
262
- renamedOldNames.add(field.renamedFrom);
263
- } else {
264
- if (typeMapper) {
265
- if (typeMapper(field).toUpperCase() !== existingCol.type.toUpperCase()) typeChanged.push({
266
- field,
267
- existingType: existingCol.type
268
- });
269
- }
270
- if (!field.isPrimaryKey && !existingCol.pk) {
271
- const desiredNotNull = !field.optional;
272
- if (existingCol.notnull !== desiredNotNull) nullableChanged.push({
273
- field,
274
- wasNullable: !existingCol.notnull
275
- });
276
- }
277
- const desiredDefault = serializeDefaultValue(field.defaultValue);
278
- if (existingCol.dflt_value !== void 0 && existingCol.dflt_value !== desiredDefault) defaultChanged.push({
279
- field,
280
- oldDefault: existingCol.dflt_value,
281
- newDefault: desiredDefault
282
- });
283
- }
284
- else if (field.renamedFrom && existingByName.has(field.renamedFrom)) {
285
- renamed.push({
286
- field,
287
- oldName: field.renamedFrom
288
- });
289
- renamedOldNames.add(field.renamedFrom);
290
- } else added.push(field);
291
- }
292
- const diff = {
293
- added,
294
- removed: existing.filter((c) => !desiredByName.has(c.name) && !renamedOldNames.has(c.name)),
295
- renamed,
296
- typeChanged,
297
- nullableChanged,
298
- defaultChanged,
299
- conflicts
300
- };
301
- if (existing.length > 0) {
302
- const newNameByOld = new Map(renamed.map((r) => [r.oldName, r.field.physicalName]));
303
- const from = existing.filter((c) => c.pk).map((c) => newNameByOld.get(c.name) ?? c.name);
304
- const to = desired.filter((f) => !f.ignored && f.isPrimaryKey).map((f) => f.physicalName);
305
- if (fkKey(from) !== fkKey(to)) diff.primaryKeyChanged = {
306
- from,
307
- to
308
- };
309
- }
310
- return diff;
311
- }
312
- //#endregion
2
+ const require_column_diff = require("./column-diff-CgxgFKzx.cjs");
313
3
  //#region src/schema/table-option-diff.ts
314
4
  /**
315
5
  * Computes the difference between desired and existing table options.
@@ -839,8 +529,8 @@ var SyncEntry = class SyncEntry {
839
529
  async function viewDefinitionChanged(view, store) {
840
530
  const storedSnapshot = await store.readTableSnapshot(view.tableName, true);
841
531
  if (!storedSnapshot) return false;
842
- const currentHash = computeTableHash(computeViewSnapshot(view));
843
- return computeTableHash(storedSnapshot) !== currentHash;
532
+ const currentHash = require_column_diff.computeTableHash(require_column_diff.computeViewSnapshot(view));
533
+ return require_column_diff.computeTableHash(storedSnapshot) !== currentHash;
844
534
  }
845
535
  /**
846
536
  * The plan entry of one table as `plan()` reports it (and as `run()` reports
@@ -935,14 +625,14 @@ async function executeSyncTable(facts, safe, deps, exec) {
935
625
  init.status = "alter";
936
626
  }
937
627
  phase = "Column sync";
938
- const hasFkChanges = fkDiff ? hasForeignKeyChanges(fkDiff) : false;
628
+ const hasFkChanges = fkDiff ? require_column_diff.hasForeignKeyChanges(fkDiff) : false;
939
629
  if (adapter.getExistingColumns && adapter.syncColumns) {
940
630
  const existing = facts.existing ?? await adapter.getExistingColumns();
941
631
  if (existing.length === 0 && !init.renamedFrom) {
942
632
  await adapter.ensureTable(ensureOpts);
943
633
  init.status = "create";
944
634
  } else if (existing.length > 0) {
945
- const diff = facts.diff ?? computeColumnDiff(readable.fieldDescriptors, existing, adapter.typeMapper?.bind(adapter));
635
+ const diff = facts.diff ?? require_column_diff.computeColumnDiff(readable.fieldDescriptors, existing, adapter.typeMapper?.bind(adapter));
946
636
  if (hasFkChanges && !adapter.syncForeignKeys && adapter.recreateTable) {
947
637
  await adapter.recreateTable();
948
638
  init.recreated = true;
@@ -953,7 +643,7 @@ async function executeSyncTable(facts, safe, deps, exec) {
953
643
  };
954
644
  } else {
955
645
  if (hasFkChanges && fkDiff && adapter.dropForeignKeys) {
956
- const keysToDrop = [...fkDiff.removed.map((fk) => fkKey(fk.fields)), ...fkDiff.changed.map((fk) => fkKey(fk.desired.fields))];
646
+ const keysToDrop = [...fkDiff.removed.map((fk) => require_column_diff.fkKey(fk.fields)), ...fkDiff.changed.map((fk) => require_column_diff.fkKey(fk.desired.fields))];
957
647
  if (keysToDrop.length > 0) {
958
648
  await adapter.dropForeignKeys(keysToDrop);
959
649
  droppedFks.push(...keysToDrop);
@@ -967,7 +657,7 @@ async function executeSyncTable(facts, safe, deps, exec) {
967
657
  const existed = adapter.tableExists ? await adapter.tableExists() : false;
968
658
  await adapter.ensureTable(ensureOpts);
969
659
  if (!existed) init.status = "create";
970
- } else await applyColumnDiff(adapter, readable, facts.diff ?? computeColumnDiff(readable.fieldDescriptors, snapshotToExistingColumns(storedSnapshot), deps.resolveTypeMapper(adapter)), init, safe, deps.logger, ensureOpts);
660
+ } else await applyColumnDiff(adapter, readable, facts.diff ?? require_column_diff.computeColumnDiff(readable.fieldDescriptors, require_column_diff.snapshotToExistingColumns(storedSnapshot), deps.resolveTypeMapper(adapter)), init, safe, deps.logger, ensureOpts);
971
661
  else {
972
662
  const existed = adapter.tableExists ? await adapter.tableExists() : true;
973
663
  if (!init.recreated) {
@@ -1118,7 +808,7 @@ function safeModeSkips(facts) {
1118
808
  const adapter = readable.dbAdapter;
1119
809
  const out = [];
1120
810
  if (facts.planEntry.status === "error") return out;
1121
- if (fkDiff && hasForeignKeyChanges(fkDiff) && !adapter.syncForeignKeys && adapter.recreateTable) return out;
811
+ if (fkDiff && require_column_diff.hasForeignKeyChanges(fkDiff) && !adapter.syncForeignKeys && adapter.recreateTable) return out;
1122
812
  const strategy = diff && diff.typeChanged.length > 0 ? typeChangeStrategy(readable, diff) : "modify";
1123
813
  if (strategy === "drop") out.push("recreate");
1124
814
  else if (strategy === "recreate") return out;
@@ -1321,7 +1011,7 @@ var SchemaSync = class {
1321
1011
  logger;
1322
1012
  constructor(space, logger) {
1323
1013
  this.space = space;
1324
- this.logger = logger || require_db_view.NoopLogger;
1014
+ this.logger = logger || require_column_diff.NoopLogger;
1325
1015
  this.store = new SyncStore(space);
1326
1016
  }
1327
1017
  /**
@@ -1348,20 +1038,20 @@ var SchemaSync = class {
1348
1038
  const snapshots = [];
1349
1039
  for (const r of allReadables) {
1350
1040
  if (r.isView) {
1351
- snapshots.push(computeViewSnapshot(r));
1041
+ snapshots.push(require_column_diff.computeViewSnapshot(r));
1352
1042
  continue;
1353
1043
  }
1354
1044
  r.fieldDescriptors;
1355
1045
  await r.dbAdapter.prepareTypeMapper?.();
1356
1046
  const tm = r.dbAdapter.typeMapper?.bind(r.dbAdapter);
1357
1047
  const opts = r.dbAdapter.getDesiredTableOptions?.();
1358
- snapshots.push(computeTableSnapshot(r, tm, opts));
1048
+ snapshots.push(require_column_diff.computeTableSnapshot(r, tm, opts));
1359
1049
  }
1360
1050
  return {
1361
1051
  tables,
1362
1052
  views,
1363
1053
  externalViews,
1364
- hash: computeSchemaHash(snapshots)
1054
+ hash: require_column_diff.computeSchemaHash(snapshots)
1365
1055
  };
1366
1056
  }
1367
1057
  /**
@@ -1669,7 +1359,7 @@ var SchemaSync = class {
1669
1359
  pendingRename,
1670
1360
  dbName,
1671
1361
  storedSnapshot,
1672
- fkDiff: storedSnapshot ? computeForeignKeyDiff(readable.foreignKeys, storedSnapshot.foreignKeys) : void 0,
1362
+ fkDiff: storedSnapshot ? require_column_diff.computeForeignKeyDiff(readable.foreignKeys, storedSnapshot.foreignKeys) : void 0,
1673
1363
  dropsTable: false,
1674
1364
  planEntry: init
1675
1365
  };
@@ -1681,7 +1371,7 @@ var SchemaSync = class {
1681
1371
  init.columnsToAdd = readable.fieldDescriptors.filter((f) => !f.ignored);
1682
1372
  } else if (facts.existing && facts.existing.length > 0) {
1683
1373
  const typeMapper = adapter.typeMapper?.bind(adapter);
1684
- facts.diff = computeColumnDiff(readable.fieldDescriptors, facts.existing, typeMapper);
1374
+ facts.diff = require_column_diff.computeColumnDiff(readable.fieldDescriptors, facts.existing, typeMapper);
1685
1375
  this.populatePlanFromDiff(facts.diff, init, readable, safe);
1686
1376
  }
1687
1377
  } else if (adapter.syncColumns) if (!storedSnapshot) {
@@ -1692,8 +1382,8 @@ var SchemaSync = class {
1692
1382
  }
1693
1383
  }
1694
1384
  } else {
1695
- const existing = snapshotToExistingColumns(storedSnapshot);
1696
- facts.diff = computeColumnDiff(readable.fieldDescriptors, existing, this.resolveTypeMapper(adapter));
1385
+ const existing = require_column_diff.snapshotToExistingColumns(storedSnapshot);
1386
+ facts.diff = require_column_diff.computeColumnDiff(readable.fieldDescriptors, existing, this.resolveTypeMapper(adapter));
1697
1387
  this.populatePlanFromDiff(facts.diff, init, readable, safe);
1698
1388
  }
1699
1389
  else if (adapter.tableExists) {
@@ -1708,7 +1398,7 @@ var SchemaSync = class {
1708
1398
  if (optionDiff.changed.some((c) => c.destructive)) init.recreated = true;
1709
1399
  }
1710
1400
  }
1711
- if (init.status !== "create" && init.status !== "error" && facts.fkDiff && hasForeignKeyChanges(facts.fkDiff)) {
1401
+ if (init.status !== "create" && init.status !== "error" && facts.fkDiff && require_column_diff.hasForeignKeyChanges(facts.fkDiff)) {
1712
1402
  const fkDiff = facts.fkDiff;
1713
1403
  init.status = "alter";
1714
1404
  init.fkAdded = fkDiff.added.map((fk) => ({
@@ -1760,7 +1450,7 @@ var SchemaSync = class {
1760
1450
  addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but the referencing table "${child.name}" is renamed in the same run (from "${child.pendingRename}") — rename it in a separate run first, then retarget the foreign key and re-run.`);
1761
1451
  continue;
1762
1452
  }
1763
- if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && fkKey(desired.fields) === fkKey(fk.fields) && fkKey(desired.targetFields) === fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
1453
+ if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && require_column_diff.fkKey(desired.fields) === require_column_diff.fkKey(fk.fields) && require_column_diff.fkKey(desired.targetFields) === require_column_diff.fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
1764
1454
  }
1765
1455
  for (const f of t.readable.fieldDescriptors) if (!f.ignored && !f.isPrimaryKey && f.defaultValue?.kind === "fn" && f.defaultValue.fn === "increment") addRefusal(refusals, t.name, `"${t.name}.${f.physicalName}" is auto-increment but no longer part of the primary key; auto-increment columns must be primary-key columns.`);
1766
1456
  }
@@ -1909,7 +1599,7 @@ var SchemaSync = class {
1909
1599
  if (!safe) for (const t of d.tables) {
1910
1600
  if (!t.diff?.primaryKeyChanged) continue;
1911
1601
  const keysByChild = /* @__PURE__ */ new Map();
1912
- for (const fk of t.inboundFks ?? []) keysByChild.set(fk.table, [...keysByChild.get(fk.table) ?? [], fkKey(fk.fields)]);
1602
+ for (const fk of t.inboundFks ?? []) keysByChild.set(fk.table, [...keysByChild.get(fk.table) ?? [], require_column_diff.fkKey(fk.fields)]);
1913
1603
  for (const [childName, fkKeys] of keysByChild) {
1914
1604
  const child = d.tableByDbName.get(childName);
1915
1605
  if (child?.readable.dbAdapter.dropForeignKeys) {
@@ -1992,7 +1682,7 @@ var SchemaSync = class {
1992
1682
  const adapter = readable.dbAdapter;
1993
1683
  const tm = adapter.typeMapper?.bind(adapter);
1994
1684
  const opts = adapter.getDesiredTableOptions?.();
1995
- const snapshot = readable.isView ? computeViewSnapshot(readable) : computeTableSnapshot(readable, tm, opts);
1685
+ const snapshot = readable.isView ? require_column_diff.computeViewSnapshot(readable) : require_column_diff.computeTableSnapshot(readable, tm, opts);
1996
1686
  await this.store.writeTableSnapshot(readable.tableName, snapshot);
1997
1687
  }
1998
1688
  for (const name of droppedNames) await this.store.deleteTableSnapshot(name);
@@ -2057,7 +1747,7 @@ var SchemaSync = class {
2057
1747
  */
2058
1748
  reportOutcome(result, onError) {
2059
1749
  if (onError === "silent" || result.entries.length === 0) return;
2060
- const out = this.logger === require_db_view.NoopLogger ? console : this.logger;
1750
+ const out = this.logger === require_column_diff.NoopLogger ? console : this.logger;
2061
1751
  const counts = /* @__PURE__ */ new Map();
2062
1752
  for (const entry of result.entries) counts.set(entry.status, (counts.get(entry.status) ?? 0) + 1);
2063
1753
  const summary = [...counts.entries()].map(([status, n]) => `${n} ${status}`).join(", ");
@@ -2152,7 +1842,7 @@ var SchemaSync = class {
2152
1842
  if (adapter.getExistingTableOptions) existing = await adapter.getExistingTableOptions(tableName);
2153
1843
  else {
2154
1844
  const snapshot = await this.store.readTableSnapshot(tableName ?? readable.tableName);
2155
- existing = snapshot ? snapshotToExistingTableOptions(snapshot) : [];
1845
+ existing = snapshot ? require_column_diff.snapshotToExistingTableOptions(snapshot) : [];
2156
1846
  }
2157
1847
  if (existing.length === 0) return null;
2158
1848
  const destructiveKeys = adapter.destructiveOptionKeys?.();
@@ -2219,19 +1909,19 @@ async function planSchema(space, types, opts) {
2219
1909
  //#endregion
2220
1910
  exports.SchemaSync = SchemaSync;
2221
1911
  exports.SyncEntry = SyncEntry;
2222
- exports.canonicalizeQueryNode = canonicalizeQueryNode;
2223
- exports.computeColumnDiff = computeColumnDiff;
2224
- exports.computeForeignKeyDiff = computeForeignKeyDiff;
2225
- exports.computeSchemaHash = computeSchemaHash;
2226
- exports.computeTableHash = computeTableHash;
1912
+ exports.canonicalizeQueryNode = require_column_diff.canonicalizeQueryNode;
1913
+ exports.computeColumnDiff = require_column_diff.computeColumnDiff;
1914
+ exports.computeForeignKeyDiff = require_column_diff.computeForeignKeyDiff;
1915
+ exports.computeSchemaHash = require_column_diff.computeSchemaHash;
1916
+ exports.computeTableHash = require_column_diff.computeTableHash;
2227
1917
  exports.computeTableOptionDiff = computeTableOptionDiff;
2228
- exports.computeTableSnapshot = computeTableSnapshot;
2229
- exports.computeViewSnapshot = computeViewSnapshot;
2230
- exports.fkKey = fkKey;
2231
- exports.hasForeignKeyChanges = hasForeignKeyChanges;
1918
+ exports.computeTableSnapshot = require_column_diff.computeTableSnapshot;
1919
+ exports.computeViewSnapshot = require_column_diff.computeViewSnapshot;
1920
+ exports.fkKey = require_column_diff.fkKey;
1921
+ exports.hasForeignKeyChanges = require_column_diff.hasForeignKeyChanges;
2232
1922
  exports.planSchema = planSchema;
2233
1923
  exports.readStoredSnapshot = readStoredSnapshot;
2234
- exports.snapshotToExistingColumns = snapshotToExistingColumns;
2235
- exports.snapshotToExistingTableOptions = snapshotToExistingTableOptions;
1924
+ exports.snapshotToExistingColumns = require_column_diff.snapshotToExistingColumns;
1925
+ exports.snapshotToExistingTableOptions = require_column_diff.snapshotToExistingTableOptions;
2236
1926
  exports.syncSchema = syncSchema;
2237
1927
  exports.topoOrder = topoOrder;
package/dist/sync.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as TColumnDiff, Ft as AtscriptDbReadable, G as TDbObjectKind, I as TDbDefaultValue, R as TDbFieldMeta, Ut as TGenericLogger, X as TDbStorageType, at as TExistingTableOption, ht as TReferencingForeignKey, it as TExistingForeignKey, mt as TPrimaryKeyChange, nt as TEnsureTableOptions, rt as TExistingColumn, yt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-kKY0RKYN.cjs";
2
- import { i as AtscriptDbView, l as AtscriptQueryFieldRef$1, t as DbSpace, u as AtscriptQueryNode$1 } from "./db-space-ClG41vJh.cjs";
1
+ import { $t as AtscriptDbReadable, Ft as DbSpace, G as TDbObjectKind, I as TDbDefaultValue, R as TDbFieldMeta, Rt as AtscriptDbView, Ut as AtscriptQueryFieldRef$1, Wt as AtscriptQueryNode$1, X as TDbStorageType, at as TExistingTableOption, ht as TReferencingForeignKey, it as TExistingForeignKey, mt as TPrimaryKeyChange, nt as TEnsureTableOptions, rt as TExistingColumn, sn as TGenericLogger, yt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-C-27xmtq.cjs";
2
+ import { t as computeColumnDiff } from "./column-diff-BmqvgBWw.cjs";
3
3
  import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/schema/sync-entry.d.ts
@@ -305,6 +305,11 @@ interface TViewSnapshot {
305
305
  /** @since 0.1.128 — hash of the canonical `@db.view.having` predicate. */
306
306
  havingHash?: string;
307
307
  materialized?: boolean;
308
+ /**
309
+ * @since 0.1.137 — the adapter's `viewRenderRevision()`, present only when
310
+ * the adapter defines one (managed views only).
311
+ */
312
+ renderRevision?: string;
308
313
  fields: TFieldSnapshot[];
309
314
  }
310
315
  /**
@@ -554,19 +559,6 @@ declare class SchemaSync {
554
559
  private buildExecutorDeps;
555
560
  }
556
561
  //#endregion
557
- //#region src/schema/column-diff.d.ts
558
- /**
559
- * Computes the difference between desired schema fields and existing database columns.
560
- *
561
- * @param desired - Field descriptors from the Atscript type (after flattening).
562
- * @param existing - Columns currently in the database (from introspection).
563
- * @param typeMapper - Optional function to map field metadata to DB-native type strings.
564
- * Receives the full field meta (design type, annotations, PK status, etc.)
565
- * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
566
- * Required for type change detection.
567
- */
568
- declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string): TColumnDiff;
569
- //#endregion
570
562
  //#region src/schema/table-option-diff.d.ts
571
563
  /**
572
564
  * Computes the difference between desired and existing table options.
package/dist/sync.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as TColumnDiff, Ft as AtscriptDbReadable, G as TDbObjectKind, I as TDbDefaultValue, R as TDbFieldMeta, Ut as TGenericLogger, X as TDbStorageType, at as TExistingTableOption, ht as TReferencingForeignKey, it as TExistingForeignKey, mt as TPrimaryKeyChange, nt as TEnsureTableOptions, rt as TExistingColumn, yt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-y4EzoX7D.mjs";
2
- import { i as AtscriptDbView, l as AtscriptQueryFieldRef$1, t as DbSpace, u as AtscriptQueryNode$1 } from "./db-space-BX4K3vb6.mjs";
1
+ import { $t as AtscriptDbReadable, Ft as DbSpace, G as TDbObjectKind, I as TDbDefaultValue, R as TDbFieldMeta, Rt as AtscriptDbView, Ut as AtscriptQueryFieldRef$1, Wt as AtscriptQueryNode$1, X as TDbStorageType, at as TExistingTableOption, ht as TReferencingForeignKey, it as TExistingForeignKey, mt as TPrimaryKeyChange, nt as TEnsureTableOptions, rt as TExistingColumn, sn as TGenericLogger, yt as TTableOptionDiff, z as TDbForeignKey } from "./buckets-BFG2RYRW.mjs";
2
+ import { t as computeColumnDiff } from "./column-diff-DPkbZIVE.mjs";
3
3
  import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/schema/sync-entry.d.ts
@@ -305,6 +305,11 @@ interface TViewSnapshot {
305
305
  /** @since 0.1.128 — hash of the canonical `@db.view.having` predicate. */
306
306
  havingHash?: string;
307
307
  materialized?: boolean;
308
+ /**
309
+ * @since 0.1.137 — the adapter's `viewRenderRevision()`, present only when
310
+ * the adapter defines one (managed views only).
311
+ */
312
+ renderRevision?: string;
308
313
  fields: TFieldSnapshot[];
309
314
  }
310
315
  /**
@@ -554,19 +559,6 @@ declare class SchemaSync {
554
559
  private buildExecutorDeps;
555
560
  }
556
561
  //#endregion
557
- //#region src/schema/column-diff.d.ts
558
- /**
559
- * Computes the difference between desired schema fields and existing database columns.
560
- *
561
- * @param desired - Field descriptors from the Atscript type (after flattening).
562
- * @param existing - Columns currently in the database (from introspection).
563
- * @param typeMapper - Optional function to map field metadata to DB-native type strings.
564
- * Receives the full field meta (design type, annotations, PK status, etc.)
565
- * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
566
- * Required for type change detection.
567
- */
568
- declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string): TColumnDiff;
569
- //#endregion
570
562
  //#region src/schema/table-option-diff.d.ts
571
563
  /**
572
564
  * Computes the difference between desired and existing table options.