@atscript/db 0.1.39 → 0.1.40
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/README.md +18 -18
- package/dist/agg.cjs +8 -3
- package/dist/agg.d.cts +7 -0
- package/dist/agg.d.mts +7 -0
- package/dist/agg.mjs +7 -3
- package/dist/control-DRgryKeg.cjs +14 -0
- package/dist/{control_as-bjmwe24C.mjs → control-IANbnfjG.mjs} +6 -18
- package/dist/db-readable-BQQzfguJ.d.cts +1249 -0
- package/dist/db-readable-Bbr4CjMb.d.mts +1249 -0
- package/dist/db-space-BUrQ5BFm.d.mts +309 -0
- package/dist/db-space-Vxpcnyt5.d.cts +309 -0
- package/dist/db-validator-plugin-07kDiis2.d.cts +22 -0
- package/dist/db-validator-plugin-CiqsHTI_.d.mts +22 -0
- package/dist/db-view-BntnAmXO.cjs +3071 -0
- package/dist/db-view-ZsoN91-q.mjs +2970 -0
- package/dist/index.cjs +95 -2801
- package/dist/index.d.cts +137 -0
- package/dist/index.d.mts +137 -0
- package/dist/index.mjs +55 -2761
- package/dist/{nested-writer-BkqL7cp3.cjs → nested-writer-BDXsDMPP.cjs} +196 -150
- package/dist/{nested-writer-NEN51mnR.mjs → nested-writer-Dmm1gbZV.mjs} +118 -70
- package/dist/ops-BdRAFLKY.d.mts +67 -0
- package/dist/ops-DXJ4Zw0P.d.cts +67 -0
- package/dist/ops.cjs +123 -0
- package/dist/ops.d.cts +2 -0
- package/dist/ops.d.mts +2 -0
- package/dist/ops.mjs +112 -0
- package/dist/plugin.cjs +90 -109
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.mts +6 -0
- package/dist/plugin.mjs +29 -49
- package/dist/rel.cjs +20 -20
- package/dist/rel.d.cts +119 -0
- package/dist/rel.d.mts +119 -0
- package/dist/rel.mjs +4 -5
- package/dist/{relation-helpers-guFL_oRf.cjs → relation-helpers-BYvsE1tR.cjs} +26 -22
- package/dist/{relation-helpers-DyBIlQnB.mjs → relation-helpers-CLasawQq.mjs} +11 -6
- package/dist/{relation-loader-Dv7qXYq7.mjs → relation-loader-BEOTXNcq.mjs} +63 -43
- package/dist/{relation-loader-CpnDRf9k.cjs → relation-loader-CRC5LcqM.cjs} +74 -49
- package/dist/shared.cjs +13 -13
- package/dist/{shared.d.ts → shared.d.cts} +14 -13
- package/dist/shared.d.mts +71 -0
- package/dist/shared.mjs +2 -3
- package/dist/sync.cjs +300 -252
- package/dist/sync.d.cts +369 -0
- package/dist/sync.d.mts +369 -0
- package/dist/sync.mjs +284 -233
- package/dist/{validation-utils-DEoCMmEb.cjs → validation-utils-DVJDijnB.cjs} +141 -109
- package/dist/{validation-utils-DhR_mtKa.mjs → validation-utils-DhjIjP1-.mjs} +71 -37
- package/package.json +30 -29
- package/LICENSE +0 -21
- package/dist/agg-BJFJ3dFQ.mjs +0 -8
- package/dist/agg-DnUWAOK8.cjs +0 -14
- package/dist/agg.d.ts +0 -13
- package/dist/chunk-CrpGerW8.cjs +0 -31
- package/dist/control_as-BFPERAF_.cjs +0 -28
- package/dist/index.d.ts +0 -1706
- package/dist/logger-B7oxCfLQ.mjs +0 -12
- package/dist/logger-Dt2v_-wb.cjs +0 -18
- package/dist/plugin.d.ts +0 -5
- package/dist/rel.d.ts +0 -1305
- package/dist/relation-loader-D4mTw6yH.cjs +0 -4
- package/dist/relation-loader-Ggy1ujwR.mjs +0 -4
- package/dist/sync.d.ts +0 -1878
|
@@ -1,43 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const __atscript_typescript_utils = require_chunk.__toESM(require("@atscript/typescript/utils"));
|
|
5
|
-
|
|
6
|
-
//#region packages/db/src/db-error.ts
|
|
7
|
-
function _define_property(obj, key, value) {
|
|
8
|
-
if (key in obj) Object.defineProperty(obj, key, {
|
|
9
|
-
value,
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
writable: true
|
|
13
|
-
});
|
|
14
|
-
else obj[key] = value;
|
|
15
|
-
return obj;
|
|
16
|
-
}
|
|
1
|
+
const require_relation_helpers = require("./relation-helpers-BYvsE1tR.cjs");
|
|
2
|
+
let _atscript_typescript_utils = require("@atscript/typescript/utils");
|
|
3
|
+
//#region src/db-error.ts
|
|
17
4
|
var DbError = class extends Error {
|
|
5
|
+
name = "DbError";
|
|
18
6
|
constructor(code, errors, message) {
|
|
19
|
-
super(message ?? errors[0]?.message ?? "Database error")
|
|
20
|
-
this.
|
|
7
|
+
super(message ?? errors[0]?.message ?? "Database error");
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.errors = errors;
|
|
10
|
+
this.stack = void 0;
|
|
21
11
|
}
|
|
22
12
|
};
|
|
23
|
-
|
|
24
13
|
//#endregion
|
|
25
|
-
//#region
|
|
14
|
+
//#region src/table/error-utils.ts
|
|
15
|
+
/**
|
|
16
|
+
* Prefixes error paths with a nav field context.
|
|
17
|
+
* Ensures errors from child table operations (e.g., FK violations on a comment)
|
|
18
|
+
* get paths like `comments[0].authorId` instead of just `authorId`.
|
|
19
|
+
*/
|
|
26
20
|
function prefixErrorPaths(errors, prefix) {
|
|
27
21
|
return errors.map((err) => ({
|
|
28
22
|
...err,
|
|
29
23
|
path: err.path ? `${prefix}.${err.path}` : prefix
|
|
30
24
|
}));
|
|
31
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Wraps an async nested operation and prefixes error paths with the nav field context.
|
|
28
|
+
*/
|
|
32
29
|
async function wrapNestedError(navField, fn) {
|
|
33
30
|
try {
|
|
34
31
|
return await fn();
|
|
35
32
|
} catch (error) {
|
|
36
|
-
if (error instanceof
|
|
33
|
+
if (error instanceof _atscript_typescript_utils.ValidatorError) throw new _atscript_typescript_utils.ValidatorError(prefixErrorPaths(error.errors, navField));
|
|
37
34
|
if (error instanceof DbError) throw new DbError(error.code, prefixErrorPaths(error.errors, navField));
|
|
38
35
|
throw error;
|
|
39
36
|
}
|
|
40
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Catches `DbError('FK_VIOLATION')` with empty paths (from adapters that
|
|
40
|
+
* enforce FKs natively but can't report which field failed) and enriches
|
|
41
|
+
* the error with all FK field names from table metadata.
|
|
42
|
+
*/
|
|
41
43
|
async function enrichFkViolation(meta, fn) {
|
|
42
44
|
try {
|
|
43
45
|
return await fn();
|
|
@@ -54,6 +56,10 @@ async function enrichFkViolation(meta, fn) {
|
|
|
54
56
|
throw error;
|
|
55
57
|
}
|
|
56
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Wraps a delete operation: catches native `FK_VIOLATION` errors (e.g. SQLite
|
|
61
|
+
* RESTRICT) and re-throws as `CONFLICT` (409) with a descriptive message.
|
|
62
|
+
*/
|
|
57
63
|
async function remapDeleteFkViolation(tableName, fn) {
|
|
58
64
|
try {
|
|
59
65
|
return await fn();
|
|
@@ -65,24 +71,35 @@ async function remapDeleteFkViolation(tableName, fn) {
|
|
|
65
71
|
throw error;
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
|
-
|
|
69
74
|
//#endregion
|
|
70
|
-
//#region
|
|
75
|
+
//#region src/rel/nested-writer.ts
|
|
76
|
+
/**
|
|
77
|
+
* Checks if any payload contains navigational data that would be silently
|
|
78
|
+
* dropped because maxDepth is 0.
|
|
79
|
+
*/
|
|
71
80
|
function checkDepthOverflow(payloads, maxDepth, meta) {
|
|
72
81
|
if (meta.navFields.size === 0) return;
|
|
73
|
-
for (const payload of payloads) for (const navField of meta.navFields) if (payload[navField] !==
|
|
82
|
+
for (const payload of payloads) for (const navField of meta.navFields) if (payload[navField] !== void 0) throw new Error(`Nested data in '${navField}' exceeds maxDepth (${maxDepth}). Increase maxDepth or strip nested data before writing.`);
|
|
74
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Validates a batch of items using the given validator and context.
|
|
86
|
+
* Wraps per-item validation errors with array index paths for batch operations.
|
|
87
|
+
*/
|
|
75
88
|
function validateBatch(validator, items, ctx) {
|
|
76
89
|
for (let i = 0; i < items.length; i++) try {
|
|
77
90
|
validator.validate(items[i], false, ctx);
|
|
78
91
|
} catch (error) {
|
|
79
|
-
if (error instanceof
|
|
92
|
+
if (error instanceof _atscript_typescript_utils.ValidatorError && items.length > 1) throw new _atscript_typescript_utils.ValidatorError(error.errors.map((err) => ({
|
|
80
93
|
...err,
|
|
81
94
|
path: `[${i}].${err.path}`
|
|
82
95
|
})));
|
|
83
96
|
throw error;
|
|
84
97
|
}
|
|
85
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Pre-validates FROM children (type + FK constraints) before the main insert.
|
|
101
|
+
* Catches errors early before the parent record is committed.
|
|
102
|
+
*/
|
|
86
103
|
async function preValidateNestedFrom(host, originals) {
|
|
87
104
|
for (const [navField, relation] of host._meta.relations) {
|
|
88
105
|
if (relation.direction !== "from") continue;
|
|
@@ -106,6 +123,9 @@ async function preValidateNestedFrom(host, originals) {
|
|
|
106
123
|
await wrapNestedError(navField, () => targetTable.preValidateItems(allChildren, { excludeFkTargetTable: host.tableName }));
|
|
107
124
|
}
|
|
108
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Batch-creates TO dependencies before the main insert.
|
|
128
|
+
*/
|
|
109
129
|
async function batchInsertNestedTo(host, items, maxDepth, depth) {
|
|
110
130
|
for (const [navField, relation] of host._meta.relations) {
|
|
111
131
|
if (relation.direction !== "to") continue;
|
|
@@ -130,6 +150,9 @@ async function batchInsertNestedTo(host, items, maxDepth, depth) {
|
|
|
130
150
|
for (let j = 0; j < sourceIndices.length; j++) if (fk.localFields.length === 1) items[sourceIndices[j]][fk.localFields[0]] = result.insertedIds[j];
|
|
131
151
|
}
|
|
132
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Batch-creates FROM dependents after the main insert.
|
|
155
|
+
*/
|
|
133
156
|
async function batchInsertNestedFrom(host, originals, parentIds, maxDepth, depth) {
|
|
134
157
|
for (const [navField, relation] of host._meta.relations) {
|
|
135
158
|
if (relation.direction !== "from") continue;
|
|
@@ -154,6 +177,9 @@ async function batchInsertNestedFrom(host, originals, parentIds, maxDepth, depth
|
|
|
154
177
|
}));
|
|
155
178
|
}
|
|
156
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Batch-creates VIA (M:N) targets and junction entries after the main insert.
|
|
182
|
+
*/
|
|
157
183
|
async function batchInsertNestedVia(host, originals, parentIds, maxDepth, depth) {
|
|
158
184
|
for (const [navField, relation] of host._meta.relations) {
|
|
159
185
|
if (relation.direction !== "via" || !relation.viaType) continue;
|
|
@@ -172,14 +198,14 @@ async function batchInsertNestedVia(host, originals, parentIds, maxDepth, depth)
|
|
|
172
198
|
const targets = originals[i][navField];
|
|
173
199
|
if (!Array.isArray(targets) || targets.length === 0) continue;
|
|
174
200
|
const parentPK = parentIds[i];
|
|
175
|
-
if (parentPK ===
|
|
201
|
+
if (parentPK === void 0) continue;
|
|
176
202
|
const newTargets = [];
|
|
177
203
|
const existingIds = [];
|
|
178
204
|
for (const t of targets) {
|
|
179
205
|
const rec = t;
|
|
180
206
|
const pk = rec[targetPKField];
|
|
181
|
-
if (pk !==
|
|
182
|
-
else newTargets.push({ ...rec });
|
|
207
|
+
if (pk !== void 0 && pk !== null) existingIds.push(pk);
|
|
208
|
+
else newTargets.push({ ...rec });
|
|
183
209
|
}
|
|
184
210
|
const allTargetIds = [...existingIds];
|
|
185
211
|
if (newTargets.length > 0) {
|
|
@@ -199,6 +225,9 @@ else newTargets.push({ ...rec });
|
|
|
199
225
|
}
|
|
200
226
|
}
|
|
201
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Batch-replaces TO dependencies before the main replace.
|
|
230
|
+
*/
|
|
202
231
|
async function batchReplaceNestedTo(host, items, maxDepth, depth) {
|
|
203
232
|
for (const [navField, relation] of host._meta.relations) {
|
|
204
233
|
if (relation.direction !== "to") continue;
|
|
@@ -223,6 +252,9 @@ async function batchReplaceNestedTo(host, items, maxDepth, depth) {
|
|
|
223
252
|
for (let j = 0; j < sourceIndices.length; j++) if (fk.localFields.length === 1 && fk.targetFields.length === 1) items[sourceIndices[j]][fk.localFields[0]] = parents[j][fk.targetFields[0]];
|
|
224
253
|
}
|
|
225
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Batch-replaces FROM dependents after the main replace.
|
|
257
|
+
*/
|
|
226
258
|
async function batchReplaceNestedFrom(host, originals, maxDepth, depth) {
|
|
227
259
|
for (const [navField, relation] of host._meta.relations) {
|
|
228
260
|
if (relation.direction !== "from") continue;
|
|
@@ -234,12 +266,15 @@ async function batchReplaceNestedFrom(host, originals, maxDepth, depth) {
|
|
|
234
266
|
for (const original of originals) {
|
|
235
267
|
const children = original[navField];
|
|
236
268
|
if (!Array.isArray(children)) continue;
|
|
237
|
-
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] :
|
|
238
|
-
if (parentPK ===
|
|
269
|
+
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] : void 0;
|
|
270
|
+
if (parentPK === void 0 || remoteFK.fields.length !== 1) continue;
|
|
239
271
|
await fromReplace(targetTable, children, parentPK, remoteFK.fields[0], childPKs, navField, maxDepth, depth);
|
|
240
272
|
}
|
|
241
273
|
}
|
|
242
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Handles VIA (M:N) relations during replace.
|
|
277
|
+
*/
|
|
243
278
|
async function batchReplaceNestedVia(host, originals, maxDepth, depth) {
|
|
244
279
|
for (const [navField, relation] of host._meta.relations) {
|
|
245
280
|
if (relation.direction !== "via" || !relation.viaType) continue;
|
|
@@ -257,12 +292,16 @@ async function batchReplaceNestedVia(host, originals, maxDepth, depth) {
|
|
|
257
292
|
for (const original of originals) {
|
|
258
293
|
const targets = original[navField];
|
|
259
294
|
if (!Array.isArray(targets)) continue;
|
|
260
|
-
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] :
|
|
261
|
-
if (parentPK ===
|
|
295
|
+
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] : void 0;
|
|
296
|
+
if (parentPK === void 0) continue;
|
|
262
297
|
await viaReplace(targetTable, junctionTable, targets, parentPK, targetPKField, fkToThis.fields[0], fkToTarget.fields[0], maxDepth, depth);
|
|
263
298
|
}
|
|
264
299
|
}
|
|
265
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Batch-patches TO dependencies before the main patch.
|
|
303
|
+
* Reads FK values from DB if not present in the payload.
|
|
304
|
+
*/
|
|
266
305
|
async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
267
306
|
for (const [navField, relation] of host._meta.relations) {
|
|
268
307
|
if (relation.direction !== "to") continue;
|
|
@@ -275,8 +314,8 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
275
314
|
const nested = item[navField];
|
|
276
315
|
if (!nested || typeof nested !== "object" || Array.isArray(nested)) continue;
|
|
277
316
|
const patch = { ...nested };
|
|
278
|
-
let fkValue = fk.localFields.length === 1 ? item[fk.localFields[0]] :
|
|
279
|
-
if (fkValue ===
|
|
317
|
+
let fkValue = fk.localFields.length === 1 ? item[fk.localFields[0]] : void 0;
|
|
318
|
+
if (fkValue === void 0) {
|
|
280
319
|
const pkFilter = host._extractPrimaryKeyFilter(item);
|
|
281
320
|
const current = await host.findOne({
|
|
282
321
|
filter: pkFilter,
|
|
@@ -286,9 +325,9 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
286
325
|
path: navField,
|
|
287
326
|
message: `Cannot patch relation '${navField}' — source record not found`
|
|
288
327
|
}]);
|
|
289
|
-
fkValue = fk.localFields.length === 1 ? current[fk.localFields[0]] :
|
|
328
|
+
fkValue = fk.localFields.length === 1 ? current[fk.localFields[0]] : void 0;
|
|
290
329
|
}
|
|
291
|
-
if (fkValue === null || fkValue ===
|
|
330
|
+
if (fkValue === null || fkValue === void 0) throw new DbError("FK_VIOLATION", [{
|
|
292
331
|
path: fk.localFields[0],
|
|
293
332
|
message: `Cannot patch relation '${navField}' — foreign key '${fk.localFields[0]}' is null`
|
|
294
333
|
}]);
|
|
@@ -302,6 +341,10 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
302
341
|
});
|
|
303
342
|
}
|
|
304
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Batch-patches FROM (1:N) dependencies after the main patch.
|
|
346
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
347
|
+
*/
|
|
305
348
|
async function batchPatchNestedFrom(host, originals, maxDepth, depth) {
|
|
306
349
|
for (const [navField, relation] of host._meta.relations) {
|
|
307
350
|
if (relation.direction !== "from") continue;
|
|
@@ -312,9 +355,9 @@ async function batchPatchNestedFrom(host, originals, maxDepth, depth) {
|
|
|
312
355
|
const childPKs = [...targetTable.primaryKeys];
|
|
313
356
|
for (const original of originals) {
|
|
314
357
|
const navValue = original[navField];
|
|
315
|
-
if (navValue ===
|
|
316
|
-
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] :
|
|
317
|
-
if (parentPK ===
|
|
358
|
+
if (navValue === void 0 || navValue === null) continue;
|
|
359
|
+
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] : void 0;
|
|
360
|
+
if (parentPK === void 0 || remoteFK.fields.length !== 1) continue;
|
|
318
361
|
const fkField = remoteFK.fields[0];
|
|
319
362
|
const ops = extractNavPatchOps(navValue);
|
|
320
363
|
if (ops.replace) await fromReplace(targetTable, ops.replace, parentPK, fkField, childPKs, navField, maxDepth, depth);
|
|
@@ -327,7 +370,7 @@ async function batchPatchNestedFrom(host, originals, maxDepth, depth) {
|
|
|
327
370
|
return f;
|
|
328
371
|
});
|
|
329
372
|
if (removeFilters.length === 1) await targetTable.deleteMany(removeFilters[0]);
|
|
330
|
-
else await targetTable.deleteMany({ $or: removeFilters });
|
|
373
|
+
else await targetTable.deleteMany({ $or: removeFilters });
|
|
331
374
|
}
|
|
332
375
|
if (ops.update && ops.update.length > 0) {
|
|
333
376
|
const items = ops.update.map((child) => {
|
|
@@ -346,9 +389,8 @@ else await targetTable.deleteMany({ $or: removeFilters });
|
|
|
346
389
|
for (const child of ops.upsert) {
|
|
347
390
|
const rec = { ...child };
|
|
348
391
|
rec[fkField] = parentPK;
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
else toInsert.push(rec);
|
|
392
|
+
if (childPKs.length > 0 && childPKs.every((pk) => rec[pk] !== void 0)) toUpdate.push(rec);
|
|
393
|
+
else toInsert.push(rec);
|
|
352
394
|
}
|
|
353
395
|
if (toUpdate.length > 0) await wrapNestedError(navField, () => targetTable.bulkUpdate(toUpdate, {
|
|
354
396
|
maxDepth,
|
|
@@ -360,11 +402,12 @@ else toInsert.push(rec);
|
|
|
360
402
|
}));
|
|
361
403
|
}
|
|
362
404
|
if (ops.insert && ops.insert.length > 0) {
|
|
363
|
-
const items =
|
|
364
|
-
|
|
405
|
+
const items = [];
|
|
406
|
+
for (let i = 0; i < ops.insert.length; i++) {
|
|
407
|
+
const rec = { ...ops.insert[i] };
|
|
365
408
|
rec[fkField] = parentPK;
|
|
366
|
-
|
|
367
|
-
}
|
|
409
|
+
items.push(rec);
|
|
410
|
+
}
|
|
368
411
|
await wrapNestedError(navField, () => targetTable.insertMany(items, {
|
|
369
412
|
maxDepth,
|
|
370
413
|
_depth: depth + 1
|
|
@@ -373,6 +416,10 @@ else toInsert.push(rec);
|
|
|
373
416
|
}
|
|
374
417
|
}
|
|
375
418
|
}
|
|
419
|
+
/**
|
|
420
|
+
* Batch-patches VIA (M:N) dependencies after the main patch.
|
|
421
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
422
|
+
*/
|
|
376
423
|
async function batchPatchNestedVia(host, originals, maxDepth, depth) {
|
|
377
424
|
for (const [navField, relation] of host._meta.relations) {
|
|
378
425
|
if (relation.direction !== "via" || !relation.viaType) continue;
|
|
@@ -389,18 +436,18 @@ async function batchPatchNestedVia(host, originals, maxDepth, depth) {
|
|
|
389
436
|
if (!targetPKField || fkToTarget.fields.length !== 1 || fkToThis.fields.length !== 1) continue;
|
|
390
437
|
for (const original of originals) {
|
|
391
438
|
const navValue = original[navField];
|
|
392
|
-
if (navValue ===
|
|
393
|
-
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] :
|
|
394
|
-
if (parentPK ===
|
|
439
|
+
if (navValue === void 0 || navValue === null) continue;
|
|
440
|
+
const parentPK = host._meta.primaryKeys.length === 1 ? original[host._meta.primaryKeys[0]] : void 0;
|
|
441
|
+
if (parentPK === void 0) continue;
|
|
395
442
|
const ops = extractNavPatchOps(navValue);
|
|
396
443
|
if (ops.replace) await viaReplace(targetTable, junctionTable, ops.replace, parentPK, targetPKField, fkToThis.fields[0], fkToTarget.fields[0], maxDepth, depth);
|
|
397
444
|
if (ops.remove && ops.remove.length > 0) {
|
|
398
|
-
const targetPKs = ops.remove.map((t) => t[targetPKField]).filter((pk) => pk !==
|
|
445
|
+
const targetPKs = ops.remove.map((t) => t[targetPKField]).filter((pk) => pk !== void 0 && pk !== null);
|
|
399
446
|
if (targetPKs.length === 1) await junctionTable.deleteMany({
|
|
400
447
|
[fkToThis.fields[0]]: parentPK,
|
|
401
448
|
[fkToTarget.fields[0]]: targetPKs[0]
|
|
402
449
|
});
|
|
403
|
-
else if (targetPKs.length > 1) await junctionTable.deleteMany({
|
|
450
|
+
else if (targetPKs.length > 1) await junctionTable.deleteMany({
|
|
404
451
|
[fkToThis.fields[0]]: parentPK,
|
|
405
452
|
[fkToTarget.fields[0]]: { $in: targetPKs }
|
|
406
453
|
});
|
|
@@ -416,7 +463,7 @@ else if (targetPKs.length > 1) await junctionTable.deleteMany({
|
|
|
416
463
|
for (const target of ops.upsert) {
|
|
417
464
|
const rec = { ...target };
|
|
418
465
|
const pk = rec[targetPKField];
|
|
419
|
-
if (pk !==
|
|
466
|
+
if (pk !== void 0 && pk !== null) {
|
|
420
467
|
toUpdate.push(rec);
|
|
421
468
|
existingPKs.push(pk);
|
|
422
469
|
} else toInsert.push(rec);
|
|
@@ -444,11 +491,10 @@ else if (targetPKs.length > 1) await junctionTable.deleteMany({
|
|
|
444
491
|
}
|
|
445
492
|
}
|
|
446
493
|
if (toInsert.length > 0) {
|
|
447
|
-
const
|
|
494
|
+
const junctionRows = (await targetTable.insertMany(toInsert, {
|
|
448
495
|
maxDepth,
|
|
449
496
|
_depth: depth + 1
|
|
450
|
-
})
|
|
451
|
-
const junctionRows = insertResult.insertedIds.map((newId) => ({
|
|
497
|
+
})).insertedIds.map((newId) => ({
|
|
452
498
|
[fkToThis.fields[0]]: parentPK,
|
|
453
499
|
[fkToTarget.fields[0]]: newId
|
|
454
500
|
}));
|
|
@@ -461,8 +507,8 @@ else if (targetPKs.length > 1) await junctionTable.deleteMany({
|
|
|
461
507
|
for (const target of ops.insert) {
|
|
462
508
|
const rec = { ...target };
|
|
463
509
|
const pk = rec[targetPKField];
|
|
464
|
-
if (pk !==
|
|
465
|
-
else toInsert.push(rec);
|
|
510
|
+
if (pk !== void 0 && pk !== null) existingIds.push(pk);
|
|
511
|
+
else toInsert.push(rec);
|
|
466
512
|
}
|
|
467
513
|
const allIds = [...existingIds];
|
|
468
514
|
if (toInsert.length > 0) {
|
|
@@ -486,29 +532,30 @@ else toInsert.push(rec);
|
|
|
486
532
|
/**
|
|
487
533
|
* Extracts patch operations from a nav field value.
|
|
488
534
|
* Plain array → $replace. Object with $insert, $remove, etc. → individual ops.
|
|
489
|
-
*/
|
|
535
|
+
*/
|
|
536
|
+
function extractNavPatchOps(navValue) {
|
|
490
537
|
if (Array.isArray(navValue)) return { replace: navValue };
|
|
491
538
|
if (typeof navValue !== "object" || navValue === null) return {};
|
|
492
539
|
const obj = navValue;
|
|
493
540
|
return {
|
|
494
|
-
replace: obj.$replace !==
|
|
495
|
-
insert: obj.$insert !==
|
|
496
|
-
remove: obj.$remove !==
|
|
497
|
-
update: obj.$update !==
|
|
498
|
-
upsert: obj.$upsert !==
|
|
541
|
+
replace: obj.$replace !== void 0 ? obj.$replace : void 0,
|
|
542
|
+
insert: obj.$insert !== void 0 ? obj.$insert : void 0,
|
|
543
|
+
remove: obj.$remove !== void 0 ? obj.$remove : void 0,
|
|
544
|
+
update: obj.$update !== void 0 ? obj.$update : void 0,
|
|
545
|
+
upsert: obj.$upsert !== void 0 ? obj.$upsert : void 0
|
|
499
546
|
};
|
|
500
547
|
}
|
|
501
548
|
/**
|
|
502
549
|
* FROM $replace helper: delete orphans, replace existing, insert new.
|
|
503
|
-
*/
|
|
550
|
+
*/
|
|
551
|
+
async function fromReplace(targetTable, children, parentPK, fkField, childPKs, navField, maxDepth, depth) {
|
|
504
552
|
const toReplace = [];
|
|
505
553
|
const toInsert = [];
|
|
506
|
-
const newPKSet = new Set();
|
|
554
|
+
const newPKSet = /* @__PURE__ */ new Set();
|
|
507
555
|
for (const child of children) {
|
|
508
556
|
const childData = { ...child };
|
|
509
557
|
childData[fkField] = parentPK;
|
|
510
|
-
|
|
511
|
-
if (hasPK) {
|
|
558
|
+
if (childPKs.length > 0 && childPKs.every((pk) => childData[pk] !== void 0)) {
|
|
512
559
|
newPKSet.add(childPKs.map((pk) => String(childData[pk])).join("\0"));
|
|
513
560
|
toReplace.push(childData);
|
|
514
561
|
} else toInsert.push(childData);
|
|
@@ -527,7 +574,7 @@ else toInsert.push(rec);
|
|
|
527
574
|
}
|
|
528
575
|
}
|
|
529
576
|
if (orphanFilters.length === 1) await targetTable.deleteMany(orphanFilters[0]);
|
|
530
|
-
else if (orphanFilters.length > 1) await targetTable.deleteMany({ $or: orphanFilters });
|
|
577
|
+
else if (orphanFilters.length > 1) await targetTable.deleteMany({ $or: orphanFilters });
|
|
531
578
|
if (toReplace.length > 0) await wrapNestedError(navField, () => targetTable.bulkReplace(toReplace, {
|
|
532
579
|
maxDepth,
|
|
533
580
|
_depth: depth + 1
|
|
@@ -539,7 +586,8 @@ else if (orphanFilters.length > 1) await targetTable.deleteMany({ $or: orphanFil
|
|
|
539
586
|
}
|
|
540
587
|
/**
|
|
541
588
|
* VIA $replace helper: clear junctions, replace/insert targets, rebuild junctions.
|
|
542
|
-
*/
|
|
589
|
+
*/
|
|
590
|
+
async function viaReplace(targetTable, junctionTable, targets, parentPK, targetPKField, fkToThisField, fkToTargetField, maxDepth, depth) {
|
|
543
591
|
await junctionTable.deleteMany({ [fkToThisField]: parentPK });
|
|
544
592
|
const toReplace = [];
|
|
545
593
|
const toInsert = [];
|
|
@@ -547,9 +595,8 @@ else if (orphanFilters.length > 1) await targetTable.deleteMany({ $or: orphanFil
|
|
|
547
595
|
for (const t of targets) {
|
|
548
596
|
const rec = t;
|
|
549
597
|
const pk = rec[targetPKField];
|
|
550
|
-
if (pk !==
|
|
551
|
-
|
|
552
|
-
if (keys.length > 0) toReplace.push({ ...rec });
|
|
598
|
+
if (pk !== void 0 && pk !== null) {
|
|
599
|
+
if (Object.keys(rec).filter((k) => k !== targetPKField).length > 0) toReplace.push({ ...rec });
|
|
553
600
|
existingIds.push(pk);
|
|
554
601
|
} else toInsert.push({ ...rec });
|
|
555
602
|
}
|
|
@@ -573,95 +620,94 @@ else if (orphanFilters.length > 1) await targetTable.deleteMany({ $or: orphanFil
|
|
|
573
620
|
await junctionTable.insertMany(junctionRows, { maxDepth: 0 });
|
|
574
621
|
}
|
|
575
622
|
}
|
|
576
|
-
|
|
577
623
|
//#endregion
|
|
578
|
-
Object.defineProperty(exports,
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
624
|
+
Object.defineProperty(exports, "DbError", {
|
|
625
|
+
enumerable: true,
|
|
626
|
+
get: function() {
|
|
627
|
+
return DbError;
|
|
628
|
+
}
|
|
583
629
|
});
|
|
584
|
-
Object.defineProperty(exports,
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
630
|
+
Object.defineProperty(exports, "batchInsertNestedFrom", {
|
|
631
|
+
enumerable: true,
|
|
632
|
+
get: function() {
|
|
633
|
+
return batchInsertNestedFrom;
|
|
634
|
+
}
|
|
589
635
|
});
|
|
590
|
-
Object.defineProperty(exports,
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
636
|
+
Object.defineProperty(exports, "batchInsertNestedTo", {
|
|
637
|
+
enumerable: true,
|
|
638
|
+
get: function() {
|
|
639
|
+
return batchInsertNestedTo;
|
|
640
|
+
}
|
|
595
641
|
});
|
|
596
|
-
Object.defineProperty(exports,
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
642
|
+
Object.defineProperty(exports, "batchInsertNestedVia", {
|
|
643
|
+
enumerable: true,
|
|
644
|
+
get: function() {
|
|
645
|
+
return batchInsertNestedVia;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
Object.defineProperty(exports, "batchPatchNestedFrom", {
|
|
649
|
+
enumerable: true,
|
|
650
|
+
get: function() {
|
|
651
|
+
return batchPatchNestedFrom;
|
|
652
|
+
}
|
|
601
653
|
});
|
|
602
|
-
Object.defineProperty(exports,
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
654
|
+
Object.defineProperty(exports, "batchPatchNestedTo", {
|
|
655
|
+
enumerable: true,
|
|
656
|
+
get: function() {
|
|
657
|
+
return batchPatchNestedTo;
|
|
658
|
+
}
|
|
607
659
|
});
|
|
608
|
-
Object.defineProperty(exports,
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
660
|
+
Object.defineProperty(exports, "batchPatchNestedVia", {
|
|
661
|
+
enumerable: true,
|
|
662
|
+
get: function() {
|
|
663
|
+
return batchPatchNestedVia;
|
|
664
|
+
}
|
|
613
665
|
});
|
|
614
|
-
Object.defineProperty(exports,
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
666
|
+
Object.defineProperty(exports, "batchReplaceNestedFrom", {
|
|
667
|
+
enumerable: true,
|
|
668
|
+
get: function() {
|
|
669
|
+
return batchReplaceNestedFrom;
|
|
670
|
+
}
|
|
619
671
|
});
|
|
620
|
-
Object.defineProperty(exports,
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
672
|
+
Object.defineProperty(exports, "batchReplaceNestedTo", {
|
|
673
|
+
enumerable: true,
|
|
674
|
+
get: function() {
|
|
675
|
+
return batchReplaceNestedTo;
|
|
676
|
+
}
|
|
625
677
|
});
|
|
626
|
-
Object.defineProperty(exports,
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
678
|
+
Object.defineProperty(exports, "batchReplaceNestedVia", {
|
|
679
|
+
enumerable: true,
|
|
680
|
+
get: function() {
|
|
681
|
+
return batchReplaceNestedVia;
|
|
682
|
+
}
|
|
631
683
|
});
|
|
632
|
-
Object.defineProperty(exports,
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
684
|
+
Object.defineProperty(exports, "checkDepthOverflow", {
|
|
685
|
+
enumerable: true,
|
|
686
|
+
get: function() {
|
|
687
|
+
return checkDepthOverflow;
|
|
688
|
+
}
|
|
637
689
|
});
|
|
638
|
-
Object.defineProperty(exports,
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
690
|
+
Object.defineProperty(exports, "enrichFkViolation", {
|
|
691
|
+
enumerable: true,
|
|
692
|
+
get: function() {
|
|
693
|
+
return enrichFkViolation;
|
|
694
|
+
}
|
|
643
695
|
});
|
|
644
|
-
Object.defineProperty(exports,
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
696
|
+
Object.defineProperty(exports, "preValidateNestedFrom", {
|
|
697
|
+
enumerable: true,
|
|
698
|
+
get: function() {
|
|
699
|
+
return preValidateNestedFrom;
|
|
700
|
+
}
|
|
649
701
|
});
|
|
650
|
-
Object.defineProperty(exports,
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
702
|
+
Object.defineProperty(exports, "remapDeleteFkViolation", {
|
|
703
|
+
enumerable: true,
|
|
704
|
+
get: function() {
|
|
705
|
+
return remapDeleteFkViolation;
|
|
706
|
+
}
|
|
655
707
|
});
|
|
656
|
-
Object.defineProperty(exports,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
708
|
+
Object.defineProperty(exports, "validateBatch", {
|
|
709
|
+
enumerable: true,
|
|
710
|
+
get: function() {
|
|
711
|
+
return validateBatch;
|
|
712
|
+
}
|
|
661
713
|
});
|
|
662
|
-
Object.defineProperty(exports, 'validateBatch', {
|
|
663
|
-
enumerable: true,
|
|
664
|
-
get: function () {
|
|
665
|
-
return validateBatch;
|
|
666
|
-
}
|
|
667
|
-
});
|