@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/agg.d.cts +1 -1
- package/dist/agg.d.mts +1 -1
- package/dist/{buckets-y4EzoX7D.d.mts → buckets-BFG2RYRW.d.mts} +603 -15
- package/dist/{buckets-kKY0RKYN.d.cts → buckets-C-27xmtq.d.cts} +603 -15
- package/dist/column-diff-BmqvgBWw.d.cts +24 -0
- package/dist/{db-view-BrAtbaOx.mjs → column-diff-BwOA5101.mjs} +423 -46
- package/dist/{db-view-BAzhEUxB.cjs → column-diff-CgxgFKzx.cjs} +494 -45
- package/dist/column-diff-DPkbZIVE.d.mts +24 -0
- package/dist/index.cjs +64 -54
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +18 -9
- package/dist/plugin.cjs +2 -2
- package/dist/plugin.mjs +2 -2
- package/dist/rel.d.cts +2 -2
- package/dist/rel.d.mts +2 -2
- package/dist/{relation-helpers-BVjQflL_.d.cts → relation-helpers-D3Zu0Mta.d.mts} +1 -1
- package/dist/{relation-helpers-D4haLo1n.d.mts → relation-helpers-DxrvS6ar.d.cts} +1 -1
- package/dist/sync.cjs +33 -343
- package/dist/sync.d.cts +7 -15
- package/dist/sync.d.mts +7 -15
- package/dist/sync.mjs +1 -311
- package/package.json +1 -1
- package/dist/db-space-BX4K3vb6.d.mts +0 -558
- package/dist/db-space-ClG41vJh.d.cts +0 -558
|
@@ -119,18 +119,24 @@ function findAncestorInSet(path, set) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
|
+
* Whether a `@db.column` / `@db.column.renamed` on `path` applies: always on
|
|
123
|
+
* relational storage; on document storage (`nestedObjects`) for top-level
|
|
124
|
+
* fields only — nested keys are stored as-is. Column maps are built with it.
|
|
125
|
+
*/
|
|
126
|
+
function columnOverrideApplies(path, nestedObjects) {
|
|
127
|
+
return !nestedObjects || !path.includes(".");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
122
130
|
* Logical field path → its physical path in document storage (nested
|
|
123
|
-
* objects kept inline).
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* `prof.bio`.
|
|
131
|
+
* objects kept inline). A document renames the TOP-LEVEL key only — nested
|
|
132
|
+
* keys are stored as-is, so a `@db.column` on a nested leaf renames nothing
|
|
133
|
+
* (`address.zip` stays `address.zip`; see {@link columnOverrideApplies}) —
|
|
134
|
+
* and a dotted path under a renamed top-level object renames its first
|
|
135
|
+
* segment: `profile.bio` under `@db.column 'prof'` → `prof.bio`.
|
|
128
136
|
*/
|
|
129
137
|
function documentPath(columnMap, path) {
|
|
130
|
-
const direct = columnMap.get(path);
|
|
131
|
-
if (direct !== void 0) return direct;
|
|
132
138
|
const dot = path.indexOf(".");
|
|
133
|
-
if (dot === -1) return path;
|
|
139
|
+
if (dot === -1) return columnMap.get(path) ?? path;
|
|
134
140
|
const top = columnMap.get(path.slice(0, dot));
|
|
135
141
|
return top === void 0 ? path : top + path.slice(dot);
|
|
136
142
|
}
|
|
@@ -196,6 +202,7 @@ var TableMetadata = class {
|
|
|
196
202
|
ignoredFields = /* @__PURE__ */ new Set();
|
|
197
203
|
uniqueProps = /* @__PURE__ */ new Set();
|
|
198
204
|
defaults = /* @__PURE__ */ new Map();
|
|
205
|
+
/** Logical path → `@db.column` override (top-level keys only on document storage). */
|
|
199
206
|
columnMap = /* @__PURE__ */ new Map();
|
|
200
207
|
dimensions = [];
|
|
201
208
|
measures = [];
|
|
@@ -261,17 +268,19 @@ var TableMetadata = class {
|
|
|
261
268
|
get isBuilt() {
|
|
262
269
|
return this._built;
|
|
263
270
|
}
|
|
264
|
-
/**
|
|
265
|
-
* Logical field path → its physical path in document storage (nested
|
|
266
|
-
* objects kept inline). `@db.column` renames apply to the annotated key,
|
|
267
|
-
* and a document renames the TOP-LEVEL key only — nested keys are stored
|
|
268
|
-
* as-is — so a dotted path under a renamed top-level object renames its
|
|
269
|
-
* first segment: `profile.bio` under `@db.column 'prof'` → `prof.bio`.
|
|
270
|
-
*/
|
|
271
|
+
/** {@link documentPath} over this table's `columnMap`. */
|
|
271
272
|
documentPath(path) {
|
|
272
273
|
return documentPath(this.columnMap, path);
|
|
273
274
|
}
|
|
274
275
|
/**
|
|
276
|
+
* Physical name of a logical path: the document path on nested-object
|
|
277
|
+
* adapters, else the relational column (`pathToPhysical`, then the
|
|
278
|
+
* `@db.column` override).
|
|
279
|
+
*/
|
|
280
|
+
physicalPath(logical) {
|
|
281
|
+
return this.nestedObjects ? this.documentPath(logical) : this.pathToPhysical.get(logical) ?? this.columnMap.get(logical) ?? logical;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
275
284
|
* Runs the full metadata compilation pipeline. Called once by
|
|
276
285
|
* `AtscriptDbReadable._ensureBuilt()` on first metadata access.
|
|
277
286
|
*
|
|
@@ -359,10 +368,11 @@ var TableMetadata = class {
|
|
|
359
368
|
this.primaryKeys.push(fieldName);
|
|
360
369
|
this.originalMetaIdFields.push(fieldName);
|
|
361
370
|
}
|
|
371
|
+
const renamable = columnOverrideApplies(fieldName, this.nestedObjects);
|
|
362
372
|
const column = metadata.get("db.column");
|
|
363
|
-
if (column) this.columnMap.set(fieldName, column);
|
|
373
|
+
if (column && renamable) this.columnMap.set(fieldName, column);
|
|
364
374
|
const columnFrom = metadata.get("db.column.renamed");
|
|
365
|
-
if (columnFrom) this._columnFromMap.set(fieldName, columnFrom);
|
|
375
|
+
if (columnFrom && renamable) this._columnFromMap.set(fieldName, columnFrom);
|
|
366
376
|
const resolvedDefault = resolveDefaultFromMetadata(metadata);
|
|
367
377
|
if (resolvedDefault) this.defaults.set(fieldName, resolvedDefault);
|
|
368
378
|
if (metadata.has("db.ignore")) this.ignoredFields.add(fieldName);
|
|
@@ -620,7 +630,7 @@ var TableMetadata = class {
|
|
|
620
630
|
else if (isJson) storage = "json";
|
|
621
631
|
else if (isFlattened) storage = "flattened";
|
|
622
632
|
else storage = "column";
|
|
623
|
-
const physicalName =
|
|
633
|
+
const physicalName = this.physicalPath(path);
|
|
624
634
|
const fromLocal = this._columnFromMap.get(path);
|
|
625
635
|
let renamedFrom;
|
|
626
636
|
if (fromLocal) renamedFrom = isFlattened ? flattenedPrefix(path) + fromLocal : fromLocal;
|
|
@@ -724,7 +734,7 @@ var TableMetadata = class {
|
|
|
724
734
|
field.optional = ftype.optional === true;
|
|
725
735
|
field.designType = ftype.type.tags?.has("objectId") ? "objectId" : resolveDesignType(ftype);
|
|
726
736
|
}
|
|
727
|
-
field.name = this.
|
|
737
|
+
field.name = this.physicalPath(field.name);
|
|
728
738
|
}
|
|
729
739
|
}
|
|
730
740
|
/**
|
|
@@ -1023,11 +1033,24 @@ var FieldMappingStrategy = class {
|
|
|
1023
1033
|
else if (key === "$not") result[key] = this.translateFilter(value, meta);
|
|
1024
1034
|
else if (key.startsWith("$")) result[key] = value;
|
|
1025
1035
|
else {
|
|
1026
|
-
const
|
|
1027
|
-
result[
|
|
1036
|
+
const physical = this.physicalPath(key, meta);
|
|
1037
|
+
result[physical] = this.formatFilterValue(physical, value, meta);
|
|
1028
1038
|
}
|
|
1029
1039
|
return result;
|
|
1030
1040
|
}
|
|
1041
|
+
/** `$inc` / `$mul` field-op keys to physical names ({@link physicalPath}). */
|
|
1042
|
+
translateOpsKeys(ops, meta) {
|
|
1043
|
+
if (!this.renamesPaths(meta)) return ops;
|
|
1044
|
+
const physical = (rec) => {
|
|
1045
|
+
const out = {};
|
|
1046
|
+
for (const key in rec) out[this.physicalPath(key, meta)] = rec[key];
|
|
1047
|
+
return out;
|
|
1048
|
+
};
|
|
1049
|
+
return {
|
|
1050
|
+
inc: ops.inc && physical(ops.inc),
|
|
1051
|
+
mul: ops.mul && physical(ops.mul)
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1031
1054
|
/**
|
|
1032
1055
|
* Reverse-maps `@db.column` renames on a row read from storage.
|
|
1033
1056
|
* Renames physical keys back to logical names in-place.
|
|
@@ -1187,10 +1210,11 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
1187
1210
|
}
|
|
1188
1211
|
return this.formatWriteValues(data, meta);
|
|
1189
1212
|
}
|
|
1213
|
+
/** Patch keys (top-level or decomposed dotted) to document paths. */
|
|
1190
1214
|
translatePatchKeys(update, meta) {
|
|
1191
|
-
if (meta
|
|
1215
|
+
if (this.renamesPaths(meta)) {
|
|
1192
1216
|
const result = {};
|
|
1193
|
-
for (const key of Object.keys(update)) result[
|
|
1217
|
+
for (const key of Object.keys(update)) result[this.physicalPath(key, meta)] = update[key];
|
|
1194
1218
|
return this.formatWriteValues(result, meta);
|
|
1195
1219
|
}
|
|
1196
1220
|
return this.formatWriteValues(update, meta);
|
|
@@ -2239,7 +2263,7 @@ var AtscriptDbReadable = class {
|
|
|
2239
2263
|
get syncMethod() {
|
|
2240
2264
|
return this._syncMethod;
|
|
2241
2265
|
}
|
|
2242
|
-
/** Logical → physical column name mapping from `@db.column
|
|
2266
|
+
/** Logical → physical column name mapping from `@db.column` (top-level only on document storage). */
|
|
2243
2267
|
get columnMap() {
|
|
2244
2268
|
this._ensureBuilt();
|
|
2245
2269
|
return this._meta.columnMap;
|
|
@@ -2934,6 +2958,15 @@ var BaseDbAdapter = class {
|
|
|
2934
2958
|
if (logger) this.logger = logger;
|
|
2935
2959
|
}
|
|
2936
2960
|
/**
|
|
2961
|
+
* Called by {@link DbSpace} right after its factory builds this adapter —
|
|
2962
|
+
* the administrative one included — before {@link registerReadable}. No-op
|
|
2963
|
+
* by default: override it to share state across a space's adapters when the
|
|
2964
|
+
* adapter has no driver to share it through (the memory adapter keeps one
|
|
2965
|
+
* store per space).
|
|
2966
|
+
* @since 0.1.137
|
|
2967
|
+
*/
|
|
2968
|
+
registerSpace(_space) {}
|
|
2969
|
+
/**
|
|
2937
2970
|
* Enables or disables verbose (debug-level) logging for this adapter.
|
|
2938
2971
|
* When disabled, no log strings are constructed — zero overhead.
|
|
2939
2972
|
*/
|
|
@@ -3118,6 +3151,17 @@ var BaseDbAdapter = class {
|
|
|
3118
3151
|
return require_aggregate_fns.BASE_AGGREGATE_FNS;
|
|
3119
3152
|
}
|
|
3120
3153
|
/**
|
|
3154
|
+
* Revision of how this adapter renders a managed view (its SQL / pipeline)
|
|
3155
|
+
* from an unchanged view definition. Stored in each managed view's sync
|
|
3156
|
+
* snapshot when defined, so bumping it recreates every managed view of the
|
|
3157
|
+
* adapter once on the next sync — return a new value whenever a rendering
|
|
3158
|
+
* fix changes what an existing view returns. `undefined` (the default)
|
|
3159
|
+
* leaves the snapshot, and its hash, as before. External views ignore it.
|
|
3160
|
+
*
|
|
3161
|
+
* @since 0.1.137
|
|
3162
|
+
*/
|
|
3163
|
+
viewRenderRevision() {}
|
|
3164
|
+
/**
|
|
3121
3165
|
* Whether this adapter enforces foreign key constraints natively.
|
|
3122
3166
|
* When `true`, the generic layer skips application-level cascade/setNull
|
|
3123
3167
|
* on delete — the DB engine handles it (e.g. SQLite `ON DELETE CASCADE`).
|
|
@@ -3406,6 +3450,26 @@ var BaseDbAdapter = class {
|
|
|
3406
3450
|
*/
|
|
3407
3451
|
supportsColumnModify;
|
|
3408
3452
|
/**
|
|
3453
|
+
* Drops a table by name (without needing a registered readable).
|
|
3454
|
+
* Used by schema sync to remove tables no longer in the schema. A missing
|
|
3455
|
+
* table is not an error (`DROP TABLE IF EXISTS`). The default throws —
|
|
3456
|
+
* schema sync then reports the removed table as an `error` entry and keeps
|
|
3457
|
+
* it tracked. Since 0.1.137; before, the method was optional and a drop the
|
|
3458
|
+
* adapter lacked was skipped silently while sync reported it done.
|
|
3459
|
+
*/
|
|
3460
|
+
async dropTableByName(tableName) {
|
|
3461
|
+
throw new Error(`Cannot drop table "${tableName}": dropTableByName is not supported by this adapter`);
|
|
3462
|
+
}
|
|
3463
|
+
/**
|
|
3464
|
+
* Drops a view by name (without needing a registered readable).
|
|
3465
|
+
* Used by schema sync to remove views no longer in the schema, and to drop
|
|
3466
|
+
* a managed view before recreating it. A missing view is not an error. The
|
|
3467
|
+
* default throws, with the same history as {@link dropTableByName}.
|
|
3468
|
+
*/
|
|
3469
|
+
async dropViewByName(viewName) {
|
|
3470
|
+
throw new Error(`Cannot drop view "${viewName}": dropViewByName is not supported by this adapter`);
|
|
3471
|
+
}
|
|
3472
|
+
/**
|
|
3409
3473
|
* Drops several tables that reference each other (a foreign-key cycle) as
|
|
3410
3474
|
* one operation. Schema sync only calls this for cycles whose members are
|
|
3411
3475
|
* ALL being removed. Default: {@link dropTableByName} in the given order —
|
|
@@ -3415,7 +3479,7 @@ var BaseDbAdapter = class {
|
|
|
3415
3479
|
* @since 0.1.128
|
|
3416
3480
|
*/
|
|
3417
3481
|
async dropTablesByName(tableNames) {
|
|
3418
|
-
for (const name of tableNames) await this.dropTableByName
|
|
3482
|
+
for (const name of tableNames) await this.dropTableByName(name);
|
|
3419
3483
|
}
|
|
3420
3484
|
/**
|
|
3421
3485
|
* Whether the table has at least one row. Schema sync uses it in the
|
|
@@ -3527,7 +3591,7 @@ var ApplicationIntegrity = class extends IntegrityStrategy {
|
|
|
3527
3591
|
const physicalToLogical = /* @__PURE__ */ new Map();
|
|
3528
3592
|
const physicalFields = [];
|
|
3529
3593
|
for (const logical of neededLogical) {
|
|
3530
|
-
const physical = meta.
|
|
3594
|
+
const physical = meta.physicalPath(logical);
|
|
3531
3595
|
physicalFields.push(physical);
|
|
3532
3596
|
physicalToLogical.set(physical, logical);
|
|
3533
3597
|
}
|
|
@@ -3995,19 +4059,6 @@ var RemoveGuardContext = class {
|
|
|
3995
4059
|
return this._pending;
|
|
3996
4060
|
}
|
|
3997
4061
|
};
|
|
3998
|
-
/** Translates a single ops record from logical to physical column names. */
|
|
3999
|
-
function _translateOpsRecord(rec, meta) {
|
|
4000
|
-
const out = {};
|
|
4001
|
-
for (const key in rec) out[meta.leafByLogical.get(key)?.physicalName ?? key] = rec[key];
|
|
4002
|
-
return out;
|
|
4003
|
-
}
|
|
4004
|
-
/** Translates ops keys from logical field names to physical column names. */
|
|
4005
|
-
function _translateOpsKeys(ops, meta) {
|
|
4006
|
-
return {
|
|
4007
|
-
inc: ops.inc ? _translateOpsRecord(ops.inc, meta) : void 0,
|
|
4008
|
-
mul: ops.mul ? _translateOpsRecord(ops.mul, meta) : void 0
|
|
4009
|
-
};
|
|
4010
|
-
}
|
|
4011
4062
|
/** Upper bound of keys per `touchMany` UPDATE statement (parameter-count safety). */
|
|
4012
4063
|
const TOUCH_MANY_CHUNK = 500;
|
|
4013
4064
|
/** `touchMany` input rejection — always `INVALID_QUERY`, path names the key. */
|
|
@@ -4268,13 +4319,13 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
4268
4319
|
let result;
|
|
4269
4320
|
if (this.adapter.supportsNativePatch()) {
|
|
4270
4321
|
const ops = require_ops.separateFieldOps(data);
|
|
4271
|
-
const translatedOps = ops ?
|
|
4322
|
+
const translatedOps = ops ? this._fieldMapper.translateOpsKeys(ops, this._meta) : void 0;
|
|
4272
4323
|
const translatedData = this._fieldMapper.translatePatchKeys(data, this._meta);
|
|
4273
4324
|
result = await this.adapter.nativePatch(translatedFilter, translatedData, translatedOps, expectedVersion);
|
|
4274
4325
|
} else {
|
|
4275
4326
|
const update = decomposePatch(data, this);
|
|
4276
4327
|
const ops = require_ops.separateFieldOps(update);
|
|
4277
|
-
const translatedOps = ops ?
|
|
4328
|
+
const translatedOps = ops ? this._fieldMapper.translateOpsKeys(ops, this._meta) : void 0;
|
|
4278
4329
|
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
4279
4330
|
if (getArrayOpsFields(translatedUpdate).size > 0) {
|
|
4280
4331
|
const resolved = resolveArrayOps(translatedUpdate, await this.adapter.findOne({
|
|
@@ -4413,7 +4464,7 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
4413
4464
|
await this._encryptItems([dataCopy], "patch");
|
|
4414
4465
|
const update = decomposePatch(dataCopy, this);
|
|
4415
4466
|
const ops = require_ops.separateFieldOps(update);
|
|
4416
|
-
const translatedOps = ops ?
|
|
4467
|
+
const translatedOps = ops ? this._fieldMapper.translateOpsKeys(ops, this._meta) : void 0;
|
|
4417
4468
|
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
4418
4469
|
const translatedFilter = this._fieldMapper.translateFilter(filter, this._meta);
|
|
4419
4470
|
if (translatedOps === void 0 && require_validator.isEmptyObject(translatedUpdate)) return {
|
|
@@ -4695,6 +4746,7 @@ function sourceIndex(type) {
|
|
|
4695
4746
|
idx = {
|
|
4696
4747
|
flatMap: /* @__PURE__ */ new Map(),
|
|
4697
4748
|
columnMap: /* @__PURE__ */ new Map(),
|
|
4749
|
+
documentColumnMap: /* @__PURE__ */ new Map(),
|
|
4698
4750
|
unstored: /* @__PURE__ */ new Set(),
|
|
4699
4751
|
jsonRoots: /* @__PURE__ */ new Set(),
|
|
4700
4752
|
encrypted: /* @__PURE__ */ new Set(),
|
|
@@ -4718,7 +4770,10 @@ function sourceIndex(type) {
|
|
|
4718
4770
|
for (const [path, fieldType, metadata] of collected) {
|
|
4719
4771
|
if (!path || findAncestorInSet(path, navFields) !== void 0) continue;
|
|
4720
4772
|
const column = metadata.get("db.column");
|
|
4721
|
-
if (column)
|
|
4773
|
+
if (column) {
|
|
4774
|
+
idx.columnMap.set(path, column);
|
|
4775
|
+
if (columnOverrideApplies(path, true)) idx.documentColumnMap.set(path, column);
|
|
4776
|
+
}
|
|
4722
4777
|
if (metadata.has("db.ignore") || navFields.has(path)) idx.unstored.add(path);
|
|
4723
4778
|
if (metadata.has("db.encrypted")) storage.push([path, false]);
|
|
4724
4779
|
else if (metadata.has("db.json") || resolveDesignType(fieldType) === "array") storage.push([path, true]);
|
|
@@ -4765,7 +4820,7 @@ function resolveViewSource(sourceType, logicalPath, nestedObjects) {
|
|
|
4765
4820
|
if (unstored !== void 0) throw new Error(`"${logicalPath}" has no column — "${unstored}" is @db.ignore or a navigation relation`);
|
|
4766
4821
|
const designType = resolveDesignType(node);
|
|
4767
4822
|
if (nestedObjects) return {
|
|
4768
|
-
column: documentPath(idx.
|
|
4823
|
+
column: documentPath(idx.documentColumnMap, logicalPath),
|
|
4769
4824
|
designType,
|
|
4770
4825
|
optional
|
|
4771
4826
|
};
|
|
@@ -4965,7 +5020,7 @@ var AtscriptDbView = class extends AtscriptDbReadable {
|
|
|
4965
5020
|
const ignored = this.ignoredFields;
|
|
4966
5021
|
const meta = this.getMetadata();
|
|
4967
5022
|
const nested = this._nested;
|
|
4968
|
-
const viewName = (path) => nested ? meta.
|
|
5023
|
+
const viewName = (path) => nested ? meta.physicalPath(path) : meta.pathToPhysical.get(path);
|
|
4969
5024
|
const fail = (field, message) => {
|
|
4970
5025
|
throw new Error(`View "${this.tableName}" field "${field}": ${message}`);
|
|
4971
5026
|
};
|
|
@@ -5050,6 +5105,328 @@ function isAtscriptDbView(readable) {
|
|
|
5050
5105
|
return readable.isView;
|
|
5051
5106
|
}
|
|
5052
5107
|
//#endregion
|
|
5108
|
+
//#region src/schema/schema-hash.ts
|
|
5109
|
+
/** Extracts sorted field snapshots from a readable's field descriptors. */
|
|
5110
|
+
function extractFieldSnapshots(fields, typeMapper) {
|
|
5111
|
+
return fields.filter((f) => !f.ignored).map((f) => {
|
|
5112
|
+
const snap = {
|
|
5113
|
+
physicalName: f.physicalName,
|
|
5114
|
+
designType: f.designType,
|
|
5115
|
+
optional: f.optional,
|
|
5116
|
+
isPrimaryKey: f.isPrimaryKey,
|
|
5117
|
+
storage: f.storage
|
|
5118
|
+
};
|
|
5119
|
+
if (f.defaultValue) snap.defaultValue = f.defaultValue;
|
|
5120
|
+
if (typeMapper) snap.mappedType = typeMapper(f);
|
|
5121
|
+
if (f.encrypted) snap.encrypted = true;
|
|
5122
|
+
return snap;
|
|
5123
|
+
}).toSorted((a, b) => a.physicalName.localeCompare(b.physicalName));
|
|
5124
|
+
}
|
|
5125
|
+
/**
|
|
5126
|
+
* Extracts a canonical, serializable snapshot from a readable's metadata.
|
|
5127
|
+
* Sorted deterministically so the hash is stable across runs.
|
|
5128
|
+
*
|
|
5129
|
+
* @param readable - The table/view readable.
|
|
5130
|
+
* @param typeMapper - Optional adapter-specific type mapper. When provided,
|
|
5131
|
+
* each field's mapped type (e.g., "VARCHAR(255)") is stored in the snapshot
|
|
5132
|
+
* for precise type change detection.
|
|
5133
|
+
*/
|
|
5134
|
+
function computeTableSnapshot(readable, typeMapper, tableOptions) {
|
|
5135
|
+
const fields = extractFieldSnapshots(readable.fieldDescriptors, typeMapper);
|
|
5136
|
+
const indexes = [...readable.indexes.values()].map((idx) => ({
|
|
5137
|
+
key: idx.key,
|
|
5138
|
+
type: idx.type,
|
|
5139
|
+
fields: idx.fields.map((f) => ({
|
|
5140
|
+
name: f.name,
|
|
5141
|
+
sort: f.sort
|
|
5142
|
+
}))
|
|
5143
|
+
})).toSorted((a, b) => a.key.localeCompare(b.key));
|
|
5144
|
+
const foreignKeys = [...readable.foreignKeys.values()].map((fk) => ({
|
|
5145
|
+
fields: [...fk.fields].toSorted(),
|
|
5146
|
+
targetTable: fk.targetTable,
|
|
5147
|
+
targetFields: [...fk.targetFields].toSorted(),
|
|
5148
|
+
onDelete: fk.onDelete,
|
|
5149
|
+
onUpdate: fk.onUpdate
|
|
5150
|
+
})).toSorted((a, b) => a.fields.join(",").localeCompare(b.fields.join(",")));
|
|
5151
|
+
const snapshot = {
|
|
5152
|
+
tableName: readable.tableName,
|
|
5153
|
+
fields,
|
|
5154
|
+
indexes,
|
|
5155
|
+
foreignKeys
|
|
5156
|
+
};
|
|
5157
|
+
if (tableOptions?.length) snapshot.tableOptions = [...tableOptions].toSorted((a, b) => a.key.localeCompare(b.key));
|
|
5158
|
+
return snapshot;
|
|
5159
|
+
}
|
|
5160
|
+
/**
|
|
5161
|
+
* Extracts a canonical, serializable snapshot from a view's metadata.
|
|
5162
|
+
* Captures view plan (entry table, joins, filter, materialization) for
|
|
5163
|
+
* detecting view definition changes.
|
|
5164
|
+
*/
|
|
5165
|
+
function computeViewSnapshot(view) {
|
|
5166
|
+
const fields = extractFieldSnapshots(view.fieldDescriptors);
|
|
5167
|
+
if (view.isExternal) return {
|
|
5168
|
+
tableName: view.tableName,
|
|
5169
|
+
viewType: "E",
|
|
5170
|
+
fields
|
|
5171
|
+
};
|
|
5172
|
+
const plan = view.viewPlan;
|
|
5173
|
+
const qualify = (ref) => view.resolveFieldRef(ref, (n) => n);
|
|
5174
|
+
const canonical = (node) => JSON.stringify(canonicalizeQueryNode(node, qualify));
|
|
5175
|
+
const columns = view.getViewColumnMappings().map((m) => {
|
|
5176
|
+
const col = {
|
|
5177
|
+
column: m.viewColumn,
|
|
5178
|
+
sourceTable: m.sourceTable,
|
|
5179
|
+
sourceColumn: m.sourceColumn
|
|
5180
|
+
};
|
|
5181
|
+
if (m.json) {
|
|
5182
|
+
col.jsonPath = JSON.stringify(m.json.path);
|
|
5183
|
+
col.jsonType = m.json.type;
|
|
5184
|
+
}
|
|
5185
|
+
if (m.aggFn) col.aggFn = m.aggFn;
|
|
5186
|
+
if (m.aggField) col.aggField = m.aggField;
|
|
5187
|
+
if (m.aggFilter) col.aggFilter = canonical(m.aggFilter);
|
|
5188
|
+
return col;
|
|
5189
|
+
}).toSorted((a, b) => a.column < b.column ? -1 : a.column > b.column ? 1 : 0);
|
|
5190
|
+
const result = {
|
|
5191
|
+
tableName: view.tableName,
|
|
5192
|
+
viewType: plan.materialized ? "M" : "V",
|
|
5193
|
+
entryTable: plan.entryTable,
|
|
5194
|
+
joinTables: plan.joins.map((j) => {
|
|
5195
|
+
const join = {
|
|
5196
|
+
targetTable: j.targetTable,
|
|
5197
|
+
condition: canonical(j.condition)
|
|
5198
|
+
};
|
|
5199
|
+
if (j.kind === "left") join.kind = "left";
|
|
5200
|
+
return join;
|
|
5201
|
+
}),
|
|
5202
|
+
columns
|
|
5203
|
+
};
|
|
5204
|
+
if (plan.filter) result.filterHash = fnv1a(canonical(plan.filter));
|
|
5205
|
+
if (plan.having) result.havingHash = fnv1a(canonical(plan.having));
|
|
5206
|
+
if (plan.materialized) result.materialized = true;
|
|
5207
|
+
const renderRevision = view.dbAdapter.viewRenderRevision();
|
|
5208
|
+
if (renderRevision !== void 0) result.renderRevision = renderRevision;
|
|
5209
|
+
return {
|
|
5210
|
+
...result,
|
|
5211
|
+
fields
|
|
5212
|
+
};
|
|
5213
|
+
}
|
|
5214
|
+
/**
|
|
5215
|
+
* Converts a view predicate (join condition, `@db.view.filter`,
|
|
5216
|
+
* `@db.view.having`) into a serializable structure whose JSON is a stable
|
|
5217
|
+
* function of its MEANING: field refs become `qualify(ref)` — the view's
|
|
5218
|
+
* `resolveFieldRef(ref, (n) => n)`, i.e. `"<table>.<field>"`, so a predicate
|
|
5219
|
+
* retargeted to another table with the same field name changes — operators
|
|
5220
|
+
* and literal values are kept as-is, `$and`/`$or` keep declaration order, and
|
|
5221
|
+
* no function references survive. Two identical models produce byte-identical
|
|
5222
|
+
* JSON.
|
|
5223
|
+
* @since 0.1.128
|
|
5224
|
+
*/
|
|
5225
|
+
function canonicalizeQueryNode(node, qualify) {
|
|
5226
|
+
if ("$and" in node) return { and: node.$and.map((n) => canonicalizeQueryNode(n, qualify)) };
|
|
5227
|
+
if ("$or" in node) return { or: node.$or.map((n) => canonicalizeQueryNode(n, qualify)) };
|
|
5228
|
+
if ("$not" in node) return { not: canonicalizeQueryNode(node.$not, qualify) };
|
|
5229
|
+
const comp = node;
|
|
5230
|
+
const out = {
|
|
5231
|
+
l: qualify(comp.left),
|
|
5232
|
+
op: comp.op
|
|
5233
|
+
};
|
|
5234
|
+
if (comp.right !== void 0) out.r = comp.right !== null && typeof comp.right === "object" && "field" in comp.right ? { f: qualify(comp.right) } : comp.right;
|
|
5235
|
+
return out;
|
|
5236
|
+
}
|
|
5237
|
+
/**
|
|
5238
|
+
* Computes a deterministic hash string from multiple table snapshots.
|
|
5239
|
+
* Uses FNV-1a for speed — not cryptographic, just needs stability + collision resistance.
|
|
5240
|
+
*/
|
|
5241
|
+
function computeSchemaHash(snapshots) {
|
|
5242
|
+
const sorted = [...snapshots].toSorted((a, b) => a.tableName.localeCompare(b.tableName));
|
|
5243
|
+
return fnv1a(JSON.stringify(sorted));
|
|
5244
|
+
}
|
|
5245
|
+
/**
|
|
5246
|
+
* Computes a hash for a single table/view snapshot.
|
|
5247
|
+
* Used for per-table change detection via stored snapshots.
|
|
5248
|
+
*/
|
|
5249
|
+
function computeTableHash(snapshot) {
|
|
5250
|
+
return fnv1a(JSON.stringify(snapshot));
|
|
5251
|
+
}
|
|
5252
|
+
/**
|
|
5253
|
+
* Converts stored snapshot fields to `TExistingColumn[]` format
|
|
5254
|
+
* for use with `computeColumnDiff`. Used by adapters that lack
|
|
5255
|
+
* native column introspection (e.g., MongoDB).
|
|
5256
|
+
*
|
|
5257
|
+
* The `type` field uses `mappedType` when available (adapter-specific),
|
|
5258
|
+
* falling back to `designType`.
|
|
5259
|
+
*/
|
|
5260
|
+
function snapshotToExistingColumns(snapshot) {
|
|
5261
|
+
return snapshot.fields.map((f) => ({
|
|
5262
|
+
name: f.physicalName,
|
|
5263
|
+
type: f.mappedType ?? f.designType,
|
|
5264
|
+
notnull: !f.optional,
|
|
5265
|
+
pk: f.isPrimaryKey,
|
|
5266
|
+
dflt_value: serializeDefaultValue(f.defaultValue)
|
|
5267
|
+
}));
|
|
5268
|
+
}
|
|
5269
|
+
/**
|
|
5270
|
+
* Extracts table options from a stored snapshot for diff comparison.
|
|
5271
|
+
* Used as fallback when an adapter lacks native table option introspection.
|
|
5272
|
+
*/
|
|
5273
|
+
function snapshotToExistingTableOptions(snapshot) {
|
|
5274
|
+
return snapshot.tableOptions ?? [];
|
|
5275
|
+
}
|
|
5276
|
+
/** Serializes a TDbDefaultValue to a comparable string. */
|
|
5277
|
+
function serializeDefaultValue(dv) {
|
|
5278
|
+
if (!dv) return;
|
|
5279
|
+
if (dv.kind === "value") return dv.value;
|
|
5280
|
+
return `fn:${dv.fn}`;
|
|
5281
|
+
}
|
|
5282
|
+
/** FNV-1a 32-bit hash → hex string */
|
|
5283
|
+
function fnv1a(str) {
|
|
5284
|
+
let hash = 2166136261;
|
|
5285
|
+
for (let i = 0; i < str.length; i++) {
|
|
5286
|
+
hash ^= str.codePointAt(i);
|
|
5287
|
+
hash = Math.imul(hash, 16777619);
|
|
5288
|
+
}
|
|
5289
|
+
return Math.trunc(hash).toString(16).padStart(8, "0");
|
|
5290
|
+
}
|
|
5291
|
+
//#endregion
|
|
5292
|
+
//#region src/schema/fk-diff.ts
|
|
5293
|
+
/** Canonical key for an FK: sorted local field names, comma-joined. */
|
|
5294
|
+
function fkKey(fields) {
|
|
5295
|
+
return [...fields].toSorted().join(",");
|
|
5296
|
+
}
|
|
5297
|
+
/**
|
|
5298
|
+
* Compares desired FK constraints against stored snapshot to detect
|
|
5299
|
+
* additions, removals, and property changes (target table, target fields,
|
|
5300
|
+
* onDelete, onUpdate).
|
|
5301
|
+
*/
|
|
5302
|
+
function computeForeignKeyDiff(desired, existingSnapshot) {
|
|
5303
|
+
const added = [];
|
|
5304
|
+
const removed = [];
|
|
5305
|
+
const changed = [];
|
|
5306
|
+
const existingByKey = /* @__PURE__ */ new Map();
|
|
5307
|
+
for (const fk of existingSnapshot) existingByKey.set(fkKey(fk.fields), fk);
|
|
5308
|
+
const desiredKeys = /* @__PURE__ */ new Set();
|
|
5309
|
+
for (const fk of desired.values()) {
|
|
5310
|
+
const key = fkKey(fk.fields);
|
|
5311
|
+
desiredKeys.add(key);
|
|
5312
|
+
const existing = existingByKey.get(key);
|
|
5313
|
+
if (!existing) added.push(fk);
|
|
5314
|
+
else if (fkPropertiesDiffer(fk, existing)) changed.push({
|
|
5315
|
+
desired: fk,
|
|
5316
|
+
existing
|
|
5317
|
+
});
|
|
5318
|
+
}
|
|
5319
|
+
for (const [key, fk] of existingByKey) if (!desiredKeys.has(key)) removed.push(fk);
|
|
5320
|
+
return {
|
|
5321
|
+
added,
|
|
5322
|
+
removed,
|
|
5323
|
+
changed
|
|
5324
|
+
};
|
|
5325
|
+
}
|
|
5326
|
+
/** Whether the FK diff contains any changes. */
|
|
5327
|
+
function hasForeignKeyChanges(diff) {
|
|
5328
|
+
return diff.added.length > 0 || diff.removed.length > 0 || diff.changed.length > 0;
|
|
5329
|
+
}
|
|
5330
|
+
function fkPropertiesDiffer(desired, existing) {
|
|
5331
|
+
if (desired.targetTable !== existing.targetTable) return true;
|
|
5332
|
+
if (fkKey(desired.targetFields) !== fkKey(existing.targetFields)) return true;
|
|
5333
|
+
if ((desired.onDelete ?? void 0) !== (existing.onDelete ?? void 0)) return true;
|
|
5334
|
+
if ((desired.onUpdate ?? void 0) !== (existing.onUpdate ?? void 0)) return true;
|
|
5335
|
+
return false;
|
|
5336
|
+
}
|
|
5337
|
+
//#endregion
|
|
5338
|
+
//#region src/schema/column-diff.ts
|
|
5339
|
+
/**
|
|
5340
|
+
* Whether a live column's type differs from the type the adapter's
|
|
5341
|
+
* `typeMapper` gives the field — the one rule schema sync diffs column types
|
|
5342
|
+
* by (case-insensitive). Exported for adapters that must agree with it (the
|
|
5343
|
+
* PostgreSQL recreate converts exactly the columns this reports changed).
|
|
5344
|
+
* @since 0.1.137
|
|
5345
|
+
*/
|
|
5346
|
+
function isColumnTypeChanged(existingType, expectedType) {
|
|
5347
|
+
return existingType.toUpperCase() !== expectedType.toUpperCase();
|
|
5348
|
+
}
|
|
5349
|
+
/**
|
|
5350
|
+
* Computes the difference between desired schema fields and existing database columns.
|
|
5351
|
+
*
|
|
5352
|
+
* @param desired - Field descriptors from the Atscript type (after flattening).
|
|
5353
|
+
* @param existing - Columns currently in the database (from introspection).
|
|
5354
|
+
* @param typeMapper - Optional function to map field metadata to DB-native type strings.
|
|
5355
|
+
* Receives the full field meta (design type, annotations, PK status, etc.)
|
|
5356
|
+
* so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
|
|
5357
|
+
* Required for type change detection.
|
|
5358
|
+
*/
|
|
5359
|
+
function computeColumnDiff(desired, existing, typeMapper) {
|
|
5360
|
+
const existingByName = new Map(existing.map((c) => [c.name, c]));
|
|
5361
|
+
const desiredByName = /* @__PURE__ */ new Map();
|
|
5362
|
+
const renamedOldNames = /* @__PURE__ */ new Set();
|
|
5363
|
+
const added = [];
|
|
5364
|
+
const renamed = [];
|
|
5365
|
+
const typeChanged = [];
|
|
5366
|
+
const nullableChanged = [];
|
|
5367
|
+
const defaultChanged = [];
|
|
5368
|
+
const conflicts = [];
|
|
5369
|
+
for (const field of desired) {
|
|
5370
|
+
if (field.ignored) continue;
|
|
5371
|
+
desiredByName.set(field.physicalName, field);
|
|
5372
|
+
const existingCol = existingByName.get(field.physicalName);
|
|
5373
|
+
if (existingCol) if (field.renamedFrom && existingByName.has(field.renamedFrom)) {
|
|
5374
|
+
conflicts.push({
|
|
5375
|
+
field,
|
|
5376
|
+
oldName: field.renamedFrom,
|
|
5377
|
+
conflictsWith: field.physicalName
|
|
5378
|
+
});
|
|
5379
|
+
renamedOldNames.add(field.renamedFrom);
|
|
5380
|
+
} else {
|
|
5381
|
+
if (typeMapper) {
|
|
5382
|
+
if (isColumnTypeChanged(existingCol.type, typeMapper(field))) typeChanged.push({
|
|
5383
|
+
field,
|
|
5384
|
+
existingType: existingCol.type
|
|
5385
|
+
});
|
|
5386
|
+
}
|
|
5387
|
+
if (!field.isPrimaryKey && !existingCol.pk) {
|
|
5388
|
+
const desiredNotNull = !field.optional;
|
|
5389
|
+
if (existingCol.notnull !== desiredNotNull) nullableChanged.push({
|
|
5390
|
+
field,
|
|
5391
|
+
wasNullable: !existingCol.notnull
|
|
5392
|
+
});
|
|
5393
|
+
}
|
|
5394
|
+
const desiredDefault = serializeDefaultValue(field.defaultValue);
|
|
5395
|
+
if (existingCol.dflt_value !== void 0 && existingCol.dflt_value !== desiredDefault) defaultChanged.push({
|
|
5396
|
+
field,
|
|
5397
|
+
oldDefault: existingCol.dflt_value,
|
|
5398
|
+
newDefault: desiredDefault
|
|
5399
|
+
});
|
|
5400
|
+
}
|
|
5401
|
+
else if (field.renamedFrom && existingByName.has(field.renamedFrom)) {
|
|
5402
|
+
renamed.push({
|
|
5403
|
+
field,
|
|
5404
|
+
oldName: field.renamedFrom
|
|
5405
|
+
});
|
|
5406
|
+
renamedOldNames.add(field.renamedFrom);
|
|
5407
|
+
} else added.push(field);
|
|
5408
|
+
}
|
|
5409
|
+
const diff = {
|
|
5410
|
+
added,
|
|
5411
|
+
removed: existing.filter((c) => !desiredByName.has(c.name) && !renamedOldNames.has(c.name)),
|
|
5412
|
+
renamed,
|
|
5413
|
+
typeChanged,
|
|
5414
|
+
nullableChanged,
|
|
5415
|
+
defaultChanged,
|
|
5416
|
+
conflicts
|
|
5417
|
+
};
|
|
5418
|
+
if (existing.length > 0) {
|
|
5419
|
+
const newNameByOld = new Map(renamed.map((r) => [r.oldName, r.field.physicalName]));
|
|
5420
|
+
const from = existing.filter((c) => c.pk).map((c) => newNameByOld.get(c.name) ?? c.name);
|
|
5421
|
+
const to = desired.filter((f) => !f.ignored && f.isPrimaryKey).map((f) => f.physicalName);
|
|
5422
|
+
if (fkKey(from) !== fkKey(to)) diff.primaryKeyChanged = {
|
|
5423
|
+
from,
|
|
5424
|
+
to
|
|
5425
|
+
};
|
|
5426
|
+
}
|
|
5427
|
+
return diff;
|
|
5428
|
+
}
|
|
5429
|
+
//#endregion
|
|
5053
5430
|
Object.defineProperty(exports, "ADAPTER_FILTER_REASON", {
|
|
5054
5431
|
enumerable: true,
|
|
5055
5432
|
get: function() {
|
|
@@ -5176,6 +5553,12 @@ Object.defineProperty(exports, "canFilterLeaf", {
|
|
|
5176
5553
|
return canFilterLeaf;
|
|
5177
5554
|
}
|
|
5178
5555
|
});
|
|
5556
|
+
Object.defineProperty(exports, "canonicalizeQueryNode", {
|
|
5557
|
+
enumerable: true,
|
|
5558
|
+
get: function() {
|
|
5559
|
+
return canonicalizeQueryNode;
|
|
5560
|
+
}
|
|
5561
|
+
});
|
|
5179
5562
|
Object.defineProperty(exports, "checkHavingKeys", {
|
|
5180
5563
|
enumerable: true,
|
|
5181
5564
|
get: function() {
|
|
@@ -5194,6 +5577,42 @@ Object.defineProperty(exports, "collectQueryPaths", {
|
|
|
5194
5577
|
return collectQueryPaths;
|
|
5195
5578
|
}
|
|
5196
5579
|
});
|
|
5580
|
+
Object.defineProperty(exports, "computeColumnDiff", {
|
|
5581
|
+
enumerable: true,
|
|
5582
|
+
get: function() {
|
|
5583
|
+
return computeColumnDiff;
|
|
5584
|
+
}
|
|
5585
|
+
});
|
|
5586
|
+
Object.defineProperty(exports, "computeForeignKeyDiff", {
|
|
5587
|
+
enumerable: true,
|
|
5588
|
+
get: function() {
|
|
5589
|
+
return computeForeignKeyDiff;
|
|
5590
|
+
}
|
|
5591
|
+
});
|
|
5592
|
+
Object.defineProperty(exports, "computeSchemaHash", {
|
|
5593
|
+
enumerable: true,
|
|
5594
|
+
get: function() {
|
|
5595
|
+
return computeSchemaHash;
|
|
5596
|
+
}
|
|
5597
|
+
});
|
|
5598
|
+
Object.defineProperty(exports, "computeTableHash", {
|
|
5599
|
+
enumerable: true,
|
|
5600
|
+
get: function() {
|
|
5601
|
+
return computeTableHash;
|
|
5602
|
+
}
|
|
5603
|
+
});
|
|
5604
|
+
Object.defineProperty(exports, "computeTableSnapshot", {
|
|
5605
|
+
enumerable: true,
|
|
5606
|
+
get: function() {
|
|
5607
|
+
return computeTableSnapshot;
|
|
5608
|
+
}
|
|
5609
|
+
});
|
|
5610
|
+
Object.defineProperty(exports, "computeViewSnapshot", {
|
|
5611
|
+
enumerable: true,
|
|
5612
|
+
get: function() {
|
|
5613
|
+
return computeViewSnapshot;
|
|
5614
|
+
}
|
|
5615
|
+
});
|
|
5197
5616
|
Object.defineProperty(exports, "createFailureCollector", {
|
|
5198
5617
|
enumerable: true,
|
|
5199
5618
|
get: function() {
|
|
@@ -5212,6 +5631,12 @@ Object.defineProperty(exports, "findAncestorInSet", {
|
|
|
5212
5631
|
return findAncestorInSet;
|
|
5213
5632
|
}
|
|
5214
5633
|
});
|
|
5634
|
+
Object.defineProperty(exports, "fkKey", {
|
|
5635
|
+
enumerable: true,
|
|
5636
|
+
get: function() {
|
|
5637
|
+
return fkKey;
|
|
5638
|
+
}
|
|
5639
|
+
});
|
|
5215
5640
|
Object.defineProperty(exports, "guardAggregate", {
|
|
5216
5641
|
enumerable: true,
|
|
5217
5642
|
get: function() {
|
|
@@ -5242,6 +5667,12 @@ Object.defineProperty(exports, "guardQuery", {
|
|
|
5242
5667
|
return guardQuery;
|
|
5243
5668
|
}
|
|
5244
5669
|
});
|
|
5670
|
+
Object.defineProperty(exports, "hasForeignKeyChanges", {
|
|
5671
|
+
enumerable: true,
|
|
5672
|
+
get: function() {
|
|
5673
|
+
return hasForeignKeyChanges;
|
|
5674
|
+
}
|
|
5675
|
+
});
|
|
5245
5676
|
Object.defineProperty(exports, "isAtscriptDbView", {
|
|
5246
5677
|
enumerable: true,
|
|
5247
5678
|
get: function() {
|
|
@@ -5254,6 +5685,12 @@ Object.defineProperty(exports, "isBucketableField", {
|
|
|
5254
5685
|
return isBucketableField;
|
|
5255
5686
|
}
|
|
5256
5687
|
});
|
|
5688
|
+
Object.defineProperty(exports, "isColumnTypeChanged", {
|
|
5689
|
+
enumerable: true,
|
|
5690
|
+
get: function() {
|
|
5691
|
+
return isColumnTypeChanged;
|
|
5692
|
+
}
|
|
5693
|
+
});
|
|
5257
5694
|
Object.defineProperty(exports, "isGeoIndexableType", {
|
|
5258
5695
|
enumerable: true,
|
|
5259
5696
|
get: function() {
|
|
@@ -5302,6 +5739,18 @@ Object.defineProperty(exports, "resolveDesignType", {
|
|
|
5302
5739
|
return resolveDesignType;
|
|
5303
5740
|
}
|
|
5304
5741
|
});
|
|
5742
|
+
Object.defineProperty(exports, "snapshotToExistingColumns", {
|
|
5743
|
+
enumerable: true,
|
|
5744
|
+
get: function() {
|
|
5745
|
+
return snapshotToExistingColumns;
|
|
5746
|
+
}
|
|
5747
|
+
});
|
|
5748
|
+
Object.defineProperty(exports, "snapshotToExistingTableOptions", {
|
|
5749
|
+
enumerable: true,
|
|
5750
|
+
get: function() {
|
|
5751
|
+
return snapshotToExistingTableOptions;
|
|
5752
|
+
}
|
|
5753
|
+
});
|
|
5305
5754
|
Object.defineProperty(exports, "sortFieldNames", {
|
|
5306
5755
|
enumerable: true,
|
|
5307
5756
|
get: function() {
|