@atscript/db 0.1.141 → 0.1.143
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-Bv4pah66.d.cts → buckets-Ba5lP_o9.d.cts} +358 -17
- package/dist/{buckets-CjL7F-hp.d.mts → buckets-BlJ4cdlr.d.mts} +358 -17
- package/dist/{column-diff-DiBbXyLA.d.cts → column-diff-BlGxPobU.d.cts} +1 -1
- package/dist/{column-diff-CfPNcP6e.cjs → column-diff-D_Kyuh0S.cjs} +906 -209
- package/dist/{column-diff-n-k5KY0u.d.mts → column-diff-PqA_edXA.d.mts} +1 -1
- package/dist/{column-diff-CmFNXV8C.mjs → column-diff-e2oHc71_.mjs} +850 -177
- package/dist/index.cjs +16 -10
- package/dist/index.d.cts +30 -5
- package/dist/index.d.mts +30 -5
- package/dist/index.mjs +6 -5
- package/dist/nested-writer-CnOOAehr.mjs +880 -0
- package/dist/nested-writer-xfQwxplL.cjs +1029 -0
- package/dist/{object-DSN0h9lB.d.cts → object-CtPYTIvy.d.cts} +3 -1
- package/dist/{object-DSN0h9lB.d.mts → object-CtPYTIvy.d.mts} +3 -1
- package/dist/object-Djg28csK.cjs +101 -0
- package/dist/object-TkiJQ-Dp.mjs +66 -0
- package/dist/rel.cjs +5 -2
- package/dist/rel.d.cts +76 -10
- package/dist/rel.d.mts +76 -10
- package/dist/rel.mjs +3 -3
- package/dist/{relation-helpers-B59to_dG.d.mts → relation-helpers-JTEyZzVd.d.cts} +1 -1
- package/dist/{relation-helpers-DQ_nRsV9.d.cts → relation-helpers-MTwzaSGA.d.mts} +1 -1
- package/dist/{relation-loader-CgJ8bK6X.cjs → relation-loader-CBPY6kM7.cjs} +1 -1
- package/dist/{relation-loader-CuhEBzFU.mjs → relation-loader-D9XuXaMv.mjs} +1 -1
- package/dist/sync.cjs +1 -1
- package/dist/sync.d.cts +2 -2
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +1 -1
- package/dist/{validator-DASnXf1j.cjs → validator-CVS-onRg.cjs} +0 -101
- package/dist/{validator-D8bPsXPN.mjs → validator-Clu2q_7z.mjs} +1 -66
- package/dist/validator.cjs +4 -3
- package/dist/validator.d.cts +1 -1
- package/dist/validator.d.mts +1 -1
- package/dist/validator.mjs +2 -1
- package/package.json +1 -1
- package/dist/nested-writer-BO3vhbkP.mjs +0 -661
- package/dist/nested-writer-DYsRxZ5f.cjs +0 -768
|
@@ -13,6 +13,8 @@ declare function isEmptyObject(obj: Record<string, unknown>): boolean;
|
|
|
13
13
|
* runtime reconstruction on the Readable.
|
|
14
14
|
*/
|
|
15
15
|
declare function findAncestorInSet(path: string, set: ReadonlySet<string>): string | undefined;
|
|
16
|
+
/** `path` itself if it is in `set`, else its nearest ancestor in `set` ({@link findAncestorInSet}). */
|
|
17
|
+
declare function selfOrAncestor(path: string, set: ReadonlySet<string>): string | undefined;
|
|
16
18
|
/**
|
|
17
19
|
* Reads a dot-path (or its segments) off a nested plain object: `undefined`
|
|
18
20
|
* past a missing step, or a step that is not a plain object (arrays are not
|
|
@@ -27,4 +29,4 @@ declare function getPath(row: Record<string, unknown>, path: string | readonly s
|
|
|
27
29
|
*/
|
|
28
30
|
declare function deletePath(target: Record<string, unknown>, path: string | readonly string[]): void;
|
|
29
31
|
//#endregion
|
|
30
|
-
export { isPlainObject as a, isEmptyObject as i, findAncestorInSet as n, getPath as r, deletePath as t };
|
|
32
|
+
export { isPlainObject as a, isEmptyObject as i, findAncestorInSet as n, selfOrAncestor as o, getPath as r, deletePath as t };
|
|
@@ -13,6 +13,8 @@ declare function isEmptyObject(obj: Record<string, unknown>): boolean;
|
|
|
13
13
|
* runtime reconstruction on the Readable.
|
|
14
14
|
*/
|
|
15
15
|
declare function findAncestorInSet(path: string, set: ReadonlySet<string>): string | undefined;
|
|
16
|
+
/** `path` itself if it is in `set`, else its nearest ancestor in `set` ({@link findAncestorInSet}). */
|
|
17
|
+
declare function selfOrAncestor(path: string, set: ReadonlySet<string>): string | undefined;
|
|
16
18
|
/**
|
|
17
19
|
* Reads a dot-path (or its segments) off a nested plain object: `undefined`
|
|
18
20
|
* past a missing step, or a step that is not a plain object (arrays are not
|
|
@@ -27,4 +29,4 @@ declare function getPath(row: Record<string, unknown>, path: string | readonly s
|
|
|
27
29
|
*/
|
|
28
30
|
declare function deletePath(target: Record<string, unknown>, path: string | readonly string[]): void;
|
|
29
31
|
//#endregion
|
|
30
|
-
export { isPlainObject as a, isEmptyObject as i, findAncestorInSet as n, getPath as r, deletePath as t };
|
|
32
|
+
export { isPlainObject as a, isEmptyObject as i, findAncestorInSet as n, selfOrAncestor as o, getPath as r, deletePath as t };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//#region src/shared/object.ts
|
|
2
|
+
/**
|
|
3
|
+
* Plain object: prototype is `Object.prototype` or `null` — never a class
|
|
4
|
+
* instance (`Date`, `Uint8Array`, `ObjectId`, …) and never an array.
|
|
5
|
+
* Browser-safe; shared by the write paths, the HTTP shape gate and the client.
|
|
6
|
+
*/
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
if (typeof value !== "object" || value === null) return false;
|
|
9
|
+
const proto = Object.getPrototypeOf(value);
|
|
10
|
+
return proto === Object.prototype || proto === null;
|
|
11
|
+
}
|
|
12
|
+
/** Zero-allocation emptiness check for a plain object (`{}` → `true`). */
|
|
13
|
+
function isEmptyObject(obj) {
|
|
14
|
+
for (const _ in obj) return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds the nearest ancestor of `path` that belongs to `set`.
|
|
19
|
+
* Used by both the build pipeline (in `_classifyFields`) and
|
|
20
|
+
* runtime reconstruction on the Readable.
|
|
21
|
+
*/
|
|
22
|
+
function findAncestorInSet(path, set) {
|
|
23
|
+
let pos = path.length;
|
|
24
|
+
while ((pos = path.lastIndexOf(".", pos - 1)) !== -1) {
|
|
25
|
+
const ancestor = path.slice(0, pos);
|
|
26
|
+
if (set.has(ancestor)) return ancestor;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** `path` itself if it is in `set`, else its nearest ancestor in `set` ({@link findAncestorInSet}). */
|
|
30
|
+
function selfOrAncestor(path, set) {
|
|
31
|
+
return set.has(path) ? path : findAncestorInSet(path, set);
|
|
32
|
+
}
|
|
33
|
+
/** Splits a dot-path once; an already split path is used as-is. */
|
|
34
|
+
function segmentsOf(path) {
|
|
35
|
+
return typeof path === "string" ? path.split(".") : path;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reads a dot-path (or its segments) off a nested plain object: `undefined`
|
|
39
|
+
* past a missing step, or a step that is not a plain object (arrays are not
|
|
40
|
+
* descended into — no positional indexing).
|
|
41
|
+
* @since 0.1.141
|
|
42
|
+
*/
|
|
43
|
+
function getPath(row, path) {
|
|
44
|
+
let current = row;
|
|
45
|
+
for (const seg of segmentsOf(path)) {
|
|
46
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return;
|
|
47
|
+
current = current[seg];
|
|
48
|
+
}
|
|
49
|
+
return current;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Deletes a dot-path (or its segments) from a nested plain object; a no-op
|
|
53
|
+
* when an intermediate step is missing or not a plain object.
|
|
54
|
+
* @since 0.1.141
|
|
55
|
+
*/
|
|
56
|
+
function deletePath(target, path) {
|
|
57
|
+
const segments = segmentsOf(path);
|
|
58
|
+
let current = target;
|
|
59
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
60
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return;
|
|
61
|
+
current = current[segments[i]];
|
|
62
|
+
}
|
|
63
|
+
if (current !== null && typeof current === "object" && !Array.isArray(current)) delete current[segments[segments.length - 1]];
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
Object.defineProperty(exports, "deletePath", {
|
|
67
|
+
enumerable: true,
|
|
68
|
+
get: function() {
|
|
69
|
+
return deletePath;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
Object.defineProperty(exports, "findAncestorInSet", {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
get: function() {
|
|
75
|
+
return findAncestorInSet;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
Object.defineProperty(exports, "getPath", {
|
|
79
|
+
enumerable: true,
|
|
80
|
+
get: function() {
|
|
81
|
+
return getPath;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
Object.defineProperty(exports, "isEmptyObject", {
|
|
85
|
+
enumerable: true,
|
|
86
|
+
get: function() {
|
|
87
|
+
return isEmptyObject;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
Object.defineProperty(exports, "isPlainObject", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function() {
|
|
93
|
+
return isPlainObject;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
Object.defineProperty(exports, "selfOrAncestor", {
|
|
97
|
+
enumerable: true,
|
|
98
|
+
get: function() {
|
|
99
|
+
return selfOrAncestor;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/shared/object.ts
|
|
2
|
+
/**
|
|
3
|
+
* Plain object: prototype is `Object.prototype` or `null` — never a class
|
|
4
|
+
* instance (`Date`, `Uint8Array`, `ObjectId`, …) and never an array.
|
|
5
|
+
* Browser-safe; shared by the write paths, the HTTP shape gate and the client.
|
|
6
|
+
*/
|
|
7
|
+
function isPlainObject(value) {
|
|
8
|
+
if (typeof value !== "object" || value === null) return false;
|
|
9
|
+
const proto = Object.getPrototypeOf(value);
|
|
10
|
+
return proto === Object.prototype || proto === null;
|
|
11
|
+
}
|
|
12
|
+
/** Zero-allocation emptiness check for a plain object (`{}` → `true`). */
|
|
13
|
+
function isEmptyObject(obj) {
|
|
14
|
+
for (const _ in obj) return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds the nearest ancestor of `path` that belongs to `set`.
|
|
19
|
+
* Used by both the build pipeline (in `_classifyFields`) and
|
|
20
|
+
* runtime reconstruction on the Readable.
|
|
21
|
+
*/
|
|
22
|
+
function findAncestorInSet(path, set) {
|
|
23
|
+
let pos = path.length;
|
|
24
|
+
while ((pos = path.lastIndexOf(".", pos - 1)) !== -1) {
|
|
25
|
+
const ancestor = path.slice(0, pos);
|
|
26
|
+
if (set.has(ancestor)) return ancestor;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** `path` itself if it is in `set`, else its nearest ancestor in `set` ({@link findAncestorInSet}). */
|
|
30
|
+
function selfOrAncestor(path, set) {
|
|
31
|
+
return set.has(path) ? path : findAncestorInSet(path, set);
|
|
32
|
+
}
|
|
33
|
+
/** Splits a dot-path once; an already split path is used as-is. */
|
|
34
|
+
function segmentsOf(path) {
|
|
35
|
+
return typeof path === "string" ? path.split(".") : path;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reads a dot-path (or its segments) off a nested plain object: `undefined`
|
|
39
|
+
* past a missing step, or a step that is not a plain object (arrays are not
|
|
40
|
+
* descended into — no positional indexing).
|
|
41
|
+
* @since 0.1.141
|
|
42
|
+
*/
|
|
43
|
+
function getPath(row, path) {
|
|
44
|
+
let current = row;
|
|
45
|
+
for (const seg of segmentsOf(path)) {
|
|
46
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return;
|
|
47
|
+
current = current[seg];
|
|
48
|
+
}
|
|
49
|
+
return current;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Deletes a dot-path (or its segments) from a nested plain object; a no-op
|
|
53
|
+
* when an intermediate step is missing or not a plain object.
|
|
54
|
+
* @since 0.1.141
|
|
55
|
+
*/
|
|
56
|
+
function deletePath(target, path) {
|
|
57
|
+
const segments = segmentsOf(path);
|
|
58
|
+
let current = target;
|
|
59
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
60
|
+
if (current === null || typeof current !== "object" || Array.isArray(current)) return;
|
|
61
|
+
current = current[segments[i]];
|
|
62
|
+
}
|
|
63
|
+
if (current !== null && typeof current === "object" && !Array.isArray(current)) delete current[segments[segments.length - 1]];
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { isPlainObject as a, isEmptyObject as i, findAncestorInSet as n, selfOrAncestor as o, getPath as r, deletePath as t };
|
package/dist/rel.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_nested_writer = require("./nested-writer-
|
|
3
|
-
const require_relation_loader = require("./relation-loader-
|
|
2
|
+
const require_nested_writer = require("./nested-writer-xfQwxplL.cjs");
|
|
3
|
+
const require_relation_loader = require("./relation-loader-CBPY6kM7.cjs");
|
|
4
|
+
exports.applyPatchNestedTo = require_nested_writer.applyPatchNestedTo;
|
|
4
5
|
exports.batchInsertNestedFrom = require_nested_writer.batchInsertNestedFrom;
|
|
5
6
|
exports.batchInsertNestedTo = require_nested_writer.batchInsertNestedTo;
|
|
6
7
|
exports.batchInsertNestedVia = require_nested_writer.batchInsertNestedVia;
|
|
@@ -14,6 +15,8 @@ exports.checkDepthOverflow = require_nested_writer.checkDepthOverflow;
|
|
|
14
15
|
exports.findFKForRelation = require_nested_writer.findFKForRelation;
|
|
15
16
|
exports.findRemoteFK = require_nested_writer.findRemoteFK;
|
|
16
17
|
exports.loadRelationsImpl = require_relation_loader.loadRelationsImpl;
|
|
18
|
+
exports.planNestedFromVia = require_nested_writer.planNestedFromVia;
|
|
19
|
+
exports.planPatchNestedTo = require_nested_writer.planPatchNestedTo;
|
|
17
20
|
exports.preValidateNestedFrom = require_nested_writer.preValidateNestedFrom;
|
|
18
21
|
exports.resolveRelationTargetTable = require_nested_writer.resolveRelationTargetTable;
|
|
19
22
|
exports.validateBatch = require_nested_writer.validateBatch;
|
package/dist/rel.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as TDbForeignKey, Bt as BaseDbAdapter, Et as TTableResolver, It as TableMetadata, J as TDbRelation, hn as TGenericLogger, jt as TWriteTableResolver, m as AtscriptDbWritable, p as AtscriptDbTableLike } from "./buckets-Ba5lP_o9.cjs";
|
|
2
2
|
import { t as DbValidationContext } from "./db-validator-plugin-BWy60OvG.cjs";
|
|
3
|
-
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-
|
|
3
|
+
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-JTEyZzVd.cjs";
|
|
4
4
|
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
5
5
|
import { Validator } from "@atscript/typescript/utils";
|
|
6
6
|
|
|
@@ -40,7 +40,9 @@ interface TNestedWriterHost {
|
|
|
40
40
|
_extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
41
41
|
findOne(query: {
|
|
42
42
|
filter: FilterExpr;
|
|
43
|
-
controls:
|
|
43
|
+
controls: {
|
|
44
|
+
$select?: string[];
|
|
45
|
+
};
|
|
44
46
|
}): Promise<Record<string, unknown> | null>;
|
|
45
47
|
}
|
|
46
48
|
/**
|
|
@@ -75,27 +77,91 @@ declare function batchInsertNestedVia(host: TNestedWriterHost, originals: Array<
|
|
|
75
77
|
*/
|
|
76
78
|
declare function batchReplaceNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
77
79
|
/**
|
|
78
|
-
* Batch-replaces FROM dependents after the main replace.
|
|
80
|
+
* Batch-replaces FROM dependents after the main replace. `plan` is the
|
|
81
|
+
* {@link planNestedFromVia} result for `originals` (`mode: "replace"`);
|
|
82
|
+
* omitted, the plan is made here first.
|
|
79
83
|
*/
|
|
80
|
-
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
84
|
+
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
81
85
|
/**
|
|
82
86
|
* Handles VIA (M:N) relations during replace.
|
|
83
87
|
*/
|
|
84
88
|
declare function batchReplaceNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
85
89
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
90
|
+
* The FROM / VIA nested writes of a batch, validated by
|
|
91
|
+
* {@link planNestedFromVia} before the main write (since 0.1.143).
|
|
92
|
+
*/
|
|
93
|
+
interface TNestedFromViaPlan {
|
|
94
|
+
/**
|
|
95
|
+
* Per FROM nav field: the {@link pkTupleKey}s of the keyed children that
|
|
96
|
+
* exist under the parent naming them. Their writes must match (a child
|
|
97
|
+
* re-parented meanwhile → `CONFLICT`, rolled back).
|
|
98
|
+
*/
|
|
99
|
+
readonly owned: ReadonlyMap<string, ReadonlySet<string>>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validates the FROM and VIA nested writes of a batch BEFORE the main write
|
|
103
|
+
* (since 0.1.143), so a rejected nested operation never leaves the main
|
|
104
|
+
* write applied — even on adapters whose transaction is a pass-through. One
|
|
105
|
+
* read per relation for the whole batch; the entries are evaluated in memory
|
|
106
|
+
* in apply order (`$replace` → `$update` → `$upsert`). `mode: "patch"`
|
|
107
|
+
* checks the operators, `mode: "replace"` the plain arrays of a PUT:
|
|
108
|
+
* - FROM: a keyed child that exists under another parent (or none) → `CONFLICT`;
|
|
109
|
+
* a `$update` entry without the child PK → `NOT_FOUND`;
|
|
110
|
+
* - VIA: a keyed `$update` / `$upsert` target not linked to the parent →
|
|
111
|
+
* `CONFLICT`; a `$update` entry without the target PK → `NOT_FOUND`.
|
|
112
|
+
*
|
|
113
|
+
* The apply phases write the planned FROM children through filters
|
|
114
|
+
* constrained to their parent (`{ pk, fk: parentPK }`), so a child
|
|
115
|
+
* re-parented between the plan and the write is never touched.
|
|
116
|
+
*/
|
|
117
|
+
declare function planNestedFromVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, mode: "patch" | "replace"): Promise<TNestedFromViaPlan>;
|
|
118
|
+
/** One TO relation's nested patches, planned before the main patch — see {@link planPatchNestedTo}. */
|
|
119
|
+
interface TNestedToPatchPlan {
|
|
120
|
+
navField: string;
|
|
121
|
+
targetTable: AtscriptDbTableLike & AtscriptDbWritable;
|
|
122
|
+
/** `index` = position of the source item in the batch. */
|
|
123
|
+
entries: Array<{
|
|
124
|
+
index: number;
|
|
125
|
+
patch: Record<string, unknown>;
|
|
126
|
+
}>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Plans the TO relation patches of a batch BEFORE the main patch (since
|
|
130
|
+
* 0.1.143). A nested TO object always patches the row the STORED foreign key
|
|
131
|
+
* references. `targets[i]` is item `i`'s stored row (at least its foreign-key
|
|
132
|
+
* columns; `null` = missing) as the table pinned it inside the transaction;
|
|
133
|
+
* omitted, each item's row is read here. Rejected with `INVALID_QUERY`
|
|
134
|
+
* (nothing written): a payload that changes that foreign key AND carries a
|
|
135
|
+
* nested object for the same relation, and a nested object whose own key
|
|
136
|
+
* names a different row. An item whose source row does not exist is skipped
|
|
137
|
+
* (the main patch matches nothing for it). A stored `null` foreign key (or a
|
|
138
|
+
* composite one) → `FK_VIOLATION`.
|
|
139
|
+
*/
|
|
140
|
+
declare function planPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, targets?: ReadonlyArray<Record<string, unknown> | null | undefined>): Promise<TNestedToPatchPlan[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Applies the TO patches {@link planPatchNestedTo} planned — after the main
|
|
143
|
+
* patch, only for the items it matched (`matched[i]`; all when omitted).
|
|
144
|
+
*/
|
|
145
|
+
declare function applyPatchNestedTo(plans: ReadonlyArray<TNestedToPatchPlan>, maxDepth: number, depth: number, matched?: ReadonlyArray<boolean>): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Batch-patches TO dependencies: {@link planPatchNestedTo} +
|
|
148
|
+
* {@link applyPatchNestedTo} in one step (the table itself plans before and
|
|
149
|
+
* applies after its main patch).
|
|
88
150
|
*/
|
|
89
151
|
declare function batchPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
90
152
|
/**
|
|
91
153
|
* Batch-patches FROM (1:N) dependencies after the main patch.
|
|
92
154
|
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
155
|
+
* `plan` is the {@link planNestedFromVia} result for `originals`
|
|
156
|
+
* (`mode: "patch"`); omitted, the plan is made here first.
|
|
93
157
|
*/
|
|
94
|
-
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
158
|
+
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
95
159
|
/**
|
|
96
160
|
* Batch-patches VIA (M:N) dependencies after the main patch.
|
|
97
161
|
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
162
|
+
* `plan` marks `originals` as already validated by {@link planNestedFromVia}
|
|
163
|
+
* (`mode: "patch"`); omitted, they are validated here first.
|
|
98
164
|
*/
|
|
99
|
-
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
165
|
+
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
100
166
|
//#endregion
|
|
101
|
-
export { type TNestedWriterHost, type TRelationLoaderHost, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
|
167
|
+
export { type TNestedFromViaPlan, type TNestedToPatchPlan, type TNestedWriterHost, type TRelationLoaderHost, applyPatchNestedTo, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, planNestedFromVia, planPatchNestedTo, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
package/dist/rel.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as TDbForeignKey, Bt as BaseDbAdapter, Et as TTableResolver, It as TableMetadata, J as TDbRelation, hn as TGenericLogger, jt as TWriteTableResolver, m as AtscriptDbWritable, p as AtscriptDbTableLike } from "./buckets-BlJ4cdlr.mjs";
|
|
2
2
|
import { t as DbValidationContext } from "./db-validator-plugin-BWy60OvG.mjs";
|
|
3
|
-
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-
|
|
3
|
+
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-MTwzaSGA.mjs";
|
|
4
4
|
import { Validator } from "@atscript/typescript/utils";
|
|
5
5
|
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
6
6
|
|
|
@@ -40,7 +40,9 @@ interface TNestedWriterHost {
|
|
|
40
40
|
_extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
41
41
|
findOne(query: {
|
|
42
42
|
filter: FilterExpr;
|
|
43
|
-
controls:
|
|
43
|
+
controls: {
|
|
44
|
+
$select?: string[];
|
|
45
|
+
};
|
|
44
46
|
}): Promise<Record<string, unknown> | null>;
|
|
45
47
|
}
|
|
46
48
|
/**
|
|
@@ -75,27 +77,91 @@ declare function batchInsertNestedVia(host: TNestedWriterHost, originals: Array<
|
|
|
75
77
|
*/
|
|
76
78
|
declare function batchReplaceNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
77
79
|
/**
|
|
78
|
-
* Batch-replaces FROM dependents after the main replace.
|
|
80
|
+
* Batch-replaces FROM dependents after the main replace. `plan` is the
|
|
81
|
+
* {@link planNestedFromVia} result for `originals` (`mode: "replace"`);
|
|
82
|
+
* omitted, the plan is made here first.
|
|
79
83
|
*/
|
|
80
|
-
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
84
|
+
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
81
85
|
/**
|
|
82
86
|
* Handles VIA (M:N) relations during replace.
|
|
83
87
|
*/
|
|
84
88
|
declare function batchReplaceNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
85
89
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
90
|
+
* The FROM / VIA nested writes of a batch, validated by
|
|
91
|
+
* {@link planNestedFromVia} before the main write (since 0.1.143).
|
|
92
|
+
*/
|
|
93
|
+
interface TNestedFromViaPlan {
|
|
94
|
+
/**
|
|
95
|
+
* Per FROM nav field: the {@link pkTupleKey}s of the keyed children that
|
|
96
|
+
* exist under the parent naming them. Their writes must match (a child
|
|
97
|
+
* re-parented meanwhile → `CONFLICT`, rolled back).
|
|
98
|
+
*/
|
|
99
|
+
readonly owned: ReadonlyMap<string, ReadonlySet<string>>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validates the FROM and VIA nested writes of a batch BEFORE the main write
|
|
103
|
+
* (since 0.1.143), so a rejected nested operation never leaves the main
|
|
104
|
+
* write applied — even on adapters whose transaction is a pass-through. One
|
|
105
|
+
* read per relation for the whole batch; the entries are evaluated in memory
|
|
106
|
+
* in apply order (`$replace` → `$update` → `$upsert`). `mode: "patch"`
|
|
107
|
+
* checks the operators, `mode: "replace"` the plain arrays of a PUT:
|
|
108
|
+
* - FROM: a keyed child that exists under another parent (or none) → `CONFLICT`;
|
|
109
|
+
* a `$update` entry without the child PK → `NOT_FOUND`;
|
|
110
|
+
* - VIA: a keyed `$update` / `$upsert` target not linked to the parent →
|
|
111
|
+
* `CONFLICT`; a `$update` entry without the target PK → `NOT_FOUND`.
|
|
112
|
+
*
|
|
113
|
+
* The apply phases write the planned FROM children through filters
|
|
114
|
+
* constrained to their parent (`{ pk, fk: parentPK }`), so a child
|
|
115
|
+
* re-parented between the plan and the write is never touched.
|
|
116
|
+
*/
|
|
117
|
+
declare function planNestedFromVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, mode: "patch" | "replace"): Promise<TNestedFromViaPlan>;
|
|
118
|
+
/** One TO relation's nested patches, planned before the main patch — see {@link planPatchNestedTo}. */
|
|
119
|
+
interface TNestedToPatchPlan {
|
|
120
|
+
navField: string;
|
|
121
|
+
targetTable: AtscriptDbTableLike & AtscriptDbWritable;
|
|
122
|
+
/** `index` = position of the source item in the batch. */
|
|
123
|
+
entries: Array<{
|
|
124
|
+
index: number;
|
|
125
|
+
patch: Record<string, unknown>;
|
|
126
|
+
}>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Plans the TO relation patches of a batch BEFORE the main patch (since
|
|
130
|
+
* 0.1.143). A nested TO object always patches the row the STORED foreign key
|
|
131
|
+
* references. `targets[i]` is item `i`'s stored row (at least its foreign-key
|
|
132
|
+
* columns; `null` = missing) as the table pinned it inside the transaction;
|
|
133
|
+
* omitted, each item's row is read here. Rejected with `INVALID_QUERY`
|
|
134
|
+
* (nothing written): a payload that changes that foreign key AND carries a
|
|
135
|
+
* nested object for the same relation, and a nested object whose own key
|
|
136
|
+
* names a different row. An item whose source row does not exist is skipped
|
|
137
|
+
* (the main patch matches nothing for it). A stored `null` foreign key (or a
|
|
138
|
+
* composite one) → `FK_VIOLATION`.
|
|
139
|
+
*/
|
|
140
|
+
declare function planPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, targets?: ReadonlyArray<Record<string, unknown> | null | undefined>): Promise<TNestedToPatchPlan[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Applies the TO patches {@link planPatchNestedTo} planned — after the main
|
|
143
|
+
* patch, only for the items it matched (`matched[i]`; all when omitted).
|
|
144
|
+
*/
|
|
145
|
+
declare function applyPatchNestedTo(plans: ReadonlyArray<TNestedToPatchPlan>, maxDepth: number, depth: number, matched?: ReadonlyArray<boolean>): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Batch-patches TO dependencies: {@link planPatchNestedTo} +
|
|
148
|
+
* {@link applyPatchNestedTo} in one step (the table itself plans before and
|
|
149
|
+
* applies after its main patch).
|
|
88
150
|
*/
|
|
89
151
|
declare function batchPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
90
152
|
/**
|
|
91
153
|
* Batch-patches FROM (1:N) dependencies after the main patch.
|
|
92
154
|
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
155
|
+
* `plan` is the {@link planNestedFromVia} result for `originals`
|
|
156
|
+
* (`mode: "patch"`); omitted, the plan is made here first.
|
|
93
157
|
*/
|
|
94
|
-
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
158
|
+
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
95
159
|
/**
|
|
96
160
|
* Batch-patches VIA (M:N) dependencies after the main patch.
|
|
97
161
|
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
162
|
+
* `plan` marks `originals` as already validated by {@link planNestedFromVia}
|
|
163
|
+
* (`mode: "patch"`); omitted, they are validated here first.
|
|
98
164
|
*/
|
|
99
|
-
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
165
|
+
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number, plan?: TNestedFromViaPlan): Promise<void>;
|
|
100
166
|
//#endregion
|
|
101
|
-
export { type TNestedWriterHost, type TRelationLoaderHost, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
|
167
|
+
export { type TNestedFromViaPlan, type TNestedToPatchPlan, type TNestedWriterHost, type TRelationLoaderHost, applyPatchNestedTo, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, planNestedFromVia, planPatchNestedTo, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
package/dist/rel.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as loadRelationsImpl } from "./relation-loader-
|
|
2
|
-
import {
|
|
3
|
-
export { batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
|
1
|
+
import { t as loadRelationsImpl } from "./relation-loader-D9XuXaMv.mjs";
|
|
2
|
+
import { C as findRemoteFK, S as findFKForRelation, a as batchPatchNestedFrom, c as batchReplaceNestedFrom, d as checkDepthOverflow, f as planNestedFromVia, h as validateBatch, i as batchInsertNestedVia, l as batchReplaceNestedTo, m as preValidateNestedFrom, n as batchInsertNestedFrom, o as batchPatchNestedTo, p as planPatchNestedTo, r as batchInsertNestedTo, s as batchPatchNestedVia, t as applyPatchNestedTo, u as batchReplaceNestedVia, w as resolveRelationTargetTable } from "./nested-writer-CnOOAehr.mjs";
|
|
3
|
+
export { applyPatchNestedTo, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, planNestedFromVia, planPatchNestedTo, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as TDbForeignKey, J as TDbRelation } from "./buckets-Ba5lP_o9.cjs";
|
|
2
2
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
3
3
|
|
|
4
4
|
//#region src/rel/relation-helpers.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as TDbForeignKey, J as TDbRelation } from "./buckets-BlJ4cdlr.mjs";
|
|
2
2
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
3
3
|
|
|
4
4
|
//#region src/rel/relation-helpers.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_nested_writer = require("./nested-writer-
|
|
1
|
+
const require_nested_writer = require("./nested-writer-xfQwxplL.cjs");
|
|
2
2
|
//#region src/rel/relation-loader.ts
|
|
3
3
|
var relation_loader_exports = /* @__PURE__ */ require("./plugin.cjs").__exportAll({
|
|
4
4
|
ensureSelectIncludesFields: () => ensureSelectIncludesFields,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as findRemoteFK, S as findFKForRelation, w as resolveRelationTargetTable } from "./nested-writer-CnOOAehr.mjs";
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __exportAll = (all, no_symbols) => {
|
package/dist/sync.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_db_error = require("./db-error-DTkkeu5b.cjs");
|
|
3
|
-
const require_column_diff = require("./column-diff-
|
|
3
|
+
const require_column_diff = require("./column-diff-D_Kyuh0S.cjs");
|
|
4
4
|
//#region src/schema/table-option-diff.ts
|
|
5
5
|
/**
|
|
6
6
|
* Computes the difference between desired and existing table options.
|
package/dist/sync.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-
|
|
1
|
+
import { B as TDbForeignKey, K as TDbObjectKind, Tt as TTableOptionDiff, Vt as DbSpace, at as TDerivedChangeReason, bt as TReferencingForeignKey, hn as TGenericLogger, lt as TExistingForeignKey, st as TEnsureTableOptions, ut as TExistingTableOption, yt as TPrimaryKeyChange, z as TDbFieldMeta } from "./buckets-Ba5lP_o9.cjs";
|
|
2
|
+
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-BlGxPobU.cjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
package/dist/sync.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-
|
|
1
|
+
import { B as TDbForeignKey, K as TDbObjectKind, Tt as TTableOptionDiff, Vt as DbSpace, at as TDerivedChangeReason, bt as TReferencingForeignKey, hn as TGenericLogger, lt as TExistingForeignKey, st as TEnsureTableOptions, ut as TExistingTableOption, yt as TPrimaryKeyChange, z as TDbFieldMeta } from "./buckets-BlJ4cdlr.mjs";
|
|
2
|
+
import { a as TTableSnapshot, c as TViewSnapshot, d as computeTableHash, f as computeTableSnapshot, h as snapshotToExistingTableOptions, i as TForeignKeySnapshot, l as canonicalizeQueryNode, m as snapshotToExistingColumns, o as TViewColumnSnapshot, p as computeViewSnapshot, r as TFieldSnapshot, s as TViewJoinSnapshot, t as computeColumnDiff, u as computeSchemaHash } from "./column-diff-PqA_edXA.mjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
package/dist/sync.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as DbError } from "./db-error-D5uilS_A.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as hasForeignKeyChanges, c as computeTableHash, d as snapshotToExistingColumns, f as snapshotToExistingTableOptions, i as fkKey, l as computeTableSnapshot, o as canonicalizeQueryNode, p as viewSnapshotSources, r as computeForeignKeyDiff, s as computeSchemaHash, st as NoopLogger, t as computeColumnDiff, tt as aliasTargetOf, u as computeViewSnapshot } from "./column-diff-e2oHc71_.mjs";
|
|
3
3
|
//#region src/schema/table-option-diff.ts
|
|
4
4
|
/**
|
|
5
5
|
* Computes the difference between desired and existing table options.
|