@atscript/db 0.1.40 → 0.1.42
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 +1 -1
- package/dist/{db-readable-BQQzfguJ.d.cts → db-readable-C3C-qPcP.d.cts} +14 -3
- package/dist/{db-readable-Bbr4CjMb.d.mts → db-readable-Cc868K54.d.mts} +14 -3
- package/dist/{db-space-BUrQ5BFm.d.mts → db-space-Dgf-CphX.d.cts} +12 -4
- package/dist/{db-space-Vxpcnyt5.d.cts → db-space-crCFv3DF.d.mts} +12 -4
- package/dist/{db-validator-plugin-07kDiis2.d.cts → db-validator-plugin-BLMVdi9z.d.mts} +2 -0
- package/dist/{db-validator-plugin-CiqsHTI_.d.mts → db-validator-plugin-Cz4QoDWg.d.cts} +2 -0
- package/dist/{db-view-BntnAmXO.cjs → db-view-CcUjETIF.cjs} +185 -46
- package/dist/{db-view-ZsoN91-q.mjs → db-view-DSK76uc9.mjs} +185 -46
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +8 -3
- package/dist/index.d.mts +8 -3
- package/dist/index.mjs +2 -2
- package/dist/{nested-writer-BDXsDMPP.cjs → nested-writer-BIQ6EfaR.cjs} +1 -1
- package/dist/{nested-writer-Dmm1gbZV.mjs → nested-writer-CNDyhg2L.mjs} +1 -1
- package/dist/rel.cjs +1 -1
- package/dist/rel.d.cts +3 -3
- package/dist/rel.d.mts +3 -3
- package/dist/rel.mjs +1 -1
- package/dist/sync.cjs +2 -2
- package/dist/sync.d.cts +2 -2
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -399,7 +399,11 @@ declare class TableMetadata {
|
|
|
399
399
|
booleanFields: Set<string>;
|
|
400
400
|
decimalFields: Set<string>;
|
|
401
401
|
allPhysicalFields: string[];
|
|
402
|
+
/** Precomputed parent path → child physical column names for fast null-setting. */
|
|
403
|
+
childrenByParent: Map<string, string[]>;
|
|
402
404
|
requiresMappings: boolean;
|
|
405
|
+
/** True when the only mappings needed are simple `@db.column` renames (no nesting/JSON). */
|
|
406
|
+
onlyColumnRenames: boolean;
|
|
403
407
|
toStorageFormatters?: Map<string, (value: unknown) => unknown>;
|
|
404
408
|
fromStorageFormatters?: Map<string, (value: unknown) => unknown>;
|
|
405
409
|
/** Leaf field descriptors indexed by physical column name (read path). */
|
|
@@ -958,13 +962,20 @@ declare abstract class FieldMappingStrategy {
|
|
|
958
962
|
abstract translateQuery(query: Uniquery, meta: TableMetadata): DbQuery;
|
|
959
963
|
abstract translateAggregateQuery(query: AggregateQuery, meta: TableMetadata): DbQuery;
|
|
960
964
|
/**
|
|
961
|
-
* Recursively walks a filter expression, applying
|
|
962
|
-
*
|
|
963
|
-
*
|
|
965
|
+
* Recursively walks a filter expression, applying `@db.column` key renames
|
|
966
|
+
* via `columnMap` and adapter-specific value formatting via `formatFilterValue`.
|
|
967
|
+
*
|
|
968
|
+
* The relational mapper overrides this to use `leafByLogical` for deeper
|
|
969
|
+
* key resolution (flattened nested paths).
|
|
964
970
|
*/
|
|
965
971
|
translateFilter(filter: FilterExpr, meta: TableMetadata): FilterExpr;
|
|
966
972
|
abstract prepareForWrite(payload: Record<string, unknown>, meta: TableMetadata, adapter: BaseDbAdapter): Record<string, unknown>;
|
|
967
973
|
abstract translatePatchKeys(update: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
|
|
974
|
+
/**
|
|
975
|
+
* Reverse-maps `@db.column` renames on a row read from storage.
|
|
976
|
+
* Renames physical keys back to logical names in-place.
|
|
977
|
+
*/
|
|
978
|
+
protected reverseColumnRenames(row: Record<string, unknown>, meta: TableMetadata): void;
|
|
968
979
|
/**
|
|
969
980
|
* Coerces field values from storage representation to JS types
|
|
970
981
|
* (booleans from 0/1, decimals from number to string).
|
|
@@ -399,7 +399,11 @@ declare class TableMetadata {
|
|
|
399
399
|
booleanFields: Set<string>;
|
|
400
400
|
decimalFields: Set<string>;
|
|
401
401
|
allPhysicalFields: string[];
|
|
402
|
+
/** Precomputed parent path → child physical column names for fast null-setting. */
|
|
403
|
+
childrenByParent: Map<string, string[]>;
|
|
402
404
|
requiresMappings: boolean;
|
|
405
|
+
/** True when the only mappings needed are simple `@db.column` renames (no nesting/JSON). */
|
|
406
|
+
onlyColumnRenames: boolean;
|
|
403
407
|
toStorageFormatters?: Map<string, (value: unknown) => unknown>;
|
|
404
408
|
fromStorageFormatters?: Map<string, (value: unknown) => unknown>;
|
|
405
409
|
/** Leaf field descriptors indexed by physical column name (read path). */
|
|
@@ -958,13 +962,20 @@ declare abstract class FieldMappingStrategy {
|
|
|
958
962
|
abstract translateQuery(query: Uniquery, meta: TableMetadata): DbQuery;
|
|
959
963
|
abstract translateAggregateQuery(query: AggregateQuery, meta: TableMetadata): DbQuery;
|
|
960
964
|
/**
|
|
961
|
-
* Recursively walks a filter expression, applying
|
|
962
|
-
*
|
|
963
|
-
*
|
|
965
|
+
* Recursively walks a filter expression, applying `@db.column` key renames
|
|
966
|
+
* via `columnMap` and adapter-specific value formatting via `formatFilterValue`.
|
|
967
|
+
*
|
|
968
|
+
* The relational mapper overrides this to use `leafByLogical` for deeper
|
|
969
|
+
* key resolution (flattened nested paths).
|
|
964
970
|
*/
|
|
965
971
|
translateFilter(filter: FilterExpr, meta: TableMetadata): FilterExpr;
|
|
966
972
|
abstract prepareForWrite(payload: Record<string, unknown>, meta: TableMetadata, adapter: BaseDbAdapter): Record<string, unknown>;
|
|
967
973
|
abstract translatePatchKeys(update: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
|
|
974
|
+
/**
|
|
975
|
+
* Reverse-maps `@db.column` renames on a row read from storage.
|
|
976
|
+
* Renames physical keys back to logical names in-place.
|
|
977
|
+
*/
|
|
978
|
+
protected reverseColumnRenames(row: Record<string, unknown>, meta: TableMetadata): void;
|
|
968
979
|
/**
|
|
969
980
|
* Coerces field values from storage representation to JS types
|
|
970
981
|
* (booleans from 0/1, decimals from number to string).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as TDbInsertResult, H as TFkLookupResolver, O as TDbDeleteResult, P as TDbInsertManyResult, S as TCascadeResolver, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata, t as AtscriptDbReadable, z as TDbUpdateResult } from "./db-readable-
|
|
2
|
-
import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
|
|
1
|
+
import { F as TDbInsertResult, H as TFkLookupResolver, O as TDbDeleteResult, P as TDbInsertManyResult, S as TCascadeResolver, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata, t as AtscriptDbReadable, z as TDbUpdateResult } from "./db-readable-C3C-qPcP.cjs";
|
|
3
2
|
import { FilterExpr } from "@uniqu/core";
|
|
3
|
+
import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/strategies/integrity.d.ts
|
|
6
6
|
/**
|
|
@@ -130,9 +130,17 @@ declare class AtscriptDbTable<T extends TAtscriptAnnotatedType = TAtscriptAnnota
|
|
|
130
130
|
*/
|
|
131
131
|
protected _applyDefaults(data: Record<string, unknown>): Record<string, unknown>;
|
|
132
132
|
/**
|
|
133
|
-
* Extracts
|
|
133
|
+
* Extracts a record-identifying filter from a payload.
|
|
134
|
+
*
|
|
135
|
+
* Resolution order:
|
|
136
|
+
* 1. Primary key field(s) — if all PK fields are present in the payload.
|
|
137
|
+
* 2. Single-field unique index — first `@db.index.unique` field found.
|
|
138
|
+
* 3. Compound unique index — first compound unique index whose fields are all present.
|
|
139
|
+
*
|
|
140
|
+
* Throws when no identifying fields can be found.
|
|
134
141
|
*/
|
|
135
|
-
protected
|
|
142
|
+
protected _extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
143
|
+
private _prepareFilterValue;
|
|
136
144
|
/**
|
|
137
145
|
* Pre-validate items (type validation + FK constraints) without inserting them.
|
|
138
146
|
* Used by parent tables to validate FROM children before the main insert,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { F as TDbInsertResult, H as TFkLookupResolver, O as TDbDeleteResult, P as TDbInsertManyResult, S as TCascadeResolver, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata, t as AtscriptDbReadable, z as TDbUpdateResult } from "./db-readable-
|
|
2
|
-
import { FilterExpr } from "@uniqu/core";
|
|
1
|
+
import { F as TDbInsertResult, H as TFkLookupResolver, O as TDbDeleteResult, P as TDbInsertManyResult, S as TCascadeResolver, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata, t as AtscriptDbReadable, z as TDbUpdateResult } from "./db-readable-Cc868K54.mjs";
|
|
3
2
|
import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
|
|
3
|
+
import { FilterExpr } from "@uniqu/core";
|
|
4
4
|
|
|
5
5
|
//#region src/strategies/integrity.d.ts
|
|
6
6
|
/**
|
|
@@ -130,9 +130,17 @@ declare class AtscriptDbTable<T extends TAtscriptAnnotatedType = TAtscriptAnnota
|
|
|
130
130
|
*/
|
|
131
131
|
protected _applyDefaults(data: Record<string, unknown>): Record<string, unknown>;
|
|
132
132
|
/**
|
|
133
|
-
* Extracts
|
|
133
|
+
* Extracts a record-identifying filter from a payload.
|
|
134
|
+
*
|
|
135
|
+
* Resolution order:
|
|
136
|
+
* 1. Primary key field(s) — if all PK fields are present in the payload.
|
|
137
|
+
* 2. Single-field unique index — first `@db.index.unique` field found.
|
|
138
|
+
* 3. Compound unique index — first compound unique index whose fields are all present.
|
|
139
|
+
*
|
|
140
|
+
* Throws when no identifying fields can be found.
|
|
134
141
|
*/
|
|
135
|
-
protected
|
|
142
|
+
protected _extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
143
|
+
private _prepareFilterValue;
|
|
136
144
|
/**
|
|
137
145
|
* Pre-validate items (type validation + FK constraints) without inserting them.
|
|
138
146
|
* Used by parent tables to validate FROM children before the main insert,
|
|
@@ -5,6 +5,8 @@ interface DbValidationContext {
|
|
|
5
5
|
mode: "insert" | "replace" | "patch";
|
|
6
6
|
/** Flat map from the table — used to check if an array is a top-level array. */
|
|
7
7
|
flatMap?: Map<string, TAtscriptAnnotatedType>;
|
|
8
|
+
/** Precomputed nav field names — used to skip field-op validation inside TO/FROM/VIA relations. */
|
|
9
|
+
navFields?: ReadonlySet<string>;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Validator plugin for database operations.
|
|
@@ -5,6 +5,8 @@ interface DbValidationContext {
|
|
|
5
5
|
mode: "insert" | "replace" | "patch";
|
|
6
6
|
/** Flat map from the table — used to check if an array is a top-level array. */
|
|
7
7
|
flatMap?: Map<string, TAtscriptAnnotatedType>;
|
|
8
|
+
/** Precomputed nav field names — used to skip field-op validation inside TO/FROM/VIA relations. */
|
|
9
|
+
navFields?: ReadonlySet<string>;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Validator plugin for database operations.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_nested_writer = require("./nested-writer-
|
|
1
|
+
const require_nested_writer = require("./nested-writer-BIQ6EfaR.cjs");
|
|
2
2
|
const require_agg = require("./agg.cjs");
|
|
3
3
|
const require_relation_helpers = require("./relation-helpers-BYvsE1tR.cjs");
|
|
4
4
|
const require_ops = require("./ops.cjs");
|
|
@@ -69,7 +69,11 @@ var TableMetadata = class {
|
|
|
69
69
|
booleanFields = /* @__PURE__ */ new Set();
|
|
70
70
|
decimalFields = /* @__PURE__ */ new Set();
|
|
71
71
|
allPhysicalFields = [];
|
|
72
|
+
/** Precomputed parent path → child physical column names for fast null-setting. */
|
|
73
|
+
childrenByParent = /* @__PURE__ */ new Map();
|
|
72
74
|
requiresMappings = false;
|
|
75
|
+
/** True when the only mappings needed are simple `@db.column` renames (no nesting/JSON). */
|
|
76
|
+
onlyColumnRenames = false;
|
|
73
77
|
toStorageFormatters;
|
|
74
78
|
fromStorageFormatters;
|
|
75
79
|
/** Leaf field descriptors indexed by physical column name (read path). */
|
|
@@ -300,7 +304,8 @@ var TableMetadata = class {
|
|
|
300
304
|
for (const [path, physical] of this.pathToPhysical) if (path.startsWith(prefix)) leaves.push(physical);
|
|
301
305
|
if (leaves.length > 0) this.selectExpansion.set(parentPath, leaves);
|
|
302
306
|
}
|
|
303
|
-
this.
|
|
307
|
+
this.onlyColumnRenames = this.columnMap.size > 0 && this.flattenedParents.size === 0 && this.jsonFields.size === 0;
|
|
308
|
+
this.requiresMappings = this.flattenedParents.size > 0 || this.jsonFields.size > 0 || this.onlyColumnRenames;
|
|
304
309
|
}
|
|
305
310
|
/** Returns the `__`-separated parent prefix for a dot-separated path, or empty string for top-level paths. */
|
|
306
311
|
_flattenedPrefix(path) {
|
|
@@ -317,6 +322,12 @@ var TableMetadata = class {
|
|
|
317
322
|
this.leafByPhysical.set(fd.physicalName, fd);
|
|
318
323
|
this.leafByLogical.set(fd.path, fd);
|
|
319
324
|
}
|
|
325
|
+
for (const parentPath of this.flattenedParents) {
|
|
326
|
+
const prefix = `${parentPath}.`;
|
|
327
|
+
const children = [];
|
|
328
|
+
for (const [path, fd] of this.leafByLogical.entries()) if (path.startsWith(prefix)) children.push(fd.physicalName);
|
|
329
|
+
if (children.length > 0) this.childrenByParent.set(parentPath, children);
|
|
330
|
+
}
|
|
320
331
|
}
|
|
321
332
|
/**
|
|
322
333
|
* Builds field descriptors, physical-name lookup, and value formatters.
|
|
@@ -540,21 +551,36 @@ function toDecimalString(value) {
|
|
|
540
551
|
*/
|
|
541
552
|
var FieldMappingStrategy = class {
|
|
542
553
|
/**
|
|
543
|
-
* Recursively walks a filter expression, applying
|
|
544
|
-
*
|
|
545
|
-
*
|
|
554
|
+
* Recursively walks a filter expression, applying `@db.column` key renames
|
|
555
|
+
* via `columnMap` and adapter-specific value formatting via `formatFilterValue`.
|
|
556
|
+
*
|
|
557
|
+
* The relational mapper overrides this to use `leafByLogical` for deeper
|
|
558
|
+
* key resolution (flattened nested paths).
|
|
546
559
|
*/
|
|
547
560
|
translateFilter(filter, meta) {
|
|
548
561
|
if (!filter || typeof filter !== "object") return filter;
|
|
549
|
-
if (!meta.toStorageFormatters) return filter;
|
|
562
|
+
if (!meta.toStorageFormatters && meta.columnMap.size === 0) return filter;
|
|
550
563
|
const result = {};
|
|
551
564
|
for (const [key, value] of Object.entries(filter)) if (key === "$and" || key === "$or") result[key] = value.map((f) => this.translateFilter(f, meta));
|
|
552
565
|
else if (key === "$not") result[key] = this.translateFilter(value, meta);
|
|
553
566
|
else if (key.startsWith("$")) result[key] = value;
|
|
554
|
-
else
|
|
567
|
+
else {
|
|
568
|
+
const physical = meta.columnMap.get(key) ?? key;
|
|
569
|
+
result[physical] = this.formatFilterValue(physical, value, meta);
|
|
570
|
+
}
|
|
555
571
|
return result;
|
|
556
572
|
}
|
|
557
573
|
/**
|
|
574
|
+
* Reverse-maps `@db.column` renames on a row read from storage.
|
|
575
|
+
* Renames physical keys back to logical names in-place.
|
|
576
|
+
*/
|
|
577
|
+
reverseColumnRenames(row, meta) {
|
|
578
|
+
for (const [logical, physical] of meta.columnMap.entries()) if (physical in row) {
|
|
579
|
+
row[logical] = row[physical];
|
|
580
|
+
delete row[physical];
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
558
584
|
* Coerces field values from storage representation to JS types
|
|
559
585
|
* (booleans from 0/1, decimals from number to string).
|
|
560
586
|
*/
|
|
@@ -662,12 +688,15 @@ var FieldMappingStrategy = class {
|
|
|
662
688
|
*/
|
|
663
689
|
var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
664
690
|
reconstructFromRead(row, meta) {
|
|
665
|
-
|
|
691
|
+
this.coerceFieldValues(row, meta);
|
|
692
|
+
this.applyFromStorageFormatters(row, meta);
|
|
693
|
+
if (meta.columnMap.size > 0) this.reverseColumnRenames(row, meta);
|
|
694
|
+
return row;
|
|
666
695
|
}
|
|
667
696
|
translateQuery(query, meta) {
|
|
668
697
|
const controls = query.controls;
|
|
669
698
|
return {
|
|
670
|
-
filter:
|
|
699
|
+
filter: this.translateFilter(query.filter, meta),
|
|
671
700
|
controls: {
|
|
672
701
|
...controls,
|
|
673
702
|
$with: void 0,
|
|
@@ -679,7 +708,7 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
679
708
|
translateAggregateQuery(query, meta) {
|
|
680
709
|
const controls = query.controls;
|
|
681
710
|
return {
|
|
682
|
-
filter:
|
|
711
|
+
filter: this.translateFilter(query.filter ?? {}, meta),
|
|
683
712
|
controls: {
|
|
684
713
|
...controls,
|
|
685
714
|
$with: void 0,
|
|
@@ -698,6 +727,11 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
698
727
|
return this.formatWriteValues(data, meta);
|
|
699
728
|
}
|
|
700
729
|
translatePatchKeys(update, meta) {
|
|
730
|
+
if (meta.columnMap.size > 0) {
|
|
731
|
+
const result = {};
|
|
732
|
+
for (const key of Object.keys(update)) result[meta.columnMap.get(key) ?? key] = update[key];
|
|
733
|
+
return this.formatWriteValues(result, meta);
|
|
734
|
+
}
|
|
701
735
|
return this.formatWriteValues(update, meta);
|
|
702
736
|
}
|
|
703
737
|
};
|
|
@@ -712,6 +746,12 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
712
746
|
var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
713
747
|
reconstructFromRead(row, meta) {
|
|
714
748
|
if (!meta.requiresMappings) return this.applyFromStorageFormatters(this.coerceFieldValues(row, meta), meta);
|
|
749
|
+
if (meta.onlyColumnRenames) {
|
|
750
|
+
this.coerceFieldValues(row, meta);
|
|
751
|
+
this.applyFromStorageFormatters(row, meta);
|
|
752
|
+
this.reverseColumnRenames(row, meta);
|
|
753
|
+
return row;
|
|
754
|
+
}
|
|
715
755
|
const result = {};
|
|
716
756
|
const fromFmts = meta.fromStorageFormatters;
|
|
717
757
|
for (const physical of Object.keys(row)) {
|
|
@@ -794,6 +834,15 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
794
834
|
};
|
|
795
835
|
}
|
|
796
836
|
/**
|
|
837
|
+
* Overrides the base `translateFilter` to use `leafByLogical` for key resolution
|
|
838
|
+
* (handles flattened nested paths like `contact.email` → `contact__email`).
|
|
839
|
+
*/
|
|
840
|
+
translateFilter(filter, meta) {
|
|
841
|
+
if (!filter || typeof filter !== "object") return filter;
|
|
842
|
+
if (!meta.requiresMappings && !meta.toStorageFormatters) return filter;
|
|
843
|
+
return this.translateFilterWithRename(filter, meta);
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
797
846
|
* Translates filter with key renaming from logical to physical names.
|
|
798
847
|
* Used by the relational query path where field paths must be mapped
|
|
799
848
|
* to `__`-separated column names.
|
|
@@ -813,7 +862,8 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
813
862
|
prepareForWrite(payload, meta, adapter) {
|
|
814
863
|
const data = { ...payload };
|
|
815
864
|
this.prepareCommon(data, meta, adapter);
|
|
816
|
-
if (!meta.requiresMappings)
|
|
865
|
+
if (!meta.requiresMappings) return this.formatWriteValues(data, meta);
|
|
866
|
+
if (meta.onlyColumnRenames) {
|
|
817
867
|
for (const [logical, physical] of meta.columnMap.entries()) if (logical in data) {
|
|
818
868
|
data[physical] = data[logical];
|
|
819
869
|
delete data[logical];
|
|
@@ -824,6 +874,11 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
824
874
|
}
|
|
825
875
|
translatePatchKeys(update, meta) {
|
|
826
876
|
if (!meta.requiresMappings && !meta.toStorageFormatters) return update;
|
|
877
|
+
if (meta.onlyColumnRenames && !meta.toStorageFormatters) {
|
|
878
|
+
const result = {};
|
|
879
|
+
for (const key of Object.keys(update)) result[meta.leafByLogical.get(key)?.physicalName ?? key] = update[key];
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
827
882
|
const result = {};
|
|
828
883
|
const updateKeys = Object.keys(update);
|
|
829
884
|
for (const key of updateKeys) {
|
|
@@ -921,8 +976,8 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
921
976
|
* When a parent object is null/undefined, set all its flattened children to null.
|
|
922
977
|
*/
|
|
923
978
|
setFlattenedChildrenNull(parentPath, result, meta) {
|
|
924
|
-
const
|
|
925
|
-
for (const
|
|
979
|
+
const children = meta.childrenByParent.get(parentPath);
|
|
980
|
+
if (children) for (const physical of children) result[physical] = null;
|
|
926
981
|
}
|
|
927
982
|
};
|
|
928
983
|
//#endregion
|
|
@@ -2108,16 +2163,52 @@ function createDbValidatorPlugin() {
|
|
|
2108
2163
|
const isFrom = def.metadata.has("db.rel.from");
|
|
2109
2164
|
const isVia = def.metadata.has("db.rel.via");
|
|
2110
2165
|
if (isTo || isFrom || isVia) return handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia);
|
|
2111
|
-
if (dbCtx.mode === "patch"
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2166
|
+
if (dbCtx.mode === "patch") {
|
|
2167
|
+
if (require_ops.isDbFieldOp(value)) {
|
|
2168
|
+
if (dbCtx.flatMap && !isFieldOpAllowed(ctx.path, dbCtx.flatMap, dbCtx.navFields)) {
|
|
2169
|
+
ctx.error("Field operations ($inc/$dec/$mul) are not supported inside @db.json fields or nested objects without @db.patch.strategy \"merge\"");
|
|
2170
|
+
return false;
|
|
2171
|
+
}
|
|
2172
|
+
if (!(def.type.kind === "" && def.type.designType === "number")) {
|
|
2173
|
+
ctx.error("Field operations ($inc/$dec/$mul) can only be applied to numeric fields");
|
|
2174
|
+
return false;
|
|
2175
|
+
}
|
|
2176
|
+
return true;
|
|
2177
|
+
}
|
|
2178
|
+
if (def.type.kind === "array" && dbCtx.flatMap) {
|
|
2179
|
+
const flatEntry = dbCtx.flatMap.get(ctx.path);
|
|
2180
|
+
if (flatEntry?.metadata?.has("db.__topLevelArray") && !flatEntry.metadata.has("db.json")) return handleArrayPatch(ctx, def, value);
|
|
2181
|
+
}
|
|
2115
2182
|
}
|
|
2116
2183
|
};
|
|
2117
2184
|
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Checks whether a field op is valid at `path`.
|
|
2187
|
+
*
|
|
2188
|
+
* Rejects when:
|
|
2189
|
+
* - The field itself is `@db.json` (ops on opaque blobs are meaningless).
|
|
2190
|
+
* - Any ancestor is `@db.json`.
|
|
2191
|
+
* - Any ancestor is a nested object without `@db.patch.strategy "merge"`.
|
|
2192
|
+
*
|
|
2193
|
+
* Accepts immediately when an ancestor is a navigation field (TO/FROM/VIA) —
|
|
2194
|
+
* the nested data is extracted and validated against its own table separately.
|
|
2195
|
+
*/
|
|
2196
|
+
function isFieldOpAllowed(path, flatMap, navFields) {
|
|
2197
|
+
if (flatMap.get(path)?.metadata.has("db.json")) return false;
|
|
2198
|
+
let pos = path.length;
|
|
2199
|
+
while ((pos = path.lastIndexOf(".", pos - 1)) !== -1) {
|
|
2200
|
+
const ancestor = path.slice(0, pos);
|
|
2201
|
+
if (navFields?.has(ancestor)) return true;
|
|
2202
|
+
const entry = flatMap.get(ancestor);
|
|
2203
|
+
if (!entry) continue;
|
|
2204
|
+
if (entry.metadata.has("db.json")) return false;
|
|
2205
|
+
if (entry.type.kind === "object" && entry.metadata.get("db.patch.strategy") !== "merge") return false;
|
|
2206
|
+
}
|
|
2207
|
+
return true;
|
|
2208
|
+
}
|
|
2118
2209
|
function handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia) {
|
|
2119
|
-
const
|
|
2120
|
-
const fieldName =
|
|
2210
|
+
const dotIdx = ctx.path.lastIndexOf(".");
|
|
2211
|
+
const fieldName = dotIdx === -1 ? ctx.path : ctx.path.slice(dotIdx + 1);
|
|
2121
2212
|
if (value === null) {
|
|
2122
2213
|
ctx.error(`Cannot process null navigation property '${fieldName}'`);
|
|
2123
2214
|
return false;
|
|
@@ -2554,7 +2645,10 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2554
2645
|
if (!canNest && this._meta.navFields.size > 0) require_nested_writer.checkDepthOverflow(payloads, maxDepth, this._meta);
|
|
2555
2646
|
return require_nested_writer.enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2556
2647
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2557
|
-
require_nested_writer.validateBatch(this.getValidator("insert"), items, {
|
|
2648
|
+
require_nested_writer.validateBatch(this.getValidator("insert"), items, {
|
|
2649
|
+
mode: "insert",
|
|
2650
|
+
navFields: this._meta.navFields
|
|
2651
|
+
});
|
|
2558
2652
|
const host = this;
|
|
2559
2653
|
if (canNest) await require_nested_writer.batchInsertNestedTo(host, items, maxDepth, depth);
|
|
2560
2654
|
const prepared = [];
|
|
@@ -2594,7 +2688,10 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2594
2688
|
return require_nested_writer.enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2595
2689
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2596
2690
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2597
|
-
require_nested_writer.validateBatch(this.getValidator("bulkReplace"), items, {
|
|
2691
|
+
require_nested_writer.validateBatch(this.getValidator("bulkReplace"), items, {
|
|
2692
|
+
mode: "replace",
|
|
2693
|
+
navFields: this._meta.navFields
|
|
2694
|
+
});
|
|
2598
2695
|
const host = this;
|
|
2599
2696
|
if (canNest) await require_nested_writer.batchReplaceNestedTo(host, items, maxDepth, depth);
|
|
2600
2697
|
await this._integrity.validateForeignKeys(items, this._meta, this._fkLookupResolver, this._writeTableResolver);
|
|
@@ -2603,7 +2700,7 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2603
2700
|
let modifiedCount = 0;
|
|
2604
2701
|
for (const data of items) {
|
|
2605
2702
|
for (const navField of this._meta.navFields) delete data[navField];
|
|
2606
|
-
const filter = this.
|
|
2703
|
+
const filter = this._extractRecordFilter(data);
|
|
2607
2704
|
const prepared = this._fieldMapper.prepareForWrite(data, this._meta, this.adapter);
|
|
2608
2705
|
const result = await this.adapter.replaceOne(this._fieldMapper.translateFilter(filter, this._meta), prepared);
|
|
2609
2706
|
matchedCount += result.matchedCount;
|
|
@@ -2640,7 +2737,8 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2640
2737
|
return require_nested_writer.enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2641
2738
|
require_nested_writer.validateBatch(this.getValidator("bulkUpdate"), payloads, {
|
|
2642
2739
|
mode: "patch",
|
|
2643
|
-
flatMap: this.flatMap
|
|
2740
|
+
flatMap: this.flatMap,
|
|
2741
|
+
navFields: this._meta.navFields
|
|
2644
2742
|
});
|
|
2645
2743
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2646
2744
|
const host = this;
|
|
@@ -2651,20 +2749,24 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2651
2749
|
for (const payload of payloads) {
|
|
2652
2750
|
const data = { ...payload };
|
|
2653
2751
|
for (const navField of this._meta.navFields) delete data[navField];
|
|
2654
|
-
const filter = this.
|
|
2655
|
-
for (const
|
|
2656
|
-
|
|
2657
|
-
if (_isEmptyObj(data) && !ops) {
|
|
2752
|
+
const filter = this._extractRecordFilter(data);
|
|
2753
|
+
for (const key of Object.keys(filter)) delete data[key];
|
|
2754
|
+
if (_isEmptyObj(data)) {
|
|
2658
2755
|
matchedCount += 1;
|
|
2659
2756
|
modifiedCount += 0;
|
|
2660
2757
|
continue;
|
|
2661
2758
|
}
|
|
2662
2759
|
let result;
|
|
2663
2760
|
const translatedFilter = this._fieldMapper.translateFilter(filter, this._meta);
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2761
|
+
if (this.adapter.supportsNativePatch()) {
|
|
2762
|
+
const ops = require_ops.separateFieldOps(data);
|
|
2763
|
+
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2764
|
+
const translatedData = this._fieldMapper.translatePatchKeys(data, this._meta);
|
|
2765
|
+
result = await this.adapter.nativePatch(translatedFilter, translatedData, translatedOps);
|
|
2766
|
+
} else {
|
|
2667
2767
|
const update = decomposePatch(data, this);
|
|
2768
|
+
const ops = require_ops.separateFieldOps(update);
|
|
2769
|
+
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2668
2770
|
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
2669
2771
|
if (getArrayOpsFields(translatedUpdate).size > 0) {
|
|
2670
2772
|
const resolved = resolveArrayOps(translatedUpdate, await this.adapter.findOne({
|
|
@@ -2705,10 +2807,11 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2705
2807
|
async updateMany(filter, data) {
|
|
2706
2808
|
this._ensureBuilt();
|
|
2707
2809
|
await this._integrity.validateForeignKeys([data], this._meta, this._fkLookupResolver, this._writeTableResolver, true);
|
|
2708
|
-
const
|
|
2709
|
-
const ops = require_ops.separateFieldOps(
|
|
2810
|
+
const update = decomposePatch({ ...data }, this);
|
|
2811
|
+
const ops = require_ops.separateFieldOps(update);
|
|
2710
2812
|
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2711
|
-
|
|
2813
|
+
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
2814
|
+
return require_nested_writer.enrichFkViolation(this._meta, () => this.adapter.updateMany(this._fieldMapper.translateFilter(filter, this._meta), translatedUpdate, translatedOps));
|
|
2712
2815
|
}
|
|
2713
2816
|
async replaceMany(filter, data) {
|
|
2714
2817
|
this._ensureBuilt();
|
|
@@ -2761,24 +2864,55 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2761
2864
|
return data;
|
|
2762
2865
|
}
|
|
2763
2866
|
/**
|
|
2764
|
-
* Extracts
|
|
2867
|
+
* Extracts a record-identifying filter from a payload.
|
|
2868
|
+
*
|
|
2869
|
+
* Resolution order:
|
|
2870
|
+
* 1. Primary key field(s) — if all PK fields are present in the payload.
|
|
2871
|
+
* 2. Single-field unique index — first `@db.index.unique` field found.
|
|
2872
|
+
* 3. Compound unique index — first compound unique index whose fields are all present.
|
|
2873
|
+
*
|
|
2874
|
+
* Throws when no identifying fields can be found.
|
|
2765
2875
|
*/
|
|
2766
|
-
|
|
2876
|
+
_extractRecordFilter(payload) {
|
|
2767
2877
|
const pkFields = this.primaryKeys;
|
|
2878
|
+
if (pkFields.length > 0) {
|
|
2879
|
+
let allPresent = true;
|
|
2880
|
+
for (const field of pkFields) if (payload[field] === void 0) {
|
|
2881
|
+
allPresent = false;
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2884
|
+
if (allPresent) {
|
|
2885
|
+
const filter = {};
|
|
2886
|
+
for (const field of pkFields) filter[field] = this._prepareFilterValue(field, payload[field]);
|
|
2887
|
+
return filter;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
for (const prop of this.uniqueProps) if (payload[prop] !== void 0) return { [prop]: this._prepareFilterValue(prop, payload[prop]) };
|
|
2891
|
+
for (const index of this._meta.indexes.values()) {
|
|
2892
|
+
if (index.type !== "unique" || index.fields.length < 2) continue;
|
|
2893
|
+
let allPresent = true;
|
|
2894
|
+
for (const indexField of index.fields) if (payload[indexField.name] === void 0) {
|
|
2895
|
+
allPresent = false;
|
|
2896
|
+
break;
|
|
2897
|
+
}
|
|
2898
|
+
if (allPresent) {
|
|
2899
|
+
const filter = {};
|
|
2900
|
+
for (const indexField of index.fields) filter[indexField.name] = this._prepareFilterValue(indexField.name, payload[indexField.name]);
|
|
2901
|
+
return filter;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2768
2904
|
if (pkFields.length === 0) throw new require_nested_writer.DbError("NOT_FOUND", [{
|
|
2769
2905
|
path: "",
|
|
2770
2906
|
message: "No primary key defined — cannot extract filter"
|
|
2771
2907
|
}]);
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
}
|
|
2781
|
-
return filter;
|
|
2908
|
+
throw new require_nested_writer.DbError("NOT_FOUND", [{
|
|
2909
|
+
path: pkFields[0],
|
|
2910
|
+
message: `Missing primary key field "${pkFields[0]}" in payload`
|
|
2911
|
+
}]);
|
|
2912
|
+
}
|
|
2913
|
+
_prepareFilterValue(field, value) {
|
|
2914
|
+
const fieldType = this.flatMap.get(field);
|
|
2915
|
+
return fieldType ? this.adapter.prepareId(value, fieldType) : value;
|
|
2782
2916
|
}
|
|
2783
2917
|
/**
|
|
2784
2918
|
* Pre-validate items (type validation + FK constraints) without inserting them.
|
|
@@ -2789,7 +2923,12 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2789
2923
|
*/
|
|
2790
2924
|
async preValidateItems(items, opts) {
|
|
2791
2925
|
this._ensureBuilt();
|
|
2792
|
-
|
|
2926
|
+
const validator = this.getValidator("insert");
|
|
2927
|
+
const ctx = {
|
|
2928
|
+
mode: "insert",
|
|
2929
|
+
navFields: this._meta.navFields
|
|
2930
|
+
};
|
|
2931
|
+
require_nested_writer.validateBatch(validator, items.map((raw) => this._applyDefaults({ ...raw })), ctx);
|
|
2793
2932
|
await this._integrity.validateForeignKeys(items, this._meta, this._fkLookupResolver, this._writeTableResolver, false, opts?.excludeFkTargetTable);
|
|
2794
2933
|
}
|
|
2795
2934
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as batchPatchNestedTo, c as batchReplaceNestedTo, d as preValidateNestedFrom, f as validateBatch, h as DbError, i as batchPatchNestedFrom, l as batchReplaceNestedVia, m as remapDeleteFkViolation, n as batchInsertNestedTo, o as batchPatchNestedVia, p as enrichFkViolation, r as batchInsertNestedVia, s as batchReplaceNestedFrom, t as batchInsertNestedFrom, u as checkDepthOverflow } from "./nested-writer-
|
|
1
|
+
import { a as batchPatchNestedTo, c as batchReplaceNestedTo, d as preValidateNestedFrom, f as validateBatch, h as DbError, i as batchPatchNestedFrom, l as batchReplaceNestedVia, m as remapDeleteFkViolation, n as batchInsertNestedTo, o as batchPatchNestedVia, p as enrichFkViolation, r as batchInsertNestedVia, s as batchReplaceNestedFrom, t as batchInsertNestedFrom, u as checkDepthOverflow } from "./nested-writer-CNDyhg2L.mjs";
|
|
2
2
|
import { resolveAlias } from "./agg.mjs";
|
|
3
3
|
import { n as findRemoteFK, t as findFKForRelation } from "./relation-helpers-CLasawQq.mjs";
|
|
4
4
|
import { isDbFieldOp, separateFieldOps } from "./ops.mjs";
|
|
@@ -69,7 +69,11 @@ var TableMetadata = class {
|
|
|
69
69
|
booleanFields = /* @__PURE__ */ new Set();
|
|
70
70
|
decimalFields = /* @__PURE__ */ new Set();
|
|
71
71
|
allPhysicalFields = [];
|
|
72
|
+
/** Precomputed parent path → child physical column names for fast null-setting. */
|
|
73
|
+
childrenByParent = /* @__PURE__ */ new Map();
|
|
72
74
|
requiresMappings = false;
|
|
75
|
+
/** True when the only mappings needed are simple `@db.column` renames (no nesting/JSON). */
|
|
76
|
+
onlyColumnRenames = false;
|
|
73
77
|
toStorageFormatters;
|
|
74
78
|
fromStorageFormatters;
|
|
75
79
|
/** Leaf field descriptors indexed by physical column name (read path). */
|
|
@@ -300,7 +304,8 @@ var TableMetadata = class {
|
|
|
300
304
|
for (const [path, physical] of this.pathToPhysical) if (path.startsWith(prefix)) leaves.push(physical);
|
|
301
305
|
if (leaves.length > 0) this.selectExpansion.set(parentPath, leaves);
|
|
302
306
|
}
|
|
303
|
-
this.
|
|
307
|
+
this.onlyColumnRenames = this.columnMap.size > 0 && this.flattenedParents.size === 0 && this.jsonFields.size === 0;
|
|
308
|
+
this.requiresMappings = this.flattenedParents.size > 0 || this.jsonFields.size > 0 || this.onlyColumnRenames;
|
|
304
309
|
}
|
|
305
310
|
/** Returns the `__`-separated parent prefix for a dot-separated path, or empty string for top-level paths. */
|
|
306
311
|
_flattenedPrefix(path) {
|
|
@@ -317,6 +322,12 @@ var TableMetadata = class {
|
|
|
317
322
|
this.leafByPhysical.set(fd.physicalName, fd);
|
|
318
323
|
this.leafByLogical.set(fd.path, fd);
|
|
319
324
|
}
|
|
325
|
+
for (const parentPath of this.flattenedParents) {
|
|
326
|
+
const prefix = `${parentPath}.`;
|
|
327
|
+
const children = [];
|
|
328
|
+
for (const [path, fd] of this.leafByLogical.entries()) if (path.startsWith(prefix)) children.push(fd.physicalName);
|
|
329
|
+
if (children.length > 0) this.childrenByParent.set(parentPath, children);
|
|
330
|
+
}
|
|
320
331
|
}
|
|
321
332
|
/**
|
|
322
333
|
* Builds field descriptors, physical-name lookup, and value formatters.
|
|
@@ -540,21 +551,36 @@ function toDecimalString(value) {
|
|
|
540
551
|
*/
|
|
541
552
|
var FieldMappingStrategy = class {
|
|
542
553
|
/**
|
|
543
|
-
* Recursively walks a filter expression, applying
|
|
544
|
-
*
|
|
545
|
-
*
|
|
554
|
+
* Recursively walks a filter expression, applying `@db.column` key renames
|
|
555
|
+
* via `columnMap` and adapter-specific value formatting via `formatFilterValue`.
|
|
556
|
+
*
|
|
557
|
+
* The relational mapper overrides this to use `leafByLogical` for deeper
|
|
558
|
+
* key resolution (flattened nested paths).
|
|
546
559
|
*/
|
|
547
560
|
translateFilter(filter, meta) {
|
|
548
561
|
if (!filter || typeof filter !== "object") return filter;
|
|
549
|
-
if (!meta.toStorageFormatters) return filter;
|
|
562
|
+
if (!meta.toStorageFormatters && meta.columnMap.size === 0) return filter;
|
|
550
563
|
const result = {};
|
|
551
564
|
for (const [key, value] of Object.entries(filter)) if (key === "$and" || key === "$or") result[key] = value.map((f) => this.translateFilter(f, meta));
|
|
552
565
|
else if (key === "$not") result[key] = this.translateFilter(value, meta);
|
|
553
566
|
else if (key.startsWith("$")) result[key] = value;
|
|
554
|
-
else
|
|
567
|
+
else {
|
|
568
|
+
const physical = meta.columnMap.get(key) ?? key;
|
|
569
|
+
result[physical] = this.formatFilterValue(physical, value, meta);
|
|
570
|
+
}
|
|
555
571
|
return result;
|
|
556
572
|
}
|
|
557
573
|
/**
|
|
574
|
+
* Reverse-maps `@db.column` renames on a row read from storage.
|
|
575
|
+
* Renames physical keys back to logical names in-place.
|
|
576
|
+
*/
|
|
577
|
+
reverseColumnRenames(row, meta) {
|
|
578
|
+
for (const [logical, physical] of meta.columnMap.entries()) if (physical in row) {
|
|
579
|
+
row[logical] = row[physical];
|
|
580
|
+
delete row[physical];
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
558
584
|
* Coerces field values from storage representation to JS types
|
|
559
585
|
* (booleans from 0/1, decimals from number to string).
|
|
560
586
|
*/
|
|
@@ -662,12 +688,15 @@ var FieldMappingStrategy = class {
|
|
|
662
688
|
*/
|
|
663
689
|
var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
664
690
|
reconstructFromRead(row, meta) {
|
|
665
|
-
|
|
691
|
+
this.coerceFieldValues(row, meta);
|
|
692
|
+
this.applyFromStorageFormatters(row, meta);
|
|
693
|
+
if (meta.columnMap.size > 0) this.reverseColumnRenames(row, meta);
|
|
694
|
+
return row;
|
|
666
695
|
}
|
|
667
696
|
translateQuery(query, meta) {
|
|
668
697
|
const controls = query.controls;
|
|
669
698
|
return {
|
|
670
|
-
filter:
|
|
699
|
+
filter: this.translateFilter(query.filter, meta),
|
|
671
700
|
controls: {
|
|
672
701
|
...controls,
|
|
673
702
|
$with: void 0,
|
|
@@ -679,7 +708,7 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
679
708
|
translateAggregateQuery(query, meta) {
|
|
680
709
|
const controls = query.controls;
|
|
681
710
|
return {
|
|
682
|
-
filter:
|
|
711
|
+
filter: this.translateFilter(query.filter ?? {}, meta),
|
|
683
712
|
controls: {
|
|
684
713
|
...controls,
|
|
685
714
|
$with: void 0,
|
|
@@ -698,6 +727,11 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
698
727
|
return this.formatWriteValues(data, meta);
|
|
699
728
|
}
|
|
700
729
|
translatePatchKeys(update, meta) {
|
|
730
|
+
if (meta.columnMap.size > 0) {
|
|
731
|
+
const result = {};
|
|
732
|
+
for (const key of Object.keys(update)) result[meta.columnMap.get(key) ?? key] = update[key];
|
|
733
|
+
return this.formatWriteValues(result, meta);
|
|
734
|
+
}
|
|
701
735
|
return this.formatWriteValues(update, meta);
|
|
702
736
|
}
|
|
703
737
|
};
|
|
@@ -712,6 +746,12 @@ var DocumentFieldMapper = class extends FieldMappingStrategy {
|
|
|
712
746
|
var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
713
747
|
reconstructFromRead(row, meta) {
|
|
714
748
|
if (!meta.requiresMappings) return this.applyFromStorageFormatters(this.coerceFieldValues(row, meta), meta);
|
|
749
|
+
if (meta.onlyColumnRenames) {
|
|
750
|
+
this.coerceFieldValues(row, meta);
|
|
751
|
+
this.applyFromStorageFormatters(row, meta);
|
|
752
|
+
this.reverseColumnRenames(row, meta);
|
|
753
|
+
return row;
|
|
754
|
+
}
|
|
715
755
|
const result = {};
|
|
716
756
|
const fromFmts = meta.fromStorageFormatters;
|
|
717
757
|
for (const physical of Object.keys(row)) {
|
|
@@ -794,6 +834,15 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
794
834
|
};
|
|
795
835
|
}
|
|
796
836
|
/**
|
|
837
|
+
* Overrides the base `translateFilter` to use `leafByLogical` for key resolution
|
|
838
|
+
* (handles flattened nested paths like `contact.email` → `contact__email`).
|
|
839
|
+
*/
|
|
840
|
+
translateFilter(filter, meta) {
|
|
841
|
+
if (!filter || typeof filter !== "object") return filter;
|
|
842
|
+
if (!meta.requiresMappings && !meta.toStorageFormatters) return filter;
|
|
843
|
+
return this.translateFilterWithRename(filter, meta);
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
797
846
|
* Translates filter with key renaming from logical to physical names.
|
|
798
847
|
* Used by the relational query path where field paths must be mapped
|
|
799
848
|
* to `__`-separated column names.
|
|
@@ -813,7 +862,8 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
813
862
|
prepareForWrite(payload, meta, adapter) {
|
|
814
863
|
const data = { ...payload };
|
|
815
864
|
this.prepareCommon(data, meta, adapter);
|
|
816
|
-
if (!meta.requiresMappings)
|
|
865
|
+
if (!meta.requiresMappings) return this.formatWriteValues(data, meta);
|
|
866
|
+
if (meta.onlyColumnRenames) {
|
|
817
867
|
for (const [logical, physical] of meta.columnMap.entries()) if (logical in data) {
|
|
818
868
|
data[physical] = data[logical];
|
|
819
869
|
delete data[logical];
|
|
@@ -824,6 +874,11 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
824
874
|
}
|
|
825
875
|
translatePatchKeys(update, meta) {
|
|
826
876
|
if (!meta.requiresMappings && !meta.toStorageFormatters) return update;
|
|
877
|
+
if (meta.onlyColumnRenames && !meta.toStorageFormatters) {
|
|
878
|
+
const result = {};
|
|
879
|
+
for (const key of Object.keys(update)) result[meta.leafByLogical.get(key)?.physicalName ?? key] = update[key];
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
827
882
|
const result = {};
|
|
828
883
|
const updateKeys = Object.keys(update);
|
|
829
884
|
for (const key of updateKeys) {
|
|
@@ -921,8 +976,8 @@ var RelationalFieldMapper = class extends FieldMappingStrategy {
|
|
|
921
976
|
* When a parent object is null/undefined, set all its flattened children to null.
|
|
922
977
|
*/
|
|
923
978
|
setFlattenedChildrenNull(parentPath, result, meta) {
|
|
924
|
-
const
|
|
925
|
-
for (const
|
|
979
|
+
const children = meta.childrenByParent.get(parentPath);
|
|
980
|
+
if (children) for (const physical of children) result[physical] = null;
|
|
926
981
|
}
|
|
927
982
|
};
|
|
928
983
|
//#endregion
|
|
@@ -2108,16 +2163,52 @@ function createDbValidatorPlugin() {
|
|
|
2108
2163
|
const isFrom = def.metadata.has("db.rel.from");
|
|
2109
2164
|
const isVia = def.metadata.has("db.rel.via");
|
|
2110
2165
|
if (isTo || isFrom || isVia) return handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia);
|
|
2111
|
-
if (dbCtx.mode === "patch"
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2166
|
+
if (dbCtx.mode === "patch") {
|
|
2167
|
+
if (isDbFieldOp(value)) {
|
|
2168
|
+
if (dbCtx.flatMap && !isFieldOpAllowed(ctx.path, dbCtx.flatMap, dbCtx.navFields)) {
|
|
2169
|
+
ctx.error("Field operations ($inc/$dec/$mul) are not supported inside @db.json fields or nested objects without @db.patch.strategy \"merge\"");
|
|
2170
|
+
return false;
|
|
2171
|
+
}
|
|
2172
|
+
if (!(def.type.kind === "" && def.type.designType === "number")) {
|
|
2173
|
+
ctx.error("Field operations ($inc/$dec/$mul) can only be applied to numeric fields");
|
|
2174
|
+
return false;
|
|
2175
|
+
}
|
|
2176
|
+
return true;
|
|
2177
|
+
}
|
|
2178
|
+
if (def.type.kind === "array" && dbCtx.flatMap) {
|
|
2179
|
+
const flatEntry = dbCtx.flatMap.get(ctx.path);
|
|
2180
|
+
if (flatEntry?.metadata?.has("db.__topLevelArray") && !flatEntry.metadata.has("db.json")) return handleArrayPatch(ctx, def, value);
|
|
2181
|
+
}
|
|
2115
2182
|
}
|
|
2116
2183
|
};
|
|
2117
2184
|
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Checks whether a field op is valid at `path`.
|
|
2187
|
+
*
|
|
2188
|
+
* Rejects when:
|
|
2189
|
+
* - The field itself is `@db.json` (ops on opaque blobs are meaningless).
|
|
2190
|
+
* - Any ancestor is `@db.json`.
|
|
2191
|
+
* - Any ancestor is a nested object without `@db.patch.strategy "merge"`.
|
|
2192
|
+
*
|
|
2193
|
+
* Accepts immediately when an ancestor is a navigation field (TO/FROM/VIA) —
|
|
2194
|
+
* the nested data is extracted and validated against its own table separately.
|
|
2195
|
+
*/
|
|
2196
|
+
function isFieldOpAllowed(path, flatMap, navFields) {
|
|
2197
|
+
if (flatMap.get(path)?.metadata.has("db.json")) return false;
|
|
2198
|
+
let pos = path.length;
|
|
2199
|
+
while ((pos = path.lastIndexOf(".", pos - 1)) !== -1) {
|
|
2200
|
+
const ancestor = path.slice(0, pos);
|
|
2201
|
+
if (navFields?.has(ancestor)) return true;
|
|
2202
|
+
const entry = flatMap.get(ancestor);
|
|
2203
|
+
if (!entry) continue;
|
|
2204
|
+
if (entry.metadata.has("db.json")) return false;
|
|
2205
|
+
if (entry.type.kind === "object" && entry.metadata.get("db.patch.strategy") !== "merge") return false;
|
|
2206
|
+
}
|
|
2207
|
+
return true;
|
|
2208
|
+
}
|
|
2118
2209
|
function handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia) {
|
|
2119
|
-
const
|
|
2120
|
-
const fieldName =
|
|
2210
|
+
const dotIdx = ctx.path.lastIndexOf(".");
|
|
2211
|
+
const fieldName = dotIdx === -1 ? ctx.path : ctx.path.slice(dotIdx + 1);
|
|
2121
2212
|
if (value === null) {
|
|
2122
2213
|
ctx.error(`Cannot process null navigation property '${fieldName}'`);
|
|
2123
2214
|
return false;
|
|
@@ -2554,7 +2645,10 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2554
2645
|
if (!canNest && this._meta.navFields.size > 0) checkDepthOverflow(payloads, maxDepth, this._meta);
|
|
2555
2646
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2556
2647
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2557
|
-
validateBatch(this.getValidator("insert"), items, {
|
|
2648
|
+
validateBatch(this.getValidator("insert"), items, {
|
|
2649
|
+
mode: "insert",
|
|
2650
|
+
navFields: this._meta.navFields
|
|
2651
|
+
});
|
|
2558
2652
|
const host = this;
|
|
2559
2653
|
if (canNest) await batchInsertNestedTo(host, items, maxDepth, depth);
|
|
2560
2654
|
const prepared = [];
|
|
@@ -2594,7 +2688,10 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2594
2688
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2595
2689
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2596
2690
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2597
|
-
validateBatch(this.getValidator("bulkReplace"), items, {
|
|
2691
|
+
validateBatch(this.getValidator("bulkReplace"), items, {
|
|
2692
|
+
mode: "replace",
|
|
2693
|
+
navFields: this._meta.navFields
|
|
2694
|
+
});
|
|
2598
2695
|
const host = this;
|
|
2599
2696
|
if (canNest) await batchReplaceNestedTo(host, items, maxDepth, depth);
|
|
2600
2697
|
await this._integrity.validateForeignKeys(items, this._meta, this._fkLookupResolver, this._writeTableResolver);
|
|
@@ -2603,7 +2700,7 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2603
2700
|
let modifiedCount = 0;
|
|
2604
2701
|
for (const data of items) {
|
|
2605
2702
|
for (const navField of this._meta.navFields) delete data[navField];
|
|
2606
|
-
const filter = this.
|
|
2703
|
+
const filter = this._extractRecordFilter(data);
|
|
2607
2704
|
const prepared = this._fieldMapper.prepareForWrite(data, this._meta, this.adapter);
|
|
2608
2705
|
const result = await this.adapter.replaceOne(this._fieldMapper.translateFilter(filter, this._meta), prepared);
|
|
2609
2706
|
matchedCount += result.matchedCount;
|
|
@@ -2640,7 +2737,8 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2640
2737
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2641
2738
|
validateBatch(this.getValidator("bulkUpdate"), payloads, {
|
|
2642
2739
|
mode: "patch",
|
|
2643
|
-
flatMap: this.flatMap
|
|
2740
|
+
flatMap: this.flatMap,
|
|
2741
|
+
navFields: this._meta.navFields
|
|
2644
2742
|
});
|
|
2645
2743
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2646
2744
|
const host = this;
|
|
@@ -2651,20 +2749,24 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2651
2749
|
for (const payload of payloads) {
|
|
2652
2750
|
const data = { ...payload };
|
|
2653
2751
|
for (const navField of this._meta.navFields) delete data[navField];
|
|
2654
|
-
const filter = this.
|
|
2655
|
-
for (const
|
|
2656
|
-
|
|
2657
|
-
if (_isEmptyObj(data) && !ops) {
|
|
2752
|
+
const filter = this._extractRecordFilter(data);
|
|
2753
|
+
for (const key of Object.keys(filter)) delete data[key];
|
|
2754
|
+
if (_isEmptyObj(data)) {
|
|
2658
2755
|
matchedCount += 1;
|
|
2659
2756
|
modifiedCount += 0;
|
|
2660
2757
|
continue;
|
|
2661
2758
|
}
|
|
2662
2759
|
let result;
|
|
2663
2760
|
const translatedFilter = this._fieldMapper.translateFilter(filter, this._meta);
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2761
|
+
if (this.adapter.supportsNativePatch()) {
|
|
2762
|
+
const ops = separateFieldOps(data);
|
|
2763
|
+
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2764
|
+
const translatedData = this._fieldMapper.translatePatchKeys(data, this._meta);
|
|
2765
|
+
result = await this.adapter.nativePatch(translatedFilter, translatedData, translatedOps);
|
|
2766
|
+
} else {
|
|
2667
2767
|
const update = decomposePatch(data, this);
|
|
2768
|
+
const ops = separateFieldOps(update);
|
|
2769
|
+
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2668
2770
|
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
2669
2771
|
if (getArrayOpsFields(translatedUpdate).size > 0) {
|
|
2670
2772
|
const resolved = resolveArrayOps(translatedUpdate, await this.adapter.findOne({
|
|
@@ -2705,10 +2807,11 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2705
2807
|
async updateMany(filter, data) {
|
|
2706
2808
|
this._ensureBuilt();
|
|
2707
2809
|
await this._integrity.validateForeignKeys([data], this._meta, this._fkLookupResolver, this._writeTableResolver, true);
|
|
2708
|
-
const
|
|
2709
|
-
const ops = separateFieldOps(
|
|
2810
|
+
const update = decomposePatch({ ...data }, this);
|
|
2811
|
+
const ops = separateFieldOps(update);
|
|
2710
2812
|
const translatedOps = ops ? _translateOpsKeys(ops, this._meta) : void 0;
|
|
2711
|
-
|
|
2813
|
+
const translatedUpdate = this._fieldMapper.translatePatchKeys(update, this._meta);
|
|
2814
|
+
return enrichFkViolation(this._meta, () => this.adapter.updateMany(this._fieldMapper.translateFilter(filter, this._meta), translatedUpdate, translatedOps));
|
|
2712
2815
|
}
|
|
2713
2816
|
async replaceMany(filter, data) {
|
|
2714
2817
|
this._ensureBuilt();
|
|
@@ -2761,24 +2864,55 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2761
2864
|
return data;
|
|
2762
2865
|
}
|
|
2763
2866
|
/**
|
|
2764
|
-
* Extracts
|
|
2867
|
+
* Extracts a record-identifying filter from a payload.
|
|
2868
|
+
*
|
|
2869
|
+
* Resolution order:
|
|
2870
|
+
* 1. Primary key field(s) — if all PK fields are present in the payload.
|
|
2871
|
+
* 2. Single-field unique index — first `@db.index.unique` field found.
|
|
2872
|
+
* 3. Compound unique index — first compound unique index whose fields are all present.
|
|
2873
|
+
*
|
|
2874
|
+
* Throws when no identifying fields can be found.
|
|
2765
2875
|
*/
|
|
2766
|
-
|
|
2876
|
+
_extractRecordFilter(payload) {
|
|
2767
2877
|
const pkFields = this.primaryKeys;
|
|
2878
|
+
if (pkFields.length > 0) {
|
|
2879
|
+
let allPresent = true;
|
|
2880
|
+
for (const field of pkFields) if (payload[field] === void 0) {
|
|
2881
|
+
allPresent = false;
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2884
|
+
if (allPresent) {
|
|
2885
|
+
const filter = {};
|
|
2886
|
+
for (const field of pkFields) filter[field] = this._prepareFilterValue(field, payload[field]);
|
|
2887
|
+
return filter;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
for (const prop of this.uniqueProps) if (payload[prop] !== void 0) return { [prop]: this._prepareFilterValue(prop, payload[prop]) };
|
|
2891
|
+
for (const index of this._meta.indexes.values()) {
|
|
2892
|
+
if (index.type !== "unique" || index.fields.length < 2) continue;
|
|
2893
|
+
let allPresent = true;
|
|
2894
|
+
for (const indexField of index.fields) if (payload[indexField.name] === void 0) {
|
|
2895
|
+
allPresent = false;
|
|
2896
|
+
break;
|
|
2897
|
+
}
|
|
2898
|
+
if (allPresent) {
|
|
2899
|
+
const filter = {};
|
|
2900
|
+
for (const indexField of index.fields) filter[indexField.name] = this._prepareFilterValue(indexField.name, payload[indexField.name]);
|
|
2901
|
+
return filter;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2768
2904
|
if (pkFields.length === 0) throw new DbError("NOT_FOUND", [{
|
|
2769
2905
|
path: "",
|
|
2770
2906
|
message: "No primary key defined — cannot extract filter"
|
|
2771
2907
|
}]);
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
}
|
|
2781
|
-
return filter;
|
|
2908
|
+
throw new DbError("NOT_FOUND", [{
|
|
2909
|
+
path: pkFields[0],
|
|
2910
|
+
message: `Missing primary key field "${pkFields[0]}" in payload`
|
|
2911
|
+
}]);
|
|
2912
|
+
}
|
|
2913
|
+
_prepareFilterValue(field, value) {
|
|
2914
|
+
const fieldType = this.flatMap.get(field);
|
|
2915
|
+
return fieldType ? this.adapter.prepareId(value, fieldType) : value;
|
|
2782
2916
|
}
|
|
2783
2917
|
/**
|
|
2784
2918
|
* Pre-validate items (type validation + FK constraints) without inserting them.
|
|
@@ -2789,7 +2923,12 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2789
2923
|
*/
|
|
2790
2924
|
async preValidateItems(items, opts) {
|
|
2791
2925
|
this._ensureBuilt();
|
|
2792
|
-
|
|
2926
|
+
const validator = this.getValidator("insert");
|
|
2927
|
+
const ctx = {
|
|
2928
|
+
mode: "insert",
|
|
2929
|
+
navFields: this._meta.navFields
|
|
2930
|
+
};
|
|
2931
|
+
validateBatch(validator, items.map((raw) => this._applyDefaults({ ...raw })), ctx);
|
|
2793
2932
|
await this._integrity.validateForeignKeys(items, this._meta, this._fkLookupResolver, this._writeTableResolver, false, opts?.excludeFkTargetTable);
|
|
2794
2933
|
}
|
|
2795
2934
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_nested_writer = require("./nested-writer-
|
|
3
|
-
const require_db_view = require("./db-view-
|
|
2
|
+
const require_nested_writer = require("./nested-writer-BIQ6EfaR.cjs");
|
|
3
|
+
const require_db_view = require("./db-view-CcUjETIF.cjs");
|
|
4
4
|
const require_ops = require("./ops.cjs");
|
|
5
5
|
let _uniqu_core = require("@uniqu/core");
|
|
6
6
|
//#region src/table/db-space.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as Uniquery, A as TDbForeignKey, B as TExistingColumn, C as TCascadeTarget, D as TDbDefaultValue, E as TDbDefaultFn, F as TDbInsertResult, G as TMetadataOverrides, H as TFkLookupResolver, I as TDbReferentialAction, J as TTableOptionDiff, K as TSearchIndexInfo, L as TDbRelation, M as TDbIndexField, N as TDbIndexType, O as TDbDeleteResult, P as TDbInsertManyResult, Q as TypedWithRelation, R as TDbStorageType, S as TCascadeResolver, T as TDbCollation, U as TFkLookupTarget, V as TExistingTableOption, W as TIdDescriptor, X as TValueFormatterPair, Y as TTableResolver, Z as TWriteTableResolver, _ as DbQuery, a as FieldMappingStrategy, b as NavPropsOf, c as NoopLogger, d as AggregateExpr, et as UniqueryControls, f as AggregateFn, g as DbControls, h as AtscriptDbWritable, i as DocumentFieldMapper, j as TDbIndex, k as TDbFieldMeta, l as TGenericLogger, m as AggregateResult, n as DbResponse, nt as UniquSelect, o as BaseDbAdapter, p as AggregateQuery, q as TSyncColumnResult, r as resolveDesignType, s as TableMetadata, t as AtscriptDbReadable, tt as WithRelation, u as AggregateControls, v as FieldOpsFor, w as TColumnDiff, x as OwnPropsOf, y as FilterExpr, z as TDbUpdateResult } from "./db-readable-
|
|
1
|
+
import { $ as Uniquery, A as TDbForeignKey, B as TExistingColumn, C as TCascadeTarget, D as TDbDefaultValue, E as TDbDefaultFn, F as TDbInsertResult, G as TMetadataOverrides, H as TFkLookupResolver, I as TDbReferentialAction, J as TTableOptionDiff, K as TSearchIndexInfo, L as TDbRelation, M as TDbIndexField, N as TDbIndexType, O as TDbDeleteResult, P as TDbInsertManyResult, Q as TypedWithRelation, R as TDbStorageType, S as TCascadeResolver, T as TDbCollation, U as TFkLookupTarget, V as TExistingTableOption, W as TIdDescriptor, X as TValueFormatterPair, Y as TTableResolver, Z as TWriteTableResolver, _ as DbQuery, a as FieldMappingStrategy, b as NavPropsOf, c as NoopLogger, d as AggregateExpr, et as UniqueryControls, f as AggregateFn, g as DbControls, h as AtscriptDbWritable, i as DocumentFieldMapper, j as TDbIndex, k as TDbFieldMeta, l as TGenericLogger, m as AggregateResult, n as DbResponse, nt as UniquSelect, o as BaseDbAdapter, p as AggregateQuery, q as TSyncColumnResult, r as resolveDesignType, s as TableMetadata, t as AtscriptDbReadable, tt as WithRelation, u as AggregateControls, v as FieldOpsFor, w as TColumnDiff, x as OwnPropsOf, y as FilterExpr, z as TDbUpdateResult } from "./db-readable-C3C-qPcP.cjs";
|
|
2
2
|
import { d as getDbFieldOp, f as isDbFieldOp, l as TDbFieldOp, p as separateFieldOps, u as TFieldOps } from "./ops-DXJ4Zw0P.cjs";
|
|
3
|
-
import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-
|
|
4
|
-
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-
|
|
3
|
+
import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-Dgf-CphX.cjs";
|
|
4
|
+
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-Cz4QoDWg.cjs";
|
|
5
5
|
import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
6
6
|
import { TAtscriptAnnotatedType, TAtscriptTypeArray } from "@atscript/typescript/utils";
|
|
7
7
|
|
|
@@ -16,6 +16,11 @@ declare class RelationalFieldMapper extends FieldMappingStrategy {
|
|
|
16
16
|
reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
|
|
17
17
|
translateQuery(query: Uniquery$1, meta: TableMetadata): DbQuery;
|
|
18
18
|
translateAggregateQuery(query: AggregateQuery$1, meta: TableMetadata): DbQuery;
|
|
19
|
+
/**
|
|
20
|
+
* Overrides the base `translateFilter` to use `leafByLogical` for key resolution
|
|
21
|
+
* (handles flattened nested paths like `contact.email` → `contact__email`).
|
|
22
|
+
*/
|
|
23
|
+
translateFilter(filter: FilterExpr$1, meta: TableMetadata): FilterExpr$1;
|
|
19
24
|
/**
|
|
20
25
|
* Translates filter with key renaming from logical to physical names.
|
|
21
26
|
* Used by the relational query path where field paths must be mapped
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as Uniquery, A as TDbForeignKey, B as TExistingColumn, C as TCascadeTarget, D as TDbDefaultValue, E as TDbDefaultFn, F as TDbInsertResult, G as TMetadataOverrides, H as TFkLookupResolver, I as TDbReferentialAction, J as TTableOptionDiff, K as TSearchIndexInfo, L as TDbRelation, M as TDbIndexField, N as TDbIndexType, O as TDbDeleteResult, P as TDbInsertManyResult, Q as TypedWithRelation, R as TDbStorageType, S as TCascadeResolver, T as TDbCollation, U as TFkLookupTarget, V as TExistingTableOption, W as TIdDescriptor, X as TValueFormatterPair, Y as TTableResolver, Z as TWriteTableResolver, _ as DbQuery, a as FieldMappingStrategy, b as NavPropsOf, c as NoopLogger, d as AggregateExpr, et as UniqueryControls, f as AggregateFn, g as DbControls, h as AtscriptDbWritable, i as DocumentFieldMapper, j as TDbIndex, k as TDbFieldMeta, l as TGenericLogger, m as AggregateResult, n as DbResponse, nt as UniquSelect, o as BaseDbAdapter, p as AggregateQuery, q as TSyncColumnResult, r as resolveDesignType, s as TableMetadata, t as AtscriptDbReadable, tt as WithRelation, u as AggregateControls, v as FieldOpsFor, w as TColumnDiff, x as OwnPropsOf, y as FilterExpr, z as TDbUpdateResult } from "./db-readable-
|
|
1
|
+
import { $ as Uniquery, A as TDbForeignKey, B as TExistingColumn, C as TCascadeTarget, D as TDbDefaultValue, E as TDbDefaultFn, F as TDbInsertResult, G as TMetadataOverrides, H as TFkLookupResolver, I as TDbReferentialAction, J as TTableOptionDiff, K as TSearchIndexInfo, L as TDbRelation, M as TDbIndexField, N as TDbIndexType, O as TDbDeleteResult, P as TDbInsertManyResult, Q as TypedWithRelation, R as TDbStorageType, S as TCascadeResolver, T as TDbCollation, U as TFkLookupTarget, V as TExistingTableOption, W as TIdDescriptor, X as TValueFormatterPair, Y as TTableResolver, Z as TWriteTableResolver, _ as DbQuery, a as FieldMappingStrategy, b as NavPropsOf, c as NoopLogger, d as AggregateExpr, et as UniqueryControls, f as AggregateFn, g as DbControls, h as AtscriptDbWritable, i as DocumentFieldMapper, j as TDbIndex, k as TDbFieldMeta, l as TGenericLogger, m as AggregateResult, n as DbResponse, nt as UniquSelect, o as BaseDbAdapter, p as AggregateQuery, q as TSyncColumnResult, r as resolveDesignType, s as TableMetadata, t as AtscriptDbReadable, tt as WithRelation, u as AggregateControls, v as FieldOpsFor, w as TColumnDiff, x as OwnPropsOf, y as FilterExpr, z as TDbUpdateResult } from "./db-readable-Cc868K54.mjs";
|
|
2
2
|
import { d as getDbFieldOp, f as isDbFieldOp, l as TDbFieldOp, p as separateFieldOps, u as TFieldOps } from "./ops-BdRAFLKY.mjs";
|
|
3
|
-
import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-
|
|
4
|
-
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-
|
|
3
|
+
import { a as AtscriptQueryComparison, c as AtscriptRef, d as translateQueryTree, f as AtscriptDbTable, i as TViewColumnMapping, l as TViewJoin, m as NativeIntegrity, n as TAdapterFactory, o as AtscriptQueryFieldRef, p as IntegrityStrategy, r as AtscriptDbView, s as AtscriptQueryNode, t as DbSpace, u as TViewPlan } from "./db-space-crCFv3DF.mjs";
|
|
4
|
+
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-BLMVdi9z.mjs";
|
|
5
5
|
import { TAtscriptAnnotatedType, TAtscriptTypeArray } from "@atscript/typescript/utils";
|
|
6
6
|
import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
7
7
|
|
|
@@ -16,6 +16,11 @@ declare class RelationalFieldMapper extends FieldMappingStrategy {
|
|
|
16
16
|
reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
|
|
17
17
|
translateQuery(query: Uniquery$1, meta: TableMetadata): DbQuery;
|
|
18
18
|
translateAggregateQuery(query: AggregateQuery$1, meta: TableMetadata): DbQuery;
|
|
19
|
+
/**
|
|
20
|
+
* Overrides the base `translateFilter` to use `leafByLogical` for key resolution
|
|
21
|
+
* (handles flattened nested paths like `contact.email` → `contact__email`).
|
|
22
|
+
*/
|
|
23
|
+
translateFilter(filter: FilterExpr$1, meta: TableMetadata): FilterExpr$1;
|
|
19
24
|
/**
|
|
20
25
|
* Translates filter with key renaming from logical to physical names.
|
|
21
26
|
* Used by the relational query path where field paths must be mapped
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as DbError } from "./nested-writer-
|
|
2
|
-
import { _ as NoopLogger, a as getKeyProps, c as IntegrityStrategy, d as resolveDesignType, f as RelationalFieldMapper, g as TableMetadata, h as UniquSelect, i as createDbValidatorPlugin, l as NativeIntegrity, m as FieldMappingStrategy, n as AtscriptDbTable, o as ApplicationIntegrity, p as DocumentFieldMapper, r as decomposePatch, s as BaseDbAdapter, t as AtscriptDbView, u as AtscriptDbReadable } from "./db-view-
|
|
1
|
+
import { h as DbError } from "./nested-writer-CNDyhg2L.mjs";
|
|
2
|
+
import { _ as NoopLogger, a as getKeyProps, c as IntegrityStrategy, d as resolveDesignType, f as RelationalFieldMapper, g as TableMetadata, h as UniquSelect, i as createDbValidatorPlugin, l as NativeIntegrity, m as FieldMappingStrategy, n as AtscriptDbTable, o as ApplicationIntegrity, p as DocumentFieldMapper, r as decomposePatch, s as BaseDbAdapter, t as AtscriptDbView, u as AtscriptDbReadable } from "./db-view-DSK76uc9.mjs";
|
|
3
3
|
import { getDbFieldOp, isDbFieldOp, separateFieldOps } from "./ops.mjs";
|
|
4
4
|
import { computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
5
5
|
//#region src/table/db-space.ts
|
|
@@ -316,7 +316,7 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
316
316
|
const patch = { ...nested };
|
|
317
317
|
let fkValue = fk.localFields.length === 1 ? item[fk.localFields[0]] : void 0;
|
|
318
318
|
if (fkValue === void 0) {
|
|
319
|
-
const pkFilter = host.
|
|
319
|
+
const pkFilter = host._extractRecordFilter(item);
|
|
320
320
|
const current = await host.findOne({
|
|
321
321
|
filter: pkFilter,
|
|
322
322
|
controls: {}
|
|
@@ -316,7 +316,7 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
316
316
|
const patch = { ...nested };
|
|
317
317
|
let fkValue = fk.localFields.length === 1 ? item[fk.localFields[0]] : void 0;
|
|
318
318
|
if (fkValue === void 0) {
|
|
319
|
-
const pkFilter = host.
|
|
319
|
+
const pkFilter = host._extractRecordFilter(item);
|
|
320
320
|
const current = await host.findOne({
|
|
321
321
|
filter: pkFilter,
|
|
322
322
|
controls: {}
|
package/dist/rel.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_relation_loader = require("./relation-loader-CRC5LcqM.cjs");
|
|
3
|
-
const require_nested_writer = require("./nested-writer-
|
|
3
|
+
const require_nested_writer = require("./nested-writer-BIQ6EfaR.cjs");
|
|
4
4
|
const require_relation_helpers = require("./relation-helpers-BYvsE1tR.cjs");
|
|
5
5
|
exports.batchInsertNestedFrom = require_nested_writer.batchInsertNestedFrom;
|
|
6
6
|
exports.batchInsertNestedTo = require_nested_writer.batchInsertNestedTo;
|
package/dist/rel.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as TDbForeignKey, L as TDbRelation, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata } from "./db-readable-
|
|
2
|
-
import { t as DbValidationContext } from "./db-validator-plugin-
|
|
1
|
+
import { A as TDbForeignKey, L as TDbRelation, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata } from "./db-readable-C3C-qPcP.cjs";
|
|
2
|
+
import { t as DbValidationContext } from "./db-validator-plugin-Cz4QoDWg.cjs";
|
|
3
3
|
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
4
4
|
import { Validator } from "@atscript/typescript/utils";
|
|
5
5
|
|
|
@@ -55,7 +55,7 @@ interface TNestedWriterHost {
|
|
|
55
55
|
_findRemoteFK(targetTable: {
|
|
56
56
|
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
57
57
|
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
58
|
-
|
|
58
|
+
_extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
59
59
|
findOne(query: {
|
|
60
60
|
filter: FilterExpr;
|
|
61
61
|
controls: Record<string, never>;
|
package/dist/rel.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as TDbForeignKey, L as TDbRelation, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata } from "./db-readable-
|
|
2
|
-
import { t as DbValidationContext } from "./db-validator-plugin-
|
|
1
|
+
import { A as TDbForeignKey, L as TDbRelation, Y as TTableResolver, Z as TWriteTableResolver, l as TGenericLogger, o as BaseDbAdapter, s as TableMetadata } from "./db-readable-Cc868K54.mjs";
|
|
2
|
+
import { t as DbValidationContext } from "./db-validator-plugin-BLMVdi9z.mjs";
|
|
3
3
|
import { Validator } from "@atscript/typescript/utils";
|
|
4
4
|
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
5
5
|
|
|
@@ -55,7 +55,7 @@ interface TNestedWriterHost {
|
|
|
55
55
|
_findRemoteFK(targetTable: {
|
|
56
56
|
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
57
57
|
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
58
|
-
|
|
58
|
+
_extractRecordFilter(payload: Record<string, unknown>): FilterExpr;
|
|
59
59
|
findOne(query: {
|
|
60
60
|
filter: FilterExpr;
|
|
61
61
|
controls: Record<string, never>;
|
package/dist/rel.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { t as loadRelationsImpl } from "./relation-loader-BEOTXNcq.mjs";
|
|
2
|
-
import { a as batchPatchNestedTo, c as batchReplaceNestedTo, d as preValidateNestedFrom, f as validateBatch, i as batchPatchNestedFrom, l as batchReplaceNestedVia, n as batchInsertNestedTo, o as batchPatchNestedVia, r as batchInsertNestedVia, s as batchReplaceNestedFrom, t as batchInsertNestedFrom, u as checkDepthOverflow } from "./nested-writer-
|
|
2
|
+
import { a as batchPatchNestedTo, c as batchReplaceNestedTo, d as preValidateNestedFrom, f as validateBatch, i as batchPatchNestedFrom, l as batchReplaceNestedVia, n as batchInsertNestedTo, o as batchPatchNestedVia, r as batchInsertNestedVia, s as batchReplaceNestedFrom, t as batchInsertNestedFrom, u as checkDepthOverflow } from "./nested-writer-CNDyhg2L.mjs";
|
|
3
3
|
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-CLasawQq.mjs";
|
|
4
4
|
export { batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
package/dist/sync.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
require("./nested-writer-
|
|
3
|
-
const require_db_view = require("./db-view-
|
|
2
|
+
require("./nested-writer-BIQ6EfaR.cjs");
|
|
3
|
+
const require_db_view = require("./db-view-CcUjETIF.cjs");
|
|
4
4
|
//#region src/schema/schema-hash.ts
|
|
5
5
|
/** Extracts sorted field snapshots from a readable's field descriptors. */
|
|
6
6
|
function extractFieldSnapshots(fields, typeMapper) {
|
package/dist/sync.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as TDbForeignKey, B as TExistingColumn, D as TDbDefaultValue, J as TTableOptionDiff, R as TDbStorageType, V as TExistingTableOption, k as TDbFieldMeta, l as TGenericLogger, t as AtscriptDbReadable, w as TColumnDiff } from "./db-readable-
|
|
2
|
-
import { r as AtscriptDbView, t as DbSpace } from "./db-space-
|
|
1
|
+
import { A as TDbForeignKey, B as TExistingColumn, D as TDbDefaultValue, J as TTableOptionDiff, R as TDbStorageType, V as TExistingTableOption, k as TDbFieldMeta, l as TGenericLogger, t as AtscriptDbReadable, w as TColumnDiff } from "./db-readable-C3C-qPcP.cjs";
|
|
2
|
+
import { r as AtscriptDbView, t as DbSpace } from "./db-space-Dgf-CphX.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 { A as TDbForeignKey, B as TExistingColumn, D as TDbDefaultValue, J as TTableOptionDiff, R as TDbStorageType, V as TExistingTableOption, k as TDbFieldMeta, l as TGenericLogger, t as AtscriptDbReadable, w as TColumnDiff } from "./db-readable-
|
|
2
|
-
import { r as AtscriptDbView, t as DbSpace } from "./db-space-
|
|
1
|
+
import { A as TDbForeignKey, B as TExistingColumn, D as TDbDefaultValue, J as TTableOptionDiff, R as TDbStorageType, V as TExistingTableOption, k as TDbFieldMeta, l as TGenericLogger, t as AtscriptDbReadable, w as TColumnDiff } from "./db-readable-Cc868K54.mjs";
|
|
2
|
+
import { r as AtscriptDbView, t as DbSpace } from "./db-space-crCFv3DF.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,4 +1,4 @@
|
|
|
1
|
-
import { _ as NoopLogger } from "./db-view-
|
|
1
|
+
import { _ as NoopLogger } from "./db-view-DSK76uc9.mjs";
|
|
2
2
|
//#region src/schema/schema-hash.ts
|
|
3
3
|
/** Extracts sorted field snapshots from a readable's field descriptors. */
|
|
4
4
|
function extractFieldSnapshots(fields, typeMapper) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "Database adapter utilities for atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -62,14 +62,14 @@
|
|
|
62
62
|
"access": "public"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@atscript/core": "^0.1.
|
|
66
|
-
"@atscript/typescript": "^0.1.
|
|
65
|
+
"@atscript/core": "^0.1.41",
|
|
66
|
+
"@atscript/typescript": "^0.1.41",
|
|
67
67
|
"@uniqu/core": "^0.1.2",
|
|
68
|
-
"unplugin-atscript": "^0.1.
|
|
68
|
+
"unplugin-atscript": "^0.1.41"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"@atscript/core": "^0.1.
|
|
72
|
-
"@atscript/typescript": "^0.1.
|
|
71
|
+
"@atscript/core": "^0.1.41",
|
|
72
|
+
"@atscript/typescript": "^0.1.41",
|
|
73
73
|
"@uniqu/core": "^0.1.2"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|