@atscript/db 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db-error-Cepx-RsQ.mjs +29 -0
- package/dist/db-error-D8tQhNgM.cjs +40 -0
- package/dist/{db-readable-GBjlsJXR.d.mts → db-readable-B9Irll4q.d.mts} +151 -116
- package/dist/{db-readable-ktHqF277.d.cts → db-readable-Cwjbk6o_.d.cts} +150 -115
- package/dist/{db-space-DB0MT6B3.d.cts → db-space-CAcEB09Y.d.mts} +15 -2
- package/dist/{db-space-DpaXOdRp.d.mts → db-space-CQg17vv7.d.cts} +15 -2
- package/dist/{db-validator-plugin-Cz4QoDWg.d.cts → db-validator-plugin-DDvYyv5t.d.mts} +10 -0
- package/dist/{db-validator-plugin-KC4aNIQq.d.mts → db-validator-plugin-DRGMCEn3.d.cts} +10 -0
- package/dist/{db-view-DjDKgytJ.cjs → db-view-DIGN4079.cjs} +81 -19
- package/dist/{db-view-B1j_IKSf.mjs → db-view-DNwX6_4x.mjs} +72 -10
- package/dist/index.cjs +5 -4
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +4 -3
- package/dist/{nested-writer-CNDyhg2L.mjs → nested-writer-CT2rLURx.mjs} +9 -16
- package/dist/{nested-writer-BIQ6EfaR.cjs → nested-writer-v_LPR1yJ.cjs} +14 -27
- package/dist/ops.d.mts +1 -1
- package/dist/plugin.cjs +99 -9
- package/dist/plugin.mjs +99 -9
- package/dist/rel.cjs +1 -1
- package/dist/rel.d.cts +2 -2
- package/dist/rel.d.mts +2 -2
- package/dist/rel.mjs +1 -1
- package/dist/shared.cjs +1 -1
- package/dist/shared.mjs +1 -1
- package/dist/sync.cjs +5 -5
- package/dist/sync.d.cts +2 -2
- package/dist/sync.d.mts +2 -2
- package/dist/sync.mjs +5 -5
- package/dist/{validator-D_7Fqzs4.mjs → validator-BB5h1Le3.mjs} +42 -0
- package/dist/{validator-0iGuvGOD.cjs → validator-BIuw_T0k.cjs} +42 -0
- package/dist/validator.cjs +1 -1
- package/dist/validator.d.cts +1 -1
- package/dist/validator.d.mts +3 -3
- package/dist/validator.mjs +1 -1
- package/package.json +6 -6
- /package/dist/{control-D1QdBO21.cjs → control-CDnwVj4q.cjs} +0 -0
- /package/dist/{control-DBd_ff5-.mjs → control-ExEKWYBE.mjs} +0 -0
- /package/dist/{ops-DcHDxrjX.d.mts → ops-C61kelof.d.mts} +0 -0
- /package/dist/{validation-utils-BiG3pLP0.cjs → validation-utils-B9WJv9aH.cjs} +0 -0
- /package/dist/{validation-utils-aNrgK-cj.mjs → validation-utils-Bh7RVrVl.mjs} +0 -0
- /package/dist/{validator-BeXlQISk.d.mts → validator-DttN2e5_.d.mts} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as DbError } from "./db-error-Cepx-RsQ.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 { separateFieldOps } from "./ops.mjs";
|
|
5
|
-
import { i as forceNavNonOptional, r as dbPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-
|
|
5
|
+
import { i as forceNavNonOptional, r as dbPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-BB5h1Le3.mjs";
|
|
6
|
+
import { a as batchPatchNestedTo, c as batchReplaceNestedTo, d as preValidateNestedFrom, f as validateBatch, 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-CT2rLURx.mjs";
|
|
6
7
|
import { flattenAnnotatedType, isAnnotatedType } from "@atscript/typescript/utils";
|
|
7
8
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
9
|
//#region src/logger.ts
|
|
@@ -1096,6 +1097,15 @@ var AtscriptDbReadable = class {
|
|
|
1096
1097
|
_ensureBuilt() {
|
|
1097
1098
|
if (!this._meta.isBuilt) this._meta.build(this.type, this.adapter, this.logger);
|
|
1098
1099
|
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Built table metadata. Triggers a lazy build on first access — safe to call
|
|
1102
|
+
* from peer tables that need this one's relations / nav fields before any
|
|
1103
|
+
* operation has run against it directly.
|
|
1104
|
+
*/
|
|
1105
|
+
getMetadata() {
|
|
1106
|
+
this._ensureBuilt();
|
|
1107
|
+
return this._meta;
|
|
1108
|
+
}
|
|
1099
1109
|
_ensureSearchable() {
|
|
1100
1110
|
if (!this.adapter.isSearchable()) throw new DbError("INVALID_QUERY", [{
|
|
1101
1111
|
path: "$search",
|
|
@@ -2358,6 +2368,7 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2358
2368
|
_fkLookupResolver;
|
|
2359
2369
|
_integrity;
|
|
2360
2370
|
validators = /* @__PURE__ */ new Map();
|
|
2371
|
+
_fromDepthMap;
|
|
2361
2372
|
constructor(_type, adapter, logger, _tableResolver, _writeTableResolver) {
|
|
2362
2373
|
super(_type, adapter, logger, _tableResolver);
|
|
2363
2374
|
if (_writeTableResolver) this._writeTableResolver = _writeTableResolver;
|
|
@@ -2411,16 +2422,20 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2411
2422
|
*/
|
|
2412
2423
|
async insertMany(payloads, opts) {
|
|
2413
2424
|
this._ensureBuilt();
|
|
2414
|
-
const maxDepth = opts
|
|
2415
|
-
const
|
|
2425
|
+
const { _depth, maxDepth: userMax } = opts ?? {};
|
|
2426
|
+
const maxDepth = userMax ?? 3;
|
|
2427
|
+
const depth = _depth ?? 0;
|
|
2416
2428
|
const canNest = depth < maxDepth && this._writeTableResolver && this._meta.navFields.size > 0;
|
|
2417
2429
|
if (!canNest && this._meta.navFields.size > 0) checkDepthOverflow(payloads, maxDepth, this._meta);
|
|
2418
2430
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2419
2431
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2420
|
-
|
|
2432
|
+
const validator = this.getValidator("insert");
|
|
2433
|
+
const ctx = {
|
|
2421
2434
|
mode: "insert",
|
|
2422
2435
|
navFields: this._meta.navFields
|
|
2423
|
-
}
|
|
2436
|
+
};
|
|
2437
|
+
this._applyDepthCtx(ctx, depth);
|
|
2438
|
+
validateBatch(validator, items, ctx);
|
|
2424
2439
|
const host = this;
|
|
2425
2440
|
if (canNest) await batchInsertNestedTo(host, items, maxDepth, depth);
|
|
2426
2441
|
const prepared = [];
|
|
@@ -2460,10 +2475,13 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2460
2475
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2461
2476
|
const items = payloads.map((p) => this._applyDefaults({ ...p }));
|
|
2462
2477
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2463
|
-
|
|
2478
|
+
const validator = this.getValidator("bulkReplace");
|
|
2479
|
+
const ctx = {
|
|
2464
2480
|
mode: "replace",
|
|
2465
2481
|
navFields: this._meta.navFields
|
|
2466
|
-
}
|
|
2482
|
+
};
|
|
2483
|
+
this._applyDepthCtx(ctx, depth);
|
|
2484
|
+
validateBatch(validator, items, ctx);
|
|
2467
2485
|
const host = this;
|
|
2468
2486
|
if (canNest) await batchReplaceNestedTo(host, items, maxDepth, depth);
|
|
2469
2487
|
await this._integrity.validateForeignKeys(items, this._meta, this._fkLookupResolver, this._writeTableResolver);
|
|
@@ -2507,11 +2525,14 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2507
2525
|
const canNest = depth < maxDepth && this._writeTableResolver && this._meta.navFields.size > 0;
|
|
2508
2526
|
if (!canNest && this._meta.navFields.size > 0) checkDepthOverflow(payloads, maxDepth, this._meta);
|
|
2509
2527
|
return enrichFkViolation(this._meta, () => this.adapter.withTransaction(async () => {
|
|
2510
|
-
|
|
2528
|
+
const validator = this.getValidator("bulkUpdate");
|
|
2529
|
+
const ctx = {
|
|
2511
2530
|
mode: "patch",
|
|
2512
2531
|
flatMap: this.flatMap,
|
|
2513
2532
|
navFields: this._meta.navFields
|
|
2514
|
-
}
|
|
2533
|
+
};
|
|
2534
|
+
this._applyDepthCtx(ctx, depth);
|
|
2535
|
+
validateBatch(validator, payloads, ctx);
|
|
2515
2536
|
const originals = canNest ? payloads.map((p) => ({ ...p })) : [];
|
|
2516
2537
|
const host = this;
|
|
2517
2538
|
if (canNest) await batchPatchNestedTo(host, payloads, maxDepth, depth);
|
|
@@ -2687,6 +2708,47 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
|
|
|
2687
2708
|
return fieldType ? this.adapter.prepareId(value, fieldType) : value;
|
|
2688
2709
|
}
|
|
2689
2710
|
/**
|
|
2711
|
+
* Lazy — builds a `normalized-path → from-depth` map from `this._meta.flatMap`
|
|
2712
|
+
* on first use. Only paths reachable through an unbroken chain of `db.rel.from`
|
|
2713
|
+
* nav fields from the root are included (chains crossing `to`/`via` are excluded).
|
|
2714
|
+
*/
|
|
2715
|
+
_getFromDepthMap() {
|
|
2716
|
+
if (!this._fromDepthMap) {
|
|
2717
|
+
const out = /* @__PURE__ */ new Map();
|
|
2718
|
+
for (const [path, def] of this._meta.flatMap) {
|
|
2719
|
+
if (!def.metadata?.has("db.rel.from")) continue;
|
|
2720
|
+
const segments = path.split(".");
|
|
2721
|
+
let prefix = "";
|
|
2722
|
+
let depth = 0;
|
|
2723
|
+
let valid = true;
|
|
2724
|
+
for (let i = 0; i < segments.length; i++) {
|
|
2725
|
+
prefix = prefix ? `${prefix}.${segments[i]}` : segments[i];
|
|
2726
|
+
const pmd = this._meta.flatMap.get(prefix)?.metadata;
|
|
2727
|
+
if (pmd?.has("db.rel.to") || pmd?.has("db.rel.via")) {
|
|
2728
|
+
valid = false;
|
|
2729
|
+
break;
|
|
2730
|
+
}
|
|
2731
|
+
if (pmd?.has("db.rel.from")) depth++;
|
|
2732
|
+
}
|
|
2733
|
+
if (valid) out.set(path, depth);
|
|
2734
|
+
}
|
|
2735
|
+
this._fromDepthMap = out;
|
|
2736
|
+
}
|
|
2737
|
+
return this._fromDepthMap;
|
|
2738
|
+
}
|
|
2739
|
+
/**
|
|
2740
|
+
* Populate the depth-limit bundle on a `DbValidationContext`. Only the root
|
|
2741
|
+
* write call (`depth === 0`) enforces — nested re-entries leave `depthCheck`
|
|
2742
|
+
* unset so the full tree is validated once at the root.
|
|
2743
|
+
*/
|
|
2744
|
+
_applyDepthCtx(ctx, depth) {
|
|
2745
|
+
if (depth !== 0 || this._meta.navFields.size === 0) return;
|
|
2746
|
+
ctx.depthCheck = {
|
|
2747
|
+
limit: this.type.metadata.get("db.depth.limit") ?? 0,
|
|
2748
|
+
fromDepthMap: this._getFromDepthMap()
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
/**
|
|
2690
2752
|
* Pre-validate items (type validation + FK constraints) without inserting them.
|
|
2691
2753
|
* Used by parent tables to validate FROM children before the main insert,
|
|
2692
2754
|
* ensuring errors are caught before the parent is committed.
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const require_db_view = require("./db-view-
|
|
2
|
+
const require_db_error = require("./db-error-D8tQhNgM.cjs");
|
|
3
|
+
const require_db_view = require("./db-view-DIGN4079.cjs");
|
|
4
4
|
const require_ops = require("./ops.cjs");
|
|
5
|
-
const require_validator = require("./validator-
|
|
5
|
+
const require_validator = require("./validator-BIuw_T0k.cjs");
|
|
6
|
+
require("./nested-writer-v_LPR1yJ.cjs");
|
|
6
7
|
let _uniqu_core = require("@uniqu/core");
|
|
7
8
|
//#region src/table/db-space.ts
|
|
8
9
|
/**
|
|
@@ -152,7 +153,7 @@ exports.AtscriptDbReadable = require_db_view.AtscriptDbReadable;
|
|
|
152
153
|
exports.AtscriptDbTable = require_db_view.AtscriptDbTable;
|
|
153
154
|
exports.AtscriptDbView = require_db_view.AtscriptDbView;
|
|
154
155
|
exports.BaseDbAdapter = require_db_view.BaseDbAdapter;
|
|
155
|
-
exports.DbError =
|
|
156
|
+
exports.DbError = require_db_error.DbError;
|
|
156
157
|
exports.DbSpace = DbSpace;
|
|
157
158
|
exports.DocumentFieldMapper = require_db_view.DocumentFieldMapper;
|
|
158
159
|
exports.FieldMappingStrategy = require_db_view.FieldMappingStrategy;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as TTableResolver, A as TDbFieldMeta, B as TDbUpdateResult, C as TDbActionIntent, D as TDbDefaultFn, E as TDbCollation, F as TDbInsertManyResult, G as TFkLookupTarget, H as TExistingTableOption, I as TDbInsertResult, J as TMetadataOverrides, K as TIdDescriptor, L as TDbReferentialAction, M as TDbIndex, N as TDbIndexField, O as TDbDefaultValue, P as TDbIndexType, Q as TTableOptionDiff, R as TDbRelation, S as TDbActionInfo, T as TDbActionProcessor, U as TFieldMeta, V as TExistingColumn, W as TFkLookupResolver, X as TSearchIndexInfo, Y as TRelationInfo, Z as TSyncColumnResult, _ as NavPropsOf, a as FieldMappingStrategy, at as WithRelation, b as TCascadeTarget, c as AggregateExpr, ct as TGenericLogger, d as AggregateResult, et as TValueFormatterPair, f as AtscriptDbWritable, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as UniqueryControls, j as TDbForeignKey, k as TDbDeleteResult, l as AggregateFn, lt as UniquSelect, m as DbQuery, n as DbResponse, nt as TypedWithRelation, o as BaseDbAdapter, ot as TableMetadata, p as DbControls, q as TMetaResponse, r as resolveDesignType, rt as Uniquery, s as AggregateControls, st as NoopLogger, t as AtscriptDbReadable, tt as TWriteTableResolver, u as AggregateQuery, v as OwnPropsOf, w as TDbActionLevel, x as TColumnDiff, y as TCascadeResolver, z as TDbStorageType } from "./db-readable-Cwjbk6o_.cjs";
|
|
2
2
|
import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, 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-CQg17vv7.cjs";
|
|
4
|
+
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-DRGMCEn3.cjs";
|
|
5
5
|
import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-_z_A3cKa.cjs";
|
|
6
6
|
import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
7
7
|
|
|
@@ -81,7 +81,7 @@ declare class ApplicationIntegrity extends IntegrityStrategy {
|
|
|
81
81
|
}
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/db-error.d.ts
|
|
84
|
-
type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY";
|
|
84
|
+
type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED";
|
|
85
85
|
declare class DbError extends Error {
|
|
86
86
|
readonly code: DbErrorCode;
|
|
87
87
|
readonly errors: Array<{
|
|
@@ -114,4 +114,4 @@ declare class DbError extends Error {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function decomposePatch(payload: Record<string, unknown>, table: AtscriptDbTable): Record<string, unknown>;
|
|
116
116
|
//#endregion
|
|
117
|
-
export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
|
|
117
|
+
export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-
|
|
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-
|
|
5
|
-
import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-
|
|
1
|
+
import { $ as TTableResolver, A as TDbFieldMeta, B as TDbUpdateResult, C as TDbActionIntent, D as TDbDefaultFn, E as TDbCollation, F as TDbInsertManyResult, G as TFkLookupTarget, H as TExistingTableOption, I as TDbInsertResult, J as TMetadataOverrides, K as TIdDescriptor, L as TDbReferentialAction, M as TDbIndex, N as TDbIndexField, O as TDbDefaultValue, P as TDbIndexType, Q as TTableOptionDiff, R as TDbRelation, S as TDbActionInfo, T as TDbActionProcessor, U as TFieldMeta, V as TExistingColumn, W as TFkLookupResolver, X as TSearchIndexInfo, Y as TRelationInfo, Z as TSyncColumnResult, _ as NavPropsOf, a as FieldMappingStrategy, at as WithRelation, b as TCascadeTarget, c as AggregateExpr, ct as TGenericLogger, d as AggregateResult, et as TValueFormatterPair, f as AtscriptDbWritable, g as FilterExpr, h as FieldOpsFor, i as DocumentFieldMapper, it as UniqueryControls, j as TDbForeignKey, k as TDbDeleteResult, l as AggregateFn, lt as UniquSelect, m as DbQuery, n as DbResponse, nt as TypedWithRelation, o as BaseDbAdapter, ot as TableMetadata, p as DbControls, q as TMetaResponse, r as resolveDesignType, rt as Uniquery, s as AggregateControls, st as NoopLogger, t as AtscriptDbReadable, tt as TWriteTableResolver, u as AggregateQuery, v as OwnPropsOf, w as TDbActionLevel, x as TColumnDiff, y as TCascadeResolver, z as TDbStorageType } from "./db-readable-B9Irll4q.mjs";
|
|
2
|
+
import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-C61kelof.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-CAcEB09Y.mjs";
|
|
4
|
+
import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-DDvYyv5t.mjs";
|
|
5
|
+
import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-DttN2e5_.mjs";
|
|
6
6
|
import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
7
7
|
|
|
8
8
|
//#region src/strategies/relational-field-mapper.d.ts
|
|
@@ -81,7 +81,7 @@ declare class ApplicationIntegrity extends IntegrityStrategy {
|
|
|
81
81
|
}
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/db-error.d.ts
|
|
84
|
-
type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY";
|
|
84
|
+
type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED";
|
|
85
85
|
declare class DbError extends Error {
|
|
86
86
|
readonly code: DbErrorCode;
|
|
87
87
|
readonly errors: Array<{
|
|
@@ -114,4 +114,4 @@ declare class DbError extends Error {
|
|
|
114
114
|
*/
|
|
115
115
|
declare function decomposePatch(payload: Record<string, unknown>, table: AtscriptDbTable): Record<string, unknown>;
|
|
116
116
|
//#endregion
|
|
117
|
-
export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
|
|
117
|
+
export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, type DbControls, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithRelation, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, isDbFieldOp, isNavRelation, isPrimitive, resolveDesignType, separateFieldOps, translateQueryTree, walkFilter };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as BaseDbAdapter, c as AtscriptDbReadable, d as DocumentFieldMapper, f as FieldMappingStrategy, h as NoopLogger, i as ApplicationIntegrity, l as resolveDesignType, m as TableMetadata, n as AtscriptDbTable, o as IntegrityStrategy, p as UniquSelect, r as decomposePatch, s as NativeIntegrity, t as AtscriptDbView, u as RelationalFieldMapper } from "./db-view-
|
|
1
|
+
import { t as DbError } from "./db-error-Cepx-RsQ.mjs";
|
|
2
|
+
import { a as BaseDbAdapter, c as AtscriptDbReadable, d as DocumentFieldMapper, f as FieldMappingStrategy, h as NoopLogger, i as ApplicationIntegrity, l as resolveDesignType, m as TableMetadata, n as AtscriptDbTable, o as IntegrityStrategy, p as UniquSelect, r as decomposePatch, s as NativeIntegrity, t as AtscriptDbView, u as RelationalFieldMapper } from "./db-view-DNwX6_4x.mjs";
|
|
3
3
|
import { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, getDbFieldOp, isDbFieldOp, separateFieldOps } from "./ops.mjs";
|
|
4
|
-
import { a as isNavRelation, i as forceNavNonOptional, n as buildValidationContext, o as createDbValidatorPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-
|
|
4
|
+
import { a as isNavRelation, i as forceNavNonOptional, n as buildValidationContext, o as createDbValidatorPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-BB5h1Le3.mjs";
|
|
5
|
+
import "./nested-writer-CT2rLURx.mjs";
|
|
5
6
|
import { computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
|
|
6
7
|
//#region src/table/db-space.ts
|
|
7
8
|
/**
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
+
import { n as DepthLimitExceededError, t as DbError } from "./db-error-Cepx-RsQ.mjs";
|
|
1
2
|
import { r as resolveRelationTargetTable } from "./relation-helpers-CLasawQq.mjs";
|
|
2
3
|
import { ValidatorError } from "@atscript/typescript/utils";
|
|
3
|
-
//#region src/db-error.ts
|
|
4
|
-
var DbError = class extends Error {
|
|
5
|
-
name = "DbError";
|
|
6
|
-
constructor(code, errors, message) {
|
|
7
|
-
super(message ?? errors[0]?.message ?? "Database error");
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.errors = errors;
|
|
10
|
-
this.stack = void 0;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
4
|
//#region src/table/error-utils.ts
|
|
15
5
|
/**
|
|
16
6
|
* Prefixes error paths with a nav field context.
|
|
@@ -89,10 +79,13 @@ function validateBatch(validator, items, ctx) {
|
|
|
89
79
|
for (let i = 0; i < items.length; i++) try {
|
|
90
80
|
validator.validate(items[i], false, ctx);
|
|
91
81
|
} catch (error) {
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
if (items.length > 1) {
|
|
83
|
+
if (error instanceof ValidatorError) throw new ValidatorError(error.errors.map((err) => ({
|
|
84
|
+
...err,
|
|
85
|
+
path: `[${i}].${err.path}`
|
|
86
|
+
})));
|
|
87
|
+
if (error instanceof DepthLimitExceededError) throw new DepthLimitExceededError(`[${i}].${error.field}`, error.declared, error.actual);
|
|
88
|
+
}
|
|
96
89
|
throw error;
|
|
97
90
|
}
|
|
98
91
|
}
|
|
@@ -621,4 +614,4 @@ async function viaReplace(targetTable, junctionTable, targets, parentPK, targetP
|
|
|
621
614
|
}
|
|
622
615
|
}
|
|
623
616
|
//#endregion
|
|
624
|
-
export { batchPatchNestedTo as a, batchReplaceNestedTo as c, preValidateNestedFrom as d, validateBatch as f,
|
|
617
|
+
export { batchPatchNestedTo as a, batchReplaceNestedTo as c, preValidateNestedFrom as d, validateBatch as f, batchPatchNestedFrom as i, batchReplaceNestedVia as l, remapDeleteFkViolation as m, batchInsertNestedTo as n, batchPatchNestedVia as o, enrichFkViolation as p, batchInsertNestedVia as r, batchReplaceNestedFrom as s, batchInsertNestedFrom as t, checkDepthOverflow as u };
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
+
const require_db_error = require("./db-error-D8tQhNgM.cjs");
|
|
1
2
|
const require_relation_helpers = require("./relation-helpers-BYvsE1tR.cjs");
|
|
2
3
|
let _atscript_typescript_utils = require("@atscript/typescript/utils");
|
|
3
|
-
//#region src/db-error.ts
|
|
4
|
-
var DbError = class extends Error {
|
|
5
|
-
name = "DbError";
|
|
6
|
-
constructor(code, errors, message) {
|
|
7
|
-
super(message ?? errors[0]?.message ?? "Database error");
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.errors = errors;
|
|
10
|
-
this.stack = void 0;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
//#endregion
|
|
14
4
|
//#region src/table/error-utils.ts
|
|
15
5
|
/**
|
|
16
6
|
* Prefixes error paths with a nav field context.
|
|
@@ -31,7 +21,7 @@ async function wrapNestedError(navField, fn) {
|
|
|
31
21
|
return await fn();
|
|
32
22
|
} catch (error) {
|
|
33
23
|
if (error instanceof _atscript_typescript_utils.ValidatorError) throw new _atscript_typescript_utils.ValidatorError(prefixErrorPaths(error.errors, navField));
|
|
34
|
-
if (error instanceof DbError) throw new DbError(error.code, prefixErrorPaths(error.errors, navField));
|
|
24
|
+
if (error instanceof require_db_error.DbError) throw new require_db_error.DbError(error.code, prefixErrorPaths(error.errors, navField));
|
|
35
25
|
throw error;
|
|
36
26
|
}
|
|
37
27
|
}
|
|
@@ -44,14 +34,14 @@ async function enrichFkViolation(meta, fn) {
|
|
|
44
34
|
try {
|
|
45
35
|
return await fn();
|
|
46
36
|
} catch (error) {
|
|
47
|
-
if (error instanceof DbError && error.code === "FK_VIOLATION" && error.errors.every((err) => !err.path)) {
|
|
37
|
+
if (error instanceof require_db_error.DbError && error.code === "FK_VIOLATION" && error.errors.every((err) => !err.path)) {
|
|
48
38
|
const msg = error.errors[0]?.message ?? error.message;
|
|
49
39
|
const errors = [];
|
|
50
40
|
for (const [, fk] of meta.foreignKeys) for (const field of fk.fields) errors.push({
|
|
51
41
|
path: field,
|
|
52
42
|
message: msg
|
|
53
43
|
});
|
|
54
|
-
throw new DbError("FK_VIOLATION", errors.length > 0 ? errors : error.errors);
|
|
44
|
+
throw new require_db_error.DbError("FK_VIOLATION", errors.length > 0 ? errors : error.errors);
|
|
55
45
|
}
|
|
56
46
|
throw error;
|
|
57
47
|
}
|
|
@@ -64,7 +54,7 @@ async function remapDeleteFkViolation(tableName, fn) {
|
|
|
64
54
|
try {
|
|
65
55
|
return await fn();
|
|
66
56
|
} catch (error) {
|
|
67
|
-
if (error instanceof DbError && error.code === "FK_VIOLATION") throw new DbError("CONFLICT", [{
|
|
57
|
+
if (error instanceof require_db_error.DbError && error.code === "FK_VIOLATION") throw new require_db_error.DbError("CONFLICT", [{
|
|
68
58
|
path: tableName,
|
|
69
59
|
message: `Cannot delete from "${tableName}": referenced by child records (RESTRICT)`
|
|
70
60
|
}]);
|
|
@@ -89,10 +79,13 @@ function validateBatch(validator, items, ctx) {
|
|
|
89
79
|
for (let i = 0; i < items.length; i++) try {
|
|
90
80
|
validator.validate(items[i], false, ctx);
|
|
91
81
|
} catch (error) {
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
if (items.length > 1) {
|
|
83
|
+
if (error instanceof _atscript_typescript_utils.ValidatorError) throw new _atscript_typescript_utils.ValidatorError(error.errors.map((err) => ({
|
|
84
|
+
...err,
|
|
85
|
+
path: `[${i}].${err.path}`
|
|
86
|
+
})));
|
|
87
|
+
if (error instanceof require_db_error.DepthLimitExceededError) throw new require_db_error.DepthLimitExceededError(`[${i}].${error.field}`, error.declared, error.actual);
|
|
88
|
+
}
|
|
96
89
|
throw error;
|
|
97
90
|
}
|
|
98
91
|
}
|
|
@@ -321,13 +314,13 @@ async function batchPatchNestedTo(host, items, maxDepth, depth) {
|
|
|
321
314
|
filter: pkFilter,
|
|
322
315
|
controls: {}
|
|
323
316
|
});
|
|
324
|
-
if (!current) throw new DbError("NOT_FOUND", [{
|
|
317
|
+
if (!current) throw new require_db_error.DbError("NOT_FOUND", [{
|
|
325
318
|
path: navField,
|
|
326
319
|
message: `Cannot patch relation '${navField}' — source record not found`
|
|
327
320
|
}]);
|
|
328
321
|
fkValue = fk.localFields.length === 1 ? current[fk.localFields[0]] : void 0;
|
|
329
322
|
}
|
|
330
|
-
if (fkValue === null || fkValue === void 0) throw new DbError("FK_VIOLATION", [{
|
|
323
|
+
if (fkValue === null || fkValue === void 0) throw new require_db_error.DbError("FK_VIOLATION", [{
|
|
331
324
|
path: fk.localFields[0],
|
|
332
325
|
message: `Cannot patch relation '${navField}' — foreign key '${fk.localFields[0]}' is null`
|
|
333
326
|
}]);
|
|
@@ -621,12 +614,6 @@ async function viaReplace(targetTable, junctionTable, targets, parentPK, targetP
|
|
|
621
614
|
}
|
|
622
615
|
}
|
|
623
616
|
//#endregion
|
|
624
|
-
Object.defineProperty(exports, "DbError", {
|
|
625
|
-
enumerable: true,
|
|
626
|
-
get: function() {
|
|
627
|
-
return DbError;
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
617
|
Object.defineProperty(exports, "batchInsertNestedFrom", {
|
|
631
618
|
enumerable: true,
|
|
632
619
|
get: function() {
|
package/dist/ops.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-
|
|
1
|
+
import { a as $remove, c as $upsert, d as getDbFieldOp, f as isDbFieldOp, i as $mul, l as TDbFieldOp, n as $inc, o as $replace, p as separateFieldOps, r as $insert, s as $update, t as $dec, u as TFieldOps } from "./ops-C61kelof.mjs";
|
|
2
2
|
export { $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, TDbFieldOp, TFieldOps, getDbFieldOp, isDbFieldOp, separateFieldOps };
|
package/dist/plugin.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_validation_utils = require("./validation-utils-
|
|
5
|
+
const require_validation_utils = require("./validation-utils-B9WJv9aH.cjs");
|
|
6
6
|
let _atscript_core = require("@atscript/core");
|
|
7
7
|
//#region src/plugin/annotations/agg.ts
|
|
8
8
|
const dbAggAnnotations = { agg: {
|
|
@@ -155,7 +155,9 @@ const dbColumnAnnotations = {
|
|
|
155
155
|
validate(token, _args, doc) {
|
|
156
156
|
return require_validation_utils.validateFieldBaseType(token, doc, "@db.column.measure", ["number", "decimal"]);
|
|
157
157
|
}
|
|
158
|
-
})
|
|
158
|
+
}),
|
|
159
|
+
filterable: columnCapability("filterable", "filtering"),
|
|
160
|
+
sortable: columnCapability("sortable", "sorting")
|
|
159
161
|
},
|
|
160
162
|
default: {
|
|
161
163
|
$self: new _atscript_core.AnnotationSpec({
|
|
@@ -226,6 +228,30 @@ const dbColumnAnnotations = {
|
|
|
226
228
|
}
|
|
227
229
|
})
|
|
228
230
|
};
|
|
231
|
+
function columnCapability(capability, verb) {
|
|
232
|
+
const example = capability === "filterable" ? " @db.column.filterable\n email: string\n" : " @db.column.sortable\n createdAt: number.timestamp\n";
|
|
233
|
+
return new _atscript_core.AnnotationSpec({
|
|
234
|
+
description: `Marks a column as ${capability} in the readable controller's query/pages endpoints. Relevant only when the host \`@db.table\` interface opts into strict mode with \`@db.table.${capability} 'manual'\`; otherwise ${verb} is open on all columns (default-open, back-compat).
|
|
235
|
+
|
|
236
|
+
**Example:**
|
|
237
|
+
\`\`\`atscript
|
|
238
|
+
@db.table "users"
|
|
239
|
+
@db.table.${capability} "manual"\nexport interface User {
|
|
240
|
+
` + example + "}\n```\n",
|
|
241
|
+
nodeType: ["prop"],
|
|
242
|
+
multiple: false,
|
|
243
|
+
validate(token, _args, _doc) {
|
|
244
|
+
const errors = [];
|
|
245
|
+
const owner = require_validation_utils.getDbTableOwner(token);
|
|
246
|
+
if (!owner || owner.countAnnotations("db.table") === 0) errors.push({
|
|
247
|
+
message: `@db.column.${capability} is only valid on fields of a @db.table interface`,
|
|
248
|
+
severity: 1,
|
|
249
|
+
range: token.range
|
|
250
|
+
});
|
|
251
|
+
return errors;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
229
255
|
//#endregion
|
|
230
256
|
//#region src/plugin/annotations/index-ann.ts
|
|
231
257
|
const dbIndexAnnotations = { index: {
|
|
@@ -281,7 +307,7 @@ const dbIndexAnnotations = { index: {
|
|
|
281
307
|
//#region src/plugin/annotations/rel.ts
|
|
282
308
|
const dbRelAnnotations = { rel: {
|
|
283
309
|
FK: new _atscript_core.AnnotationSpec({
|
|
284
|
-
description: "Declares a foreign key
|
|
310
|
+
description: "Declares a foreign key reference on this field. The field must use a chain reference type (e.g., `User.id`) whose target is a primary key (`@meta.id`) or unique (`@db.index.unique`) field.\n\n**Dual role:**\n- On a `@db.table` interface, `@db.rel.FK` additionally drives DB-relation semantics — relation loading with `@db.rel.to` / `@db.rel.from`, junction pairing with `@db.rel.via`, etc.\n- On any other interface (value-help sources, WF forms, plain interfaces), `@db.rel.FK` acts purely as the value-help indicator: the client-side picker resolver uses it to decide which fields render a value-help picker. The target's `@db.http.path` (stamped by its readable controller) supplies the picker URL.\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",
|
|
285
311
|
nodeType: ["prop"],
|
|
286
312
|
argument: {
|
|
287
313
|
optional: true,
|
|
@@ -293,12 +319,6 @@ const dbRelAnnotations = { rel: {
|
|
|
293
319
|
const errors = [];
|
|
294
320
|
const field = token.parentNode;
|
|
295
321
|
const alias = args[0]?.text;
|
|
296
|
-
const owner = require_validation_utils.getDbTableOwner(token);
|
|
297
|
-
if (!owner || owner.countAnnotations("db.table") === 0) errors.push({
|
|
298
|
-
message: "@db.rel.FK is only valid on fields of a @db.table interface",
|
|
299
|
-
severity: 1,
|
|
300
|
-
range: token.range
|
|
301
|
-
});
|
|
302
322
|
if (field.countAnnotations("db.rel.to") > 0 || field.countAnnotations("db.rel.from") > 0) errors.push({
|
|
303
323
|
message: "A field cannot be both a foreign key and a navigational property",
|
|
304
324
|
severity: 1,
|
|
@@ -705,6 +725,8 @@ const dbSearchAnnotations = { search: {
|
|
|
705
725
|
//#region src/plugin/annotations/table.ts
|
|
706
726
|
const dbTableAnnotations = {
|
|
707
727
|
table: {
|
|
728
|
+
filterable: tableCapability("filterable"),
|
|
729
|
+
sortable: tableCapability("sortable"),
|
|
708
730
|
$self: new _atscript_core.AnnotationSpec({
|
|
709
731
|
description: "Marks an interface as a database-persisted entity (table in SQL, collection in MongoDB). If the name argument is omitted, the adapter derives the table name from the interface name.\n\n**Example:**\n```atscript\n@db.table \"users\"\nexport interface User { ... }\n```\n",
|
|
710
732
|
nodeType: ["interface"],
|
|
@@ -771,8 +793,75 @@ const dbTableAnnotations = {
|
|
|
771
793
|
description: "Sync method: \"drop\" (lossy) or \"recreate\" (lossless with data copy).",
|
|
772
794
|
values: ["drop", "recreate"]
|
|
773
795
|
}
|
|
796
|
+
}) },
|
|
797
|
+
depth: { limit: new _atscript_core.AnnotationSpec({
|
|
798
|
+
description: "Security guard on nested-write payloads. `N` is a non-negative integer declaring the maximum depth a client may nest `@db.rel.from` children in insert, replace, or patch payloads. Writes deeper than `N` are rejected at the server boundary with HTTP 400 before any DB access.\n\n**Default when absent:** `0` — any nested-write payload is rejected. Authors opt in explicitly to `N >= 1` when they want the server to accept deep writes. This is a security / blast-radius control, not a performance knob.\n\n**Scope:** affects only write acceptance. Has no effect on `/meta` serialization, read/query paths, or wire shape — the meta endpoint always ships FK refs as the shallow `{ id, metadata }` shape regardless of this annotation.\n\n**Example:**\n```atscript\n@db.table \"authors\"\n@db.depth.limit 2\nexport interface Author { ... }\n```\n",
|
|
799
|
+
nodeType: ["interface"],
|
|
800
|
+
multiple: false,
|
|
801
|
+
argument: {
|
|
802
|
+
name: "depth",
|
|
803
|
+
type: "number",
|
|
804
|
+
description: "Non-negative integer: maximum nesting depth accepted for nested writes."
|
|
805
|
+
},
|
|
806
|
+
validate(token, args, _doc) {
|
|
807
|
+
const errors = [];
|
|
808
|
+
const owner = token.parentNode;
|
|
809
|
+
if (owner.countAnnotations("db.table") === 0) errors.push({
|
|
810
|
+
message: "@db.depth.limit is only valid on @db.table interfaces",
|
|
811
|
+
severity: 1,
|
|
812
|
+
range: token.range
|
|
813
|
+
});
|
|
814
|
+
if (owner.countAnnotations("db.depth.limit") > 1) errors.push({
|
|
815
|
+
message: "Multiple @db.depth.limit annotations on the same interface",
|
|
816
|
+
severity: 1,
|
|
817
|
+
range: token.range
|
|
818
|
+
});
|
|
819
|
+
const raw = args[0]?.text;
|
|
820
|
+
if (raw !== void 0) {
|
|
821
|
+
const num = Number(raw);
|
|
822
|
+
if (!Number.isFinite(num) || !Number.isInteger(num) || num < 0) errors.push({
|
|
823
|
+
message: `@db.depth.limit depth must be a non-negative integer, got '${raw}'`,
|
|
824
|
+
severity: 1,
|
|
825
|
+
range: args[0].range
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
return errors;
|
|
829
|
+
}
|
|
774
830
|
}) }
|
|
775
831
|
};
|
|
832
|
+
function tableCapability(capability) {
|
|
833
|
+
const example = capability === "filterable" ? " @db.column.filterable\n email: string\n // other fields not filterable via the controller\n" : " @db.column.sortable\n createdAt: number.timestamp\n // other fields not sortable via the controller\n";
|
|
834
|
+
const verb = capability === "filterable" ? "filter" : "sort";
|
|
835
|
+
return new _atscript_core.AnnotationSpec({
|
|
836
|
+
description: `Controls ${verb}-gating on the readable controller's \`/query\` and \`/pages\` endpoints.\n\n- **\`'auto'\`** (default when the annotation is absent) — every column is ${capability}.\n- **\`'manual'\`** — only fields annotated \`@db.column.${capability}\` are ${capability}; all others are rejected with HTTP 400.
|
|
837
|
+
|
|
838
|
+
Writing the annotation explicitly as \`@db.table.${capability} 'auto'\` has the same runtime effect as omitting it; use it to document intent.
|
|
839
|
+
|
|
840
|
+
**Example:**
|
|
841
|
+
\`\`\`atscript
|
|
842
|
+
@db.table "users"
|
|
843
|
+
@db.table.${capability} "manual"\nexport interface User {
|
|
844
|
+
` + example + "}\n```\n",
|
|
845
|
+
nodeType: ["interface"],
|
|
846
|
+
multiple: false,
|
|
847
|
+
argument: {
|
|
848
|
+
optional: true,
|
|
849
|
+
name: "mode",
|
|
850
|
+
type: "string",
|
|
851
|
+
description: `${verb[0].toUpperCase()}${verb.slice(1)}-gating mode: 'auto' (default) or 'manual'.`,
|
|
852
|
+
values: ["auto", "manual"]
|
|
853
|
+
},
|
|
854
|
+
validate(token, _args, _doc) {
|
|
855
|
+
const errors = [];
|
|
856
|
+
if (token.parentNode.countAnnotations("db.table") === 0) errors.push({
|
|
857
|
+
message: `@db.table.${capability} requires @db.table on the same interface`,
|
|
858
|
+
severity: 1,
|
|
859
|
+
range: token.range
|
|
860
|
+
});
|
|
861
|
+
return errors;
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
776
865
|
//#endregion
|
|
777
866
|
//#region src/plugin/annotations/view.ts
|
|
778
867
|
const dbViewAnnotations = { view: {
|
|
@@ -964,6 +1053,7 @@ const dbPlugin = () => ({
|
|
|
964
1053
|
ignore: dbColumnAnnotations.ignore,
|
|
965
1054
|
http: dbTableAnnotations.http,
|
|
966
1055
|
sync: dbTableAnnotations.sync,
|
|
1056
|
+
depth: dbTableAnnotations.depth,
|
|
967
1057
|
rel: dbRelAnnotations.rel,
|
|
968
1058
|
view: dbViewAnnotations.view,
|
|
969
1059
|
agg: dbAggAnnotations.agg,
|