@atscript/db 0.1.39 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -18
- package/dist/agg.cjs +8 -3
- package/dist/agg.d.cts +7 -0
- package/dist/agg.d.mts +7 -0
- package/dist/agg.mjs +7 -3
- package/dist/control-DRgryKeg.cjs +14 -0
- package/dist/{control_as-bjmwe24C.mjs → control-IANbnfjG.mjs} +6 -18
- package/dist/db-readable-BQQzfguJ.d.cts +1249 -0
- package/dist/db-readable-Bbr4CjMb.d.mts +1249 -0
- package/dist/db-space-BUrQ5BFm.d.mts +309 -0
- package/dist/db-space-Vxpcnyt5.d.cts +309 -0
- package/dist/db-validator-plugin-07kDiis2.d.cts +22 -0
- package/dist/db-validator-plugin-CiqsHTI_.d.mts +22 -0
- package/dist/db-view-BntnAmXO.cjs +3071 -0
- package/dist/db-view-ZsoN91-q.mjs +2970 -0
- package/dist/index.cjs +95 -2801
- package/dist/index.d.cts +137 -0
- package/dist/index.d.mts +137 -0
- package/dist/index.mjs +55 -2761
- package/dist/{nested-writer-BkqL7cp3.cjs → nested-writer-BDXsDMPP.cjs} +196 -150
- package/dist/{nested-writer-NEN51mnR.mjs → nested-writer-Dmm1gbZV.mjs} +118 -70
- package/dist/ops-BdRAFLKY.d.mts +67 -0
- package/dist/ops-DXJ4Zw0P.d.cts +67 -0
- package/dist/ops.cjs +123 -0
- package/dist/ops.d.cts +2 -0
- package/dist/ops.d.mts +2 -0
- package/dist/ops.mjs +112 -0
- package/dist/plugin.cjs +90 -109
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.mts +6 -0
- package/dist/plugin.mjs +29 -49
- package/dist/rel.cjs +20 -20
- package/dist/rel.d.cts +119 -0
- package/dist/rel.d.mts +119 -0
- package/dist/rel.mjs +4 -5
- package/dist/{relation-helpers-guFL_oRf.cjs → relation-helpers-BYvsE1tR.cjs} +26 -22
- package/dist/{relation-helpers-DyBIlQnB.mjs → relation-helpers-CLasawQq.mjs} +11 -6
- package/dist/{relation-loader-Dv7qXYq7.mjs → relation-loader-BEOTXNcq.mjs} +63 -43
- package/dist/{relation-loader-CpnDRf9k.cjs → relation-loader-CRC5LcqM.cjs} +74 -49
- package/dist/shared.cjs +13 -13
- package/dist/{shared.d.ts → shared.d.cts} +14 -13
- package/dist/shared.d.mts +71 -0
- package/dist/shared.mjs +2 -3
- package/dist/sync.cjs +300 -252
- package/dist/sync.d.cts +369 -0
- package/dist/sync.d.mts +369 -0
- package/dist/sync.mjs +284 -233
- package/dist/{validation-utils-DEoCMmEb.cjs → validation-utils-DVJDijnB.cjs} +141 -109
- package/dist/{validation-utils-DhR_mtKa.mjs → validation-utils-DhjIjP1-.mjs} +71 -37
- package/package.json +30 -29
- package/LICENSE +0 -21
- package/dist/agg-BJFJ3dFQ.mjs +0 -8
- package/dist/agg-DnUWAOK8.cjs +0 -14
- package/dist/agg.d.ts +0 -13
- package/dist/chunk-CrpGerW8.cjs +0 -31
- package/dist/control_as-BFPERAF_.cjs +0 -28
- package/dist/index.d.ts +0 -1706
- package/dist/logger-B7oxCfLQ.mjs +0 -12
- package/dist/logger-Dt2v_-wb.cjs +0 -18
- package/dist/plugin.d.ts +0 -5
- package/dist/rel.d.ts +0 -1305
- package/dist/relation-loader-D4mTw6yH.cjs +0 -4
- package/dist/relation-loader-Ggy1ujwR.mjs +0 -4
- package/dist/sync.d.ts +0 -1878
package/dist/plugin.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as getAnnotationAlias, c as getParentStruct, d as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-DhjIjP1-.mjs";
|
|
2
2
|
import { AnnotationSpec, isArray, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
|
|
3
|
-
|
|
4
|
-
//#region packages/db/src/plugin/annotations/agg.ts
|
|
3
|
+
//#region src/plugin/annotations/agg.ts
|
|
5
4
|
const dbAggAnnotations = { agg: {
|
|
6
5
|
sum: new AnnotationSpec({
|
|
7
6
|
description: "Declares a view field as SUM of a source column.",
|
|
@@ -59,9 +58,8 @@ const dbAggAnnotations = { agg: {
|
|
|
59
58
|
}
|
|
60
59
|
})
|
|
61
60
|
} };
|
|
62
|
-
|
|
63
61
|
//#endregion
|
|
64
|
-
//#region
|
|
62
|
+
//#region src/plugin/annotations/column.ts
|
|
65
63
|
const dbColumnAnnotations = {
|
|
66
64
|
patch: { strategy: new AnnotationSpec({
|
|
67
65
|
description: "Defines the **patching strategy** for updating nested objects.\n\n- **\"replace\"** → The field or object will be **fully replaced**.\n- **\"merge\"** → The field or object will be **merged recursively** (applies only to objects, not arrays).\n\n**Example:**\n```atscript\n@db.patch.strategy \"merge\"\nsettings: {\n notifications: boolean\n preferences: {\n theme: string\n }\n}\n```\n",
|
|
@@ -198,8 +196,7 @@ const dbColumnAnnotations = {
|
|
|
198
196
|
nodeType: ["prop"],
|
|
199
197
|
validate(token, _args, doc) {
|
|
200
198
|
const errors = [];
|
|
201
|
-
const
|
|
202
|
-
const definition = field.getDefinition();
|
|
199
|
+
const definition = token.parentNode.getDefinition();
|
|
203
200
|
if (definition && isRef(definition)) {
|
|
204
201
|
const unwound = doc.unwindType(definition.id, definition.chain);
|
|
205
202
|
if (unwound && isPrimitive(unwound.def)) errors.push({
|
|
@@ -214,10 +211,9 @@ const dbColumnAnnotations = {
|
|
|
214
211
|
ignore: new AnnotationSpec({
|
|
215
212
|
description: "Excludes a field from the database schema. The field exists in the Atscript type but has no column in the DB.\n\n**Example:**\n```atscript\n@db.ignore\ndisplayName: string\n```\n",
|
|
216
213
|
nodeType: ["prop"],
|
|
217
|
-
validate(token,
|
|
214
|
+
validate(token, _args, _doc) {
|
|
218
215
|
const errors = [];
|
|
219
|
-
|
|
220
|
-
if (field.countAnnotations("meta.id") > 0) errors.push({
|
|
216
|
+
if (token.parentNode.countAnnotations("meta.id") > 0) errors.push({
|
|
221
217
|
message: `@db.ignore cannot coexist with @meta.id — a field cannot be both a primary key and excluded from the database`,
|
|
222
218
|
severity: 1,
|
|
223
219
|
range: token.range
|
|
@@ -226,9 +222,8 @@ const dbColumnAnnotations = {
|
|
|
226
222
|
}
|
|
227
223
|
})
|
|
228
224
|
};
|
|
229
|
-
|
|
230
225
|
//#endregion
|
|
231
|
-
//#region
|
|
226
|
+
//#region src/plugin/annotations/index-ann.ts
|
|
232
227
|
const dbIndexAnnotations = { index: {
|
|
233
228
|
plain: new AnnotationSpec({
|
|
234
229
|
description: "Standard (non-unique) index for query performance. Fields sharing the same index name form a composite index.\n\n**Example:**\n```atscript\n@db.index.plain \"idx_timeline\", \"desc\"\ncreatedAt: number.timestamp\n```\n",
|
|
@@ -278,9 +273,8 @@ const dbIndexAnnotations = { index: {
|
|
|
278
273
|
}]
|
|
279
274
|
})
|
|
280
275
|
} };
|
|
281
|
-
|
|
282
276
|
//#endregion
|
|
283
|
-
//#region
|
|
277
|
+
//#region src/plugin/annotations/rel.ts
|
|
284
278
|
const dbRelAnnotations = { rel: {
|
|
285
279
|
FK: new AnnotationSpec({
|
|
286
280
|
description: "Declares a foreign key constraint on this field. The field must use a chain reference type (e.g., `User.id`) to specify the FK target.\n\n**Example:**\n```atscript\n@db.rel.FK\nauthorId: User.id\n\n// With alias (required when multiple FKs point to the same type)\n@db.rel.FK \"author\"\nauthorId: User.id\n```\n",
|
|
@@ -401,7 +395,7 @@ const dbRelAnnotations = { rel: {
|
|
|
401
395
|
const unwound = doc.unwindType(targetTypeName);
|
|
402
396
|
if (unwound) {
|
|
403
397
|
const targetDef = unwound.def;
|
|
404
|
-
const targetNode = isInterface(targetDef) ? targetDef :
|
|
398
|
+
const targetNode = isInterface(targetDef) ? targetDef : void 0;
|
|
405
399
|
if (!targetNode || targetNode.countAnnotations("db.table") === 0) errors.push({
|
|
406
400
|
message: `@db.rel.to target '${targetTypeName}' is not a @db.table entity`,
|
|
407
401
|
severity: 1,
|
|
@@ -421,9 +415,8 @@ const dbRelAnnotations = { rel: {
|
|
|
421
415
|
if (name === fieldName) continue;
|
|
422
416
|
if (prop.countAnnotations("db.rel.to") === 0) continue;
|
|
423
417
|
const propAlias = getAnnotationAlias(prop, "db.rel.to");
|
|
424
|
-
if ((alias ||
|
|
425
|
-
|
|
426
|
-
if (otherTarget === targetTypeName) {
|
|
418
|
+
if ((alias || void 0) === (propAlias || void 0)) {
|
|
419
|
+
if (getNavTargetTypeName(prop) === targetTypeName) {
|
|
427
420
|
errors.push({
|
|
428
421
|
message: `Duplicate @db.rel.to '${alias || targetTypeName}' — only one forward navigational property per alias`,
|
|
429
422
|
severity: 1,
|
|
@@ -434,8 +427,7 @@ const dbRelAnnotations = { rel: {
|
|
|
434
427
|
}
|
|
435
428
|
}
|
|
436
429
|
if (alias) {
|
|
437
|
-
|
|
438
|
-
if (matches.length === 0) errors.push({
|
|
430
|
+
if (findFKFieldsPointingTo(doc, struct, targetTypeName, alias).length === 0) errors.push({
|
|
439
431
|
message: `No @db.rel.FK '${alias}' found on this interface`,
|
|
440
432
|
severity: 1,
|
|
441
433
|
range: token.range
|
|
@@ -447,7 +439,7 @@ const dbRelAnnotations = { rel: {
|
|
|
447
439
|
severity: 1,
|
|
448
440
|
range: token.range
|
|
449
441
|
});
|
|
450
|
-
else if (matches.length > 1) errors.push({
|
|
442
|
+
else if (matches.length > 1) errors.push({
|
|
451
443
|
message: `Multiple @db.rel.FK fields point to '${targetTypeName}' — add alias to disambiguate`,
|
|
452
444
|
severity: 1,
|
|
453
445
|
range: token.range
|
|
@@ -502,9 +494,8 @@ else if (matches.length > 1) errors.push({
|
|
|
502
494
|
if (name === fieldName) continue;
|
|
503
495
|
if (prop.countAnnotations("db.rel.from") === 0) continue;
|
|
504
496
|
const propAlias = getAnnotationAlias(prop, "db.rel.from");
|
|
505
|
-
if ((alias ||
|
|
506
|
-
|
|
507
|
-
if (otherTarget === targetTypeName) {
|
|
497
|
+
if ((alias || void 0) === (propAlias || void 0)) {
|
|
498
|
+
if (getNavTargetTypeName(prop) === targetTypeName) {
|
|
508
499
|
errors.push({
|
|
509
500
|
message: `Duplicate @db.rel.from '${alias || targetTypeName}' — only one inverse navigational property per alias`,
|
|
510
501
|
severity: 1,
|
|
@@ -529,15 +520,13 @@ else if (matches.length > 1) errors.push({
|
|
|
529
520
|
severity: 1,
|
|
530
521
|
range: token.range
|
|
531
522
|
});
|
|
532
|
-
else if (matches.length > 1) errors.push({
|
|
523
|
+
else if (matches.length > 1) errors.push({
|
|
533
524
|
message: `'${targetTypeName}' has multiple @db.rel.FK fields pointing to '${thisTypeName}' — add alias`,
|
|
534
525
|
severity: 1,
|
|
535
526
|
range: token.range
|
|
536
527
|
});
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const fkProp = matches[0].prop;
|
|
540
|
-
if (fkProp.countAnnotations("db.index.unique") === 0) errors.push({
|
|
528
|
+
if (!isArray(field.getDefinition()) && matches.length === 1) {
|
|
529
|
+
if (matches[0].prop.countAnnotations("db.index.unique") === 0) errors.push({
|
|
541
530
|
message: `@db.rel.from '${field.id}' has singular type '${targetTypeName}' (1:1) but the FK on '${targetTypeName}' is not @db.index.unique — did you mean '${targetTypeName}[]' (1:N)?`,
|
|
542
531
|
severity: 2,
|
|
543
532
|
range: token.range
|
|
@@ -564,8 +553,7 @@ else if (matches.length > 1) errors.push({
|
|
|
564
553
|
severity: 1,
|
|
565
554
|
range: token.range
|
|
566
555
|
});
|
|
567
|
-
|
|
568
|
-
if (!isArray(definition)) errors.push({
|
|
556
|
+
if (!isArray(field.getDefinition())) errors.push({
|
|
569
557
|
message: "@db.rel.via requires an array type (e.g. Tag[])",
|
|
570
558
|
severity: 1,
|
|
571
559
|
range: token.range
|
|
@@ -587,7 +575,7 @@ else if (matches.length > 1) errors.push({
|
|
|
587
575
|
severity: 1,
|
|
588
576
|
range: args[0].range
|
|
589
577
|
});
|
|
590
|
-
else if (fksToThis.length > 1) errors.push({
|
|
578
|
+
else if (fksToThis.length > 1) errors.push({
|
|
591
579
|
message: `Junction '${junctionName}' has multiple @db.rel.FK pointing to '${thisTypeName}' — not supported`,
|
|
592
580
|
severity: 1,
|
|
593
581
|
range: args[0].range
|
|
@@ -599,7 +587,7 @@ else if (fksToThis.length > 1) errors.push({
|
|
|
599
587
|
severity: 1,
|
|
600
588
|
range: args[0].range
|
|
601
589
|
});
|
|
602
|
-
else if (fksToTarget.length > 1) errors.push({
|
|
590
|
+
else if (fksToTarget.length > 1) errors.push({
|
|
603
591
|
message: `Junction '${junctionName}' has multiple @db.rel.FK pointing to '${targetTypeName}' — not supported`,
|
|
604
592
|
severity: 1,
|
|
605
593
|
range: args[0].range
|
|
@@ -643,9 +631,8 @@ else if (fksToTarget.length > 1) errors.push({
|
|
|
643
631
|
}
|
|
644
632
|
})
|
|
645
633
|
} };
|
|
646
|
-
|
|
647
634
|
//#endregion
|
|
648
|
-
//#region
|
|
635
|
+
//#region src/plugin/annotations/search.ts
|
|
649
636
|
const dbSearchAnnotations = { search: {
|
|
650
637
|
vector: {
|
|
651
638
|
$self: new AnnotationSpec({
|
|
@@ -710,9 +697,8 @@ const dbSearchAnnotations = { search: {
|
|
|
710
697
|
}
|
|
711
698
|
})
|
|
712
699
|
} };
|
|
713
|
-
|
|
714
700
|
//#endregion
|
|
715
|
-
//#region
|
|
701
|
+
//#region src/plugin/annotations/table.ts
|
|
716
702
|
const dbTableAnnotations = {
|
|
717
703
|
table: {
|
|
718
704
|
$self: new AnnotationSpec({
|
|
@@ -745,8 +731,7 @@ const dbTableAnnotations = {
|
|
|
745
731
|
},
|
|
746
732
|
validate(token, _args, _doc) {
|
|
747
733
|
const errors = [];
|
|
748
|
-
|
|
749
|
-
if (owner.countAnnotations("db.table") === 0) errors.push({
|
|
734
|
+
if (token.parentNode.countAnnotations("db.table") === 0) errors.push({
|
|
750
735
|
message: "@db.table.renamed requires @db.table on the same interface",
|
|
751
736
|
severity: 1,
|
|
752
737
|
range: token.range
|
|
@@ -775,9 +760,8 @@ const dbTableAnnotations = {
|
|
|
775
760
|
}
|
|
776
761
|
}) }
|
|
777
762
|
};
|
|
778
|
-
|
|
779
763
|
//#endregion
|
|
780
|
-
//#region
|
|
764
|
+
//#region src/plugin/annotations/view.ts
|
|
781
765
|
const dbViewAnnotations = { view: {
|
|
782
766
|
$self: new AnnotationSpec({
|
|
783
767
|
description: "Marks an interface as a **database view**. Optionally takes a view name argument.\n\n**Example:**\n```atscript\n@db.view \"active_premium_users\"\n@db.view.for User\nexport interface ActivePremiumUser { ... }\n```\n",
|
|
@@ -790,8 +774,7 @@ const dbViewAnnotations = { view: {
|
|
|
790
774
|
},
|
|
791
775
|
validate(token, _args, _doc) {
|
|
792
776
|
const errors = [];
|
|
793
|
-
|
|
794
|
-
if (owner.countAnnotations("db.table") > 0) errors.push({
|
|
777
|
+
if (token.parentNode.countAnnotations("db.table") > 0) errors.push({
|
|
795
778
|
message: "An interface cannot be both a @db.table and a @db.view",
|
|
796
779
|
severity: 1,
|
|
797
780
|
range: token.range
|
|
@@ -809,8 +792,7 @@ const dbViewAnnotations = { view: {
|
|
|
809
792
|
},
|
|
810
793
|
validate(token, args, doc) {
|
|
811
794
|
const errors = [];
|
|
812
|
-
|
|
813
|
-
if (owner.countAnnotations("db.table") > 0) errors.push({
|
|
795
|
+
if (token.parentNode.countAnnotations("db.table") > 0) errors.push({
|
|
814
796
|
message: "An interface cannot be both a @db.table and a @db.view",
|
|
815
797
|
severity: 1,
|
|
816
798
|
range: token.range
|
|
@@ -952,9 +934,8 @@ const dbViewAnnotations = { view: {
|
|
|
952
934
|
}
|
|
953
935
|
})
|
|
954
936
|
} };
|
|
955
|
-
|
|
956
937
|
//#endregion
|
|
957
|
-
//#region
|
|
938
|
+
//#region src/plugin/index.ts
|
|
958
939
|
const dbPlugin = () => ({
|
|
959
940
|
name: "db",
|
|
960
941
|
config() {
|
|
@@ -984,6 +965,5 @@ const dbPlugin = () => ({
|
|
|
984
965
|
};
|
|
985
966
|
}
|
|
986
967
|
});
|
|
987
|
-
|
|
988
968
|
//#endregion
|
|
989
|
-
export { dbPlugin, dbPlugin as default };
|
|
969
|
+
export { dbPlugin, dbPlugin as default };
|
package/dist/rel.cjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
exports.batchInsertNestedFrom = require_nested_writer.batchInsertNestedFrom
|
|
6
|
-
exports.batchInsertNestedTo = require_nested_writer.batchInsertNestedTo
|
|
7
|
-
exports.batchInsertNestedVia = require_nested_writer.batchInsertNestedVia
|
|
8
|
-
exports.batchPatchNestedFrom = require_nested_writer.batchPatchNestedFrom
|
|
9
|
-
exports.batchPatchNestedTo = require_nested_writer.batchPatchNestedTo
|
|
10
|
-
exports.batchPatchNestedVia = require_nested_writer.batchPatchNestedVia
|
|
11
|
-
exports.batchReplaceNestedFrom = require_nested_writer.batchReplaceNestedFrom
|
|
12
|
-
exports.batchReplaceNestedTo = require_nested_writer.batchReplaceNestedTo
|
|
13
|
-
exports.batchReplaceNestedVia = require_nested_writer.batchReplaceNestedVia
|
|
14
|
-
exports.checkDepthOverflow = require_nested_writer.checkDepthOverflow
|
|
15
|
-
exports.findFKForRelation = require_relation_helpers.findFKForRelation
|
|
16
|
-
exports.findRemoteFK = require_relation_helpers.findRemoteFK
|
|
17
|
-
exports.loadRelationsImpl = require_relation_loader.loadRelationsImpl
|
|
18
|
-
exports.preValidateNestedFrom = require_nested_writer.preValidateNestedFrom
|
|
19
|
-
exports.resolveRelationTargetTable = require_relation_helpers.resolveRelationTargetTable
|
|
20
|
-
exports.validateBatch = require_nested_writer.validateBatch
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_relation_loader = require("./relation-loader-CRC5LcqM.cjs");
|
|
3
|
+
const require_nested_writer = require("./nested-writer-BDXsDMPP.cjs");
|
|
4
|
+
const require_relation_helpers = require("./relation-helpers-BYvsE1tR.cjs");
|
|
5
|
+
exports.batchInsertNestedFrom = require_nested_writer.batchInsertNestedFrom;
|
|
6
|
+
exports.batchInsertNestedTo = require_nested_writer.batchInsertNestedTo;
|
|
7
|
+
exports.batchInsertNestedVia = require_nested_writer.batchInsertNestedVia;
|
|
8
|
+
exports.batchPatchNestedFrom = require_nested_writer.batchPatchNestedFrom;
|
|
9
|
+
exports.batchPatchNestedTo = require_nested_writer.batchPatchNestedTo;
|
|
10
|
+
exports.batchPatchNestedVia = require_nested_writer.batchPatchNestedVia;
|
|
11
|
+
exports.batchReplaceNestedFrom = require_nested_writer.batchReplaceNestedFrom;
|
|
12
|
+
exports.batchReplaceNestedTo = require_nested_writer.batchReplaceNestedTo;
|
|
13
|
+
exports.batchReplaceNestedVia = require_nested_writer.batchReplaceNestedVia;
|
|
14
|
+
exports.checkDepthOverflow = require_nested_writer.checkDepthOverflow;
|
|
15
|
+
exports.findFKForRelation = require_relation_helpers.findFKForRelation;
|
|
16
|
+
exports.findRemoteFK = require_relation_helpers.findRemoteFK;
|
|
17
|
+
exports.loadRelationsImpl = require_relation_loader.loadRelationsImpl;
|
|
18
|
+
exports.preValidateNestedFrom = require_nested_writer.preValidateNestedFrom;
|
|
19
|
+
exports.resolveRelationTargetTable = require_relation_helpers.resolveRelationTargetTable;
|
|
20
|
+
exports.validateBatch = require_nested_writer.validateBatch;
|
package/dist/rel.d.cts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
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-BQQzfguJ.cjs";
|
|
2
|
+
import { t as DbValidationContext } from "./db-validator-plugin-07kDiis2.cjs";
|
|
3
|
+
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
4
|
+
import { Validator } from "@atscript/typescript/utils";
|
|
5
|
+
|
|
6
|
+
//#region src/rel/relation-loader.d.ts
|
|
7
|
+
/** Host interface for the relation loader — matches AtscriptDbReadable property names. */
|
|
8
|
+
interface TRelationLoaderHost {
|
|
9
|
+
readonly tableName: string;
|
|
10
|
+
readonly _meta: {
|
|
11
|
+
readonly relations: ReadonlyMap<string, TDbRelation>;
|
|
12
|
+
readonly foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
13
|
+
};
|
|
14
|
+
readonly _tableResolver?: TTableResolver;
|
|
15
|
+
readonly adapter: BaseDbAdapter;
|
|
16
|
+
readonly logger: TGenericLogger;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Loads related data for `$with` relations and attaches them to result rows.
|
|
20
|
+
*/
|
|
21
|
+
declare function loadRelationsImpl(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], host: TRelationLoaderHost): Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/rel/relation-helpers.d.ts
|
|
24
|
+
/**
|
|
25
|
+
* Finds the FK entry that connects a `@db.rel.to` relation to its target.
|
|
26
|
+
*/
|
|
27
|
+
declare function findFKForRelation(relation: TDbRelation, foreignKeys: ReadonlyMap<string, TDbForeignKey>): {
|
|
28
|
+
localFields: string[];
|
|
29
|
+
targetFields: string[];
|
|
30
|
+
} | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Finds a FK on a remote table that points back to a given table name.
|
|
33
|
+
*/
|
|
34
|
+
declare function findRemoteFK(targetTable: {
|
|
35
|
+
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
36
|
+
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Resolves the target table name from a relation's target type metadata.
|
|
39
|
+
*/
|
|
40
|
+
declare function resolveRelationTargetTable(relation: TDbRelation): string;
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/rel/nested-writer.d.ts
|
|
43
|
+
/**
|
|
44
|
+
* Properties the nested writer functions need from the table instance.
|
|
45
|
+
* AtscriptDbTable satisfies this structurally — pass `this` with a cast.
|
|
46
|
+
*/
|
|
47
|
+
interface TNestedWriterHost {
|
|
48
|
+
readonly tableName: string;
|
|
49
|
+
readonly _meta: TableMetadata;
|
|
50
|
+
readonly _writeTableResolver?: TWriteTableResolver;
|
|
51
|
+
_findFKForRelation(relation: TDbRelation): {
|
|
52
|
+
localFields: string[];
|
|
53
|
+
targetFields: string[];
|
|
54
|
+
} | undefined;
|
|
55
|
+
_findRemoteFK(targetTable: {
|
|
56
|
+
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
57
|
+
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
58
|
+
_extractPrimaryKeyFilter(payload: Record<string, unknown>): FilterExpr;
|
|
59
|
+
findOne(query: {
|
|
60
|
+
filter: FilterExpr;
|
|
61
|
+
controls: Record<string, never>;
|
|
62
|
+
}): Promise<Record<string, unknown> | null>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Checks if any payload contains navigational data that would be silently
|
|
66
|
+
* dropped because maxDepth is 0.
|
|
67
|
+
*/
|
|
68
|
+
declare function checkDepthOverflow(payloads: Array<Record<string, unknown>>, maxDepth: number, meta: TableMetadata): void;
|
|
69
|
+
/**
|
|
70
|
+
* Validates a batch of items using the given validator and context.
|
|
71
|
+
* Wraps per-item validation errors with array index paths for batch operations.
|
|
72
|
+
*/
|
|
73
|
+
declare function validateBatch(validator: Validator<any, any>, items: Array<Record<string, unknown>>, ctx: DbValidationContext): void;
|
|
74
|
+
/**
|
|
75
|
+
* Pre-validates FROM children (type + FK constraints) before the main insert.
|
|
76
|
+
* Catches errors early before the parent record is committed.
|
|
77
|
+
*/
|
|
78
|
+
declare function preValidateNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Batch-creates TO dependencies before the main insert.
|
|
81
|
+
*/
|
|
82
|
+
declare function batchInsertNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Batch-creates FROM dependents after the main insert.
|
|
85
|
+
*/
|
|
86
|
+
declare function batchInsertNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, parentIds: unknown[], maxDepth: number, depth: number): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Batch-creates VIA (M:N) targets and junction entries after the main insert.
|
|
89
|
+
*/
|
|
90
|
+
declare function batchInsertNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, parentIds: unknown[], maxDepth: number, depth: number): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Batch-replaces TO dependencies before the main replace.
|
|
93
|
+
*/
|
|
94
|
+
declare function batchReplaceNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Batch-replaces FROM dependents after the main replace.
|
|
97
|
+
*/
|
|
98
|
+
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Handles VIA (M:N) relations during replace.
|
|
101
|
+
*/
|
|
102
|
+
declare function batchReplaceNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Batch-patches TO dependencies before the main patch.
|
|
105
|
+
* Reads FK values from DB if not present in the payload.
|
|
106
|
+
*/
|
|
107
|
+
declare function batchPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Batch-patches FROM (1:N) dependencies after the main patch.
|
|
110
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
111
|
+
*/
|
|
112
|
+
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Batch-patches VIA (M:N) dependencies after the main patch.
|
|
115
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
116
|
+
*/
|
|
117
|
+
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
118
|
+
//#endregion
|
|
119
|
+
export { TNestedWriterHost, TRelationLoaderHost, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
package/dist/rel.d.mts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
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-Bbr4CjMb.mjs";
|
|
2
|
+
import { t as DbValidationContext } from "./db-validator-plugin-CiqsHTI_.mjs";
|
|
3
|
+
import { Validator } from "@atscript/typescript/utils";
|
|
4
|
+
import { FilterExpr, WithRelation } from "@uniqu/core";
|
|
5
|
+
|
|
6
|
+
//#region src/rel/relation-loader.d.ts
|
|
7
|
+
/** Host interface for the relation loader — matches AtscriptDbReadable property names. */
|
|
8
|
+
interface TRelationLoaderHost {
|
|
9
|
+
readonly tableName: string;
|
|
10
|
+
readonly _meta: {
|
|
11
|
+
readonly relations: ReadonlyMap<string, TDbRelation>;
|
|
12
|
+
readonly foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
13
|
+
};
|
|
14
|
+
readonly _tableResolver?: TTableResolver;
|
|
15
|
+
readonly adapter: BaseDbAdapter;
|
|
16
|
+
readonly logger: TGenericLogger;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Loads related data for `$with` relations and attaches them to result rows.
|
|
20
|
+
*/
|
|
21
|
+
declare function loadRelationsImpl(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], host: TRelationLoaderHost): Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/rel/relation-helpers.d.ts
|
|
24
|
+
/**
|
|
25
|
+
* Finds the FK entry that connects a `@db.rel.to` relation to its target.
|
|
26
|
+
*/
|
|
27
|
+
declare function findFKForRelation(relation: TDbRelation, foreignKeys: ReadonlyMap<string, TDbForeignKey>): {
|
|
28
|
+
localFields: string[];
|
|
29
|
+
targetFields: string[];
|
|
30
|
+
} | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Finds a FK on a remote table that points back to a given table name.
|
|
33
|
+
*/
|
|
34
|
+
declare function findRemoteFK(targetTable: {
|
|
35
|
+
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
36
|
+
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Resolves the target table name from a relation's target type metadata.
|
|
39
|
+
*/
|
|
40
|
+
declare function resolveRelationTargetTable(relation: TDbRelation): string;
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/rel/nested-writer.d.ts
|
|
43
|
+
/**
|
|
44
|
+
* Properties the nested writer functions need from the table instance.
|
|
45
|
+
* AtscriptDbTable satisfies this structurally — pass `this` with a cast.
|
|
46
|
+
*/
|
|
47
|
+
interface TNestedWriterHost {
|
|
48
|
+
readonly tableName: string;
|
|
49
|
+
readonly _meta: TableMetadata;
|
|
50
|
+
readonly _writeTableResolver?: TWriteTableResolver;
|
|
51
|
+
_findFKForRelation(relation: TDbRelation): {
|
|
52
|
+
localFields: string[];
|
|
53
|
+
targetFields: string[];
|
|
54
|
+
} | undefined;
|
|
55
|
+
_findRemoteFK(targetTable: {
|
|
56
|
+
foreignKeys: ReadonlyMap<string, TDbForeignKey>;
|
|
57
|
+
}, thisTableName: string, alias?: string): TDbForeignKey | undefined;
|
|
58
|
+
_extractPrimaryKeyFilter(payload: Record<string, unknown>): FilterExpr;
|
|
59
|
+
findOne(query: {
|
|
60
|
+
filter: FilterExpr;
|
|
61
|
+
controls: Record<string, never>;
|
|
62
|
+
}): Promise<Record<string, unknown> | null>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Checks if any payload contains navigational data that would be silently
|
|
66
|
+
* dropped because maxDepth is 0.
|
|
67
|
+
*/
|
|
68
|
+
declare function checkDepthOverflow(payloads: Array<Record<string, unknown>>, maxDepth: number, meta: TableMetadata): void;
|
|
69
|
+
/**
|
|
70
|
+
* Validates a batch of items using the given validator and context.
|
|
71
|
+
* Wraps per-item validation errors with array index paths for batch operations.
|
|
72
|
+
*/
|
|
73
|
+
declare function validateBatch(validator: Validator<any, any>, items: Array<Record<string, unknown>>, ctx: DbValidationContext): void;
|
|
74
|
+
/**
|
|
75
|
+
* Pre-validates FROM children (type + FK constraints) before the main insert.
|
|
76
|
+
* Catches errors early before the parent record is committed.
|
|
77
|
+
*/
|
|
78
|
+
declare function preValidateNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Batch-creates TO dependencies before the main insert.
|
|
81
|
+
*/
|
|
82
|
+
declare function batchInsertNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Batch-creates FROM dependents after the main insert.
|
|
85
|
+
*/
|
|
86
|
+
declare function batchInsertNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, parentIds: unknown[], maxDepth: number, depth: number): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Batch-creates VIA (M:N) targets and junction entries after the main insert.
|
|
89
|
+
*/
|
|
90
|
+
declare function batchInsertNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, parentIds: unknown[], maxDepth: number, depth: number): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Batch-replaces TO dependencies before the main replace.
|
|
93
|
+
*/
|
|
94
|
+
declare function batchReplaceNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Batch-replaces FROM dependents after the main replace.
|
|
97
|
+
*/
|
|
98
|
+
declare function batchReplaceNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Handles VIA (M:N) relations during replace.
|
|
101
|
+
*/
|
|
102
|
+
declare function batchReplaceNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Batch-patches TO dependencies before the main patch.
|
|
105
|
+
* Reads FK values from DB if not present in the payload.
|
|
106
|
+
*/
|
|
107
|
+
declare function batchPatchNestedTo(host: TNestedWriterHost, items: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Batch-patches FROM (1:N) dependencies after the main patch.
|
|
110
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
111
|
+
*/
|
|
112
|
+
declare function batchPatchNestedFrom(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Batch-patches VIA (M:N) dependencies after the main patch.
|
|
115
|
+
* Supports patch operators: $replace, $insert, $remove, $update, $upsert.
|
|
116
|
+
*/
|
|
117
|
+
declare function batchPatchNestedVia(host: TNestedWriterHost, originals: Array<Record<string, unknown>>, maxDepth: number, depth: number): Promise<void>;
|
|
118
|
+
//#endregion
|
|
119
|
+
export { type TNestedWriterHost, type TRelationLoaderHost, batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
package/dist/rel.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
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-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-Dmm1gbZV.mjs";
|
|
3
|
+
import { n as findRemoteFK, r as resolveRelationTargetTable, t as findFKForRelation } from "./relation-helpers-CLasawQq.mjs";
|
|
4
|
+
export { batchInsertNestedFrom, batchInsertNestedTo, batchInsertNestedVia, batchPatchNestedFrom, batchPatchNestedTo, batchPatchNestedVia, batchReplaceNestedFrom, batchReplaceNestedTo, batchReplaceNestedVia, checkDepthOverflow, findFKForRelation, findRemoteFK, loadRelationsImpl, preValidateNestedFrom, resolveRelationTargetTable, validateBatch };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
//#region src/rel/relation-helpers.ts
|
|
2
|
+
/**
|
|
3
|
+
* Finds the FK entry that connects a `@db.rel.to` relation to its target.
|
|
4
|
+
*/
|
|
4
5
|
function findFKForRelation(relation, foreignKeys) {
|
|
5
6
|
const targetTable = resolveRelationTargetTable(relation);
|
|
6
7
|
for (const fk of foreignKeys.values()) if (relation.alias) {
|
|
@@ -12,36 +13,39 @@ function findFKForRelation(relation, foreignKeys) {
|
|
|
12
13
|
localFields: fk.fields,
|
|
13
14
|
targetFields: fk.targetFields
|
|
14
15
|
};
|
|
15
|
-
return undefined;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds a FK on a remote table that points back to a given table name.
|
|
19
|
+
*/
|
|
17
20
|
function findRemoteFK(targetTable, thisTableName, alias) {
|
|
18
21
|
for (const fk of targetTable.foreignKeys.values()) {
|
|
19
22
|
if (alias && fk.alias === alias && fk.targetTable === thisTableName) return fk;
|
|
20
23
|
if (!alias && fk.targetTable === thisTableName) return fk;
|
|
21
24
|
}
|
|
22
|
-
return undefined;
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the target table name from a relation's target type metadata.
|
|
28
|
+
*/
|
|
24
29
|
function resolveRelationTargetTable(relation) {
|
|
25
30
|
const targetType = relation.targetType();
|
|
26
31
|
return targetType?.metadata?.get("db.table") || targetType?.id || "";
|
|
27
32
|
}
|
|
28
|
-
|
|
29
33
|
//#endregion
|
|
30
|
-
Object.defineProperty(exports,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
Object.defineProperty(exports, "findFKForRelation", {
|
|
35
|
+
enumerable: true,
|
|
36
|
+
get: function() {
|
|
37
|
+
return findFKForRelation;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
Object.defineProperty(exports, "findRemoteFK", {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
get: function() {
|
|
43
|
+
return findRemoteFK;
|
|
44
|
+
}
|
|
35
45
|
});
|
|
36
|
-
Object.defineProperty(exports,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
Object.defineProperty(exports, "resolveRelationTargetTable", {
|
|
47
|
+
enumerable: true,
|
|
48
|
+
get: function() {
|
|
49
|
+
return resolveRelationTargetTable;
|
|
50
|
+
}
|
|
41
51
|
});
|
|
42
|
-
Object.defineProperty(exports, 'resolveRelationTargetTable', {
|
|
43
|
-
enumerable: true,
|
|
44
|
-
get: function () {
|
|
45
|
-
return resolveRelationTargetTable;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/rel/relation-helpers.ts
|
|
2
|
+
/**
|
|
3
|
+
* Finds the FK entry that connects a `@db.rel.to` relation to its target.
|
|
4
|
+
*/
|
|
3
5
|
function findFKForRelation(relation, foreignKeys) {
|
|
4
6
|
const targetTable = resolveRelationTargetTable(relation);
|
|
5
7
|
for (const fk of foreignKeys.values()) if (relation.alias) {
|
|
@@ -11,19 +13,22 @@ function findFKForRelation(relation, foreignKeys) {
|
|
|
11
13
|
localFields: fk.fields,
|
|
12
14
|
targetFields: fk.targetFields
|
|
13
15
|
};
|
|
14
|
-
return undefined;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Finds a FK on a remote table that points back to a given table name.
|
|
19
|
+
*/
|
|
16
20
|
function findRemoteFK(targetTable, thisTableName, alias) {
|
|
17
21
|
for (const fk of targetTable.foreignKeys.values()) {
|
|
18
22
|
if (alias && fk.alias === alias && fk.targetTable === thisTableName) return fk;
|
|
19
23
|
if (!alias && fk.targetTable === thisTableName) return fk;
|
|
20
24
|
}
|
|
21
|
-
return undefined;
|
|
22
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the target table name from a relation's target type metadata.
|
|
28
|
+
*/
|
|
23
29
|
function resolveRelationTargetTable(relation) {
|
|
24
30
|
const targetType = relation.targetType();
|
|
25
31
|
return targetType?.metadata?.get("db.table") || targetType?.id || "";
|
|
26
32
|
}
|
|
27
|
-
|
|
28
33
|
//#endregion
|
|
29
|
-
export {
|
|
34
|
+
export { findRemoteFK as n, resolveRelationTargetTable as r, findFKForRelation as t };
|