@atscript/db 0.1.42 → 0.1.44

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.
Files changed (32) hide show
  1. package/dist/{db-readable-Cc868K54.d.mts → db-readable-D9odJuSf.d.mts} +1 -1
  2. package/dist/{db-space-crCFv3DF.d.mts → db-space-7bf9_IWC.d.mts} +1 -1
  3. package/dist/{db-view-DSK76uc9.mjs → db-view-7Y5N4muD.mjs} +19 -266
  4. package/dist/{db-view-CcUjETIF.cjs → db-view-BMPRfGjB.cjs} +20 -279
  5. package/dist/index.cjs +16 -3
  6. package/dist/index.d.cts +3 -28
  7. package/dist/index.d.mts +6 -31
  8. package/dist/index.mjs +4 -3
  9. package/dist/ops.d.mts +1 -1
  10. package/dist/plugin.cjs +1 -1
  11. package/dist/plugin.mjs +1 -1
  12. package/dist/rel.d.mts +2 -2
  13. package/dist/shared.cjs +1 -1
  14. package/dist/shared.mjs +1 -1
  15. package/dist/sync.cjs +4 -3
  16. package/dist/sync.d.mts +2 -2
  17. package/dist/sync.mjs +5 -3
  18. package/dist/validator-0iGuvGOD.cjs +337 -0
  19. package/dist/validator-BeXlQISk.d.mts +69 -0
  20. package/dist/validator-D_7Fqzs4.mjs +296 -0
  21. package/dist/validator-_z_A3cKa.d.cts +69 -0
  22. package/dist/validator.cjs +19 -0
  23. package/dist/validator.d.cts +4 -0
  24. package/dist/validator.d.mts +4 -0
  25. package/dist/validator.mjs +3 -0
  26. package/package.json +11 -6
  27. /package/dist/{control-DRgryKeg.cjs → control-D1QdBO21.cjs} +0 -0
  28. /package/dist/{control-IANbnfjG.mjs → control-DBd_ff5-.mjs} +0 -0
  29. /package/dist/{db-validator-plugin-BLMVdi9z.d.mts → db-validator-plugin-KC4aNIQq.d.mts} +0 -0
  30. /package/dist/{ops-BdRAFLKY.d.mts → ops-DcHDxrjX.d.mts} +0 -0
  31. /package/dist/{validation-utils-DVJDijnB.cjs → validation-utils-BiG3pLP0.cjs} +0 -0
  32. /package/dist/{validation-utils-DhjIjP1-.mjs → validation-utils-aNrgK-cj.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { u as TFieldOps } from "./ops-BdRAFLKY.mjs";
1
+ import { u as TFieldOps } from "./ops-DcHDxrjX.mjs";
2
2
  import { FlatOf, NavPropsOf, NavPropsOf as NavPropsOf$1, OwnPropsOf, OwnPropsOf as OwnPropsOf$1, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, TAtscriptTypeObject, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
3
3
  import { AggregateControls, AggregateExpr, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateQuery, AggregateQuery as AggregateQuery$1, AggregateResult, FieldOpsFor, FilterExpr, FilterExpr as FilterExpr$1, TypedWithRelation, Uniquery, Uniquery as Uniquery$1, UniqueryControls, UniqueryControls as UniqueryControls$1, UniqueryInsights, WithRelation, WithRelation as WithRelation$1 } from "@uniqu/core";
4
4
 
@@ -1,4 +1,4 @@
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";
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-D9odJuSf.mjs";
2
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
3
  import { FilterExpr } from "@uniqu/core";
4
4
 
@@ -1,7 +1,8 @@
1
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
- import { isDbFieldOp, separateFieldOps } from "./ops.mjs";
4
+ import { separateFieldOps } from "./ops.mjs";
5
+ import { i as forceNavNonOptional, r as dbPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-D_7Fqzs4.mjs";
5
6
  import { flattenAnnotatedType, isAnnotatedType } from "@atscript/typescript/utils";
6
7
  import { AsyncLocalStorage } from "node:async_hooks";
7
8
  //#region src/logger.ts
@@ -2106,224 +2107,6 @@ var ApplicationIntegrity = class extends IntegrityStrategy {
2106
2107
  }
2107
2108
  };
2108
2109
  //#endregion
2109
- //#region src/patch/patch-types.ts
2110
- /**
2111
- * Extracts `@expect.array.key` properties from an array-of-objects type.
2112
- * These keys uniquely identify an element inside the array and are used
2113
- * for `$update`, `$remove`, and `$upsert` operations.
2114
- *
2115
- * @param def - Atscript array type definition.
2116
- * @returns Set of property names marked as keys; empty set if none.
2117
- */
2118
- function getKeyProps(def) {
2119
- if (def.type.of.type.kind === "object") {
2120
- const objType = def.type.of.type;
2121
- const keyProps = /* @__PURE__ */ new Set();
2122
- for (const [key, val] of objType.props.entries()) if (val.metadata.get("expect.array.key")) keyProps.add(key);
2123
- return keyProps;
2124
- }
2125
- return /* @__PURE__ */ new Set();
2126
- }
2127
- //#endregion
2128
- //#region src/db-validator-plugin.ts
2129
- /** Set of recognised array‑patch operator keys. */
2130
- const PATCH_OPS = new Set([
2131
- "$replace",
2132
- "$insert",
2133
- "$upsert",
2134
- "$update",
2135
- "$remove"
2136
- ]);
2137
- /**
2138
- * Returns `true` when `value` looks like a patch‑operator object
2139
- * (at least one key is a recognised operator and no unknown keys).
2140
- */
2141
- function isPatchOperatorObject(value) {
2142
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
2143
- const keys = Object.keys(value);
2144
- if (keys.length === 0) return false;
2145
- return keys.every((k) => PATCH_OPS.has(k));
2146
- }
2147
- /**
2148
- * Validator plugin for database operations.
2149
- *
2150
- * Handles navigation field constraints and delegates to the standard validator
2151
- * for type checking. The annotated type tree already includes nav fields with
2152
- * their full target types — this plugin controls WHEN recursion is allowed
2153
- * based on the operation mode (insert/replace/patch).
2154
- *
2155
- * Replaces the old `navFieldsValidatorPlugin` (which blindly skipped all nav
2156
- * fields) and `_checkNavProps()` (which validated constraints separately).
2157
- */
2158
- function createDbValidatorPlugin() {
2159
- return (ctx, def, value) => {
2160
- const dbCtx = ctx.context;
2161
- if (!dbCtx) return;
2162
- const isTo = def.metadata.has("db.rel.to");
2163
- const isFrom = def.metadata.has("db.rel.from");
2164
- const isVia = def.metadata.has("db.rel.via");
2165
- if (isTo || isFrom || isVia) return handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia);
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
- }
2182
- }
2183
- };
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
- }
2209
- function handleNavField(ctx, def, value, dbCtx, isTo, isFrom, isVia) {
2210
- const dotIdx = ctx.path.lastIndexOf(".");
2211
- const fieldName = dotIdx === -1 ? ctx.path : ctx.path.slice(dotIdx + 1);
2212
- if (value === null) {
2213
- ctx.error(`Cannot process null navigation property '${fieldName}'`);
2214
- return false;
2215
- }
2216
- if (value === void 0) return true;
2217
- if (dbCtx.mode === "patch") {
2218
- if (isFrom || isVia) {
2219
- if (isPatchOperatorObject(value)) return validateNavPatchOps(ctx, def, value, fieldName);
2220
- const relType = isFrom ? "1:N" : "M:N";
2221
- ctx.error(`Cannot patch ${relType} relation '${fieldName}' with a plain value — use patch operators ({ $insert, $remove, $replace, $update, $upsert })`);
2222
- return false;
2223
- }
2224
- }
2225
- if (isVia) return true;
2226
- }
2227
- /**
2228
- * Validates patch operator values against the nav field's target array type.
2229
- * Each operator's items are validated against the element type.
2230
- */
2231
- function validateNavPatchOps(ctx, def, ops, fieldName) {
2232
- if (def.type.kind !== "array") {
2233
- ctx.error(`Cannot use patch operators on non-array relation '${fieldName}'`);
2234
- return false;
2235
- }
2236
- const arrayDef = def;
2237
- for (const op of [
2238
- "$replace",
2239
- "$insert",
2240
- "$upsert"
2241
- ]) if (ops[op] !== void 0) {
2242
- if (!ctx.validateAnnotatedType(arrayDef, ops[op])) return false;
2243
- }
2244
- for (const op of ["$update", "$remove"]) if (ops[op] !== void 0) {
2245
- if (!validatePartialItems(ctx, arrayDef, ops[op], op, true)) return false;
2246
- }
2247
- return true;
2248
- }
2249
- /**
2250
- * Handles patch‑mode validation for top‑level embedded arrays.
2251
- *
2252
- * When the incoming value is:
2253
- * - A plain array → falls through to default array validation ($replace semantics)
2254
- * - A patch operator object → validates each operator's payload individually
2255
- */
2256
- function handleArrayPatch(ctx, def, value) {
2257
- if (Array.isArray(value)) return;
2258
- if (typeof value !== "object" || value === null) return;
2259
- const ops = value;
2260
- const keys = Object.keys(ops);
2261
- if (keys.length === 0 || !keys.every((k) => PATCH_OPS.has(k))) {
2262
- if (keys.some((k) => PATCH_OPS.has(k))) {
2263
- const unknown = keys.filter((k) => !PATCH_OPS.has(k));
2264
- ctx.error(`Unknown patch operator(s): ${unknown.join(", ")}. Allowed: $replace, $insert, $upsert, $update, $remove`);
2265
- return false;
2266
- }
2267
- return;
2268
- }
2269
- for (const op of [
2270
- "$replace",
2271
- "$insert",
2272
- "$upsert"
2273
- ]) if (ops[op] !== void 0) {
2274
- if (!ctx.validateAnnotatedType(def, ops[op])) return false;
2275
- }
2276
- const isMerge = def.metadata.get("db.patch.strategy") === "merge";
2277
- for (const op of ["$update", "$remove"]) if (ops[op] !== void 0) {
2278
- if (!validatePartialItems(ctx, def, ops[op], op, isMerge)) return false;
2279
- }
2280
- return true;
2281
- }
2282
- /**
2283
- * Validates `$update` / `$remove` items.
2284
- *
2285
- * Each item must be an object. For object arrays with `@expect.array.key` fields,
2286
- * key properties are required and non‑key properties are validated but optional.
2287
- * For primitive arrays, items are validated directly against the element type.
2288
- */
2289
- function validatePartialItems(ctx, arrayDef, items, op, isMerge) {
2290
- if (!Array.isArray(items)) {
2291
- ctx.error(`${op} must be an array`);
2292
- return false;
2293
- }
2294
- const elementDef = arrayDef.type.of;
2295
- if (elementDef.type.kind !== "object") return ctx.validateAnnotatedType(arrayDef, items);
2296
- const keyProps = getKeyProps(arrayDef);
2297
- for (let i = 0; i < items.length; i++) {
2298
- const item = items[i];
2299
- if (typeof item !== "object" || item === null || Array.isArray(item)) {
2300
- ctx.error(`${op}[${i}]: expected object`);
2301
- return false;
2302
- }
2303
- const rec = item;
2304
- if (keyProps.size > 0) {
2305
- for (const kp of keyProps) if (rec[kp] === void 0 || rec[kp] === null) {
2306
- ctx.error(`${op}[${i}]: key field '${kp}' is required`);
2307
- return false;
2308
- }
2309
- }
2310
- const objType = elementDef.type;
2311
- for (const [key, val] of Object.entries(rec)) {
2312
- const propDef = objType.props.get(key);
2313
- if (propDef) {
2314
- if (!ctx.validateAnnotatedType(propDef, val)) return false;
2315
- }
2316
- }
2317
- if (op === "$update" && isMerge !== true) {
2318
- for (const [propName, propDef] of objType.props) if (!propDef.optional && !keyProps.has(propName) && rec[propName] === void 0) {
2319
- ctx.error(`${op}[${i}]: field '${propName}' is required (replace strategy)`);
2320
- return false;
2321
- }
2322
- }
2323
- }
2324
- return true;
2325
- }
2326
- //#endregion
2327
2110
  //#region src/patch/array-ops-resolver.ts
2328
2111
  /**
2329
2112
  * Resolves array patch operator keys (`__$insert`, `__$remove`, `__$upsert`,
@@ -2562,25 +2345,6 @@ function _translateOpsKeys(ops, meta) {
2562
2345
  mul: ops.mul ? _translateOpsRecord(ops.mul, meta) : void 0
2563
2346
  };
2564
2347
  }
2565
- /**
2566
- * Forces nav fields non-optional so the plugin handles null/undefined
2567
- * checks (validator skips optional+null before plugins run).
2568
- */
2569
- function forceNavNonOptional(type) {
2570
- if (type.metadata?.has("db.rel.to") || type.metadata?.has("db.rel.from") || type.metadata?.has("db.rel.via")) return type.optional ? {
2571
- ...type,
2572
- optional: false
2573
- } : type;
2574
- return type;
2575
- }
2576
- /** Makes PK, defaulted, and FK fields optional; forces nav fields non-optional. */
2577
- function insertReplace(type) {
2578
- if (type.metadata?.has("meta.id") || type.metadata?.has("db.default") || type.metadata?.has("db.default.increment") || type.metadata?.has("db.default.uuid") || type.metadata?.has("db.default.now") || type.metadata?.has("db.rel.FK")) return {
2579
- ...type,
2580
- optional: true
2581
- };
2582
- return forceNavNonOptional(type);
2583
- }
2584
2348
  var AtscriptDbTable = class extends AtscriptDbReadable {
2585
2349
  _cascadeResolver;
2586
2350
  _fkLookupResolver;
@@ -2939,37 +2703,26 @@ var AtscriptDbTable = class extends AtscriptDbReadable {
2939
2703
  * (including inside nav field target types).
2940
2704
  */
2941
2705
  _buildValidator(purpose) {
2942
- const dbPlugin = createDbValidatorPlugin();
2943
- const plugins = [...this.adapter.getValidatorPlugins(), dbPlugin];
2944
- switch (purpose) {
2945
- case "insert": return this.createValidator({
2946
- plugins,
2947
- replace: insertReplace
2948
- });
2949
- case "patch": return this.createValidator({
2706
+ const adapterPlugins = this.adapter.getValidatorPlugins();
2707
+ if (purpose === "insert" || purpose === "patch" || purpose === "bulkReplace") {
2708
+ const mode = purpose === "bulkReplace" ? "replace" : purpose;
2709
+ return buildDbValidator(this.type, mode, adapterPlugins);
2710
+ }
2711
+ if (purpose === "bulkUpdate") {
2712
+ const plugins = adapterPlugins.length ? [...adapterPlugins, dbPlugin] : [dbPlugin];
2713
+ const navFields = this._meta.navFields;
2714
+ return this.createValidator({
2950
2715
  plugins,
2951
- partial: true,
2716
+ partial: (_def, path) => {
2717
+ if (path === "") return true;
2718
+ const root = path.split(".")[0];
2719
+ if (navFields.has(root)) return true;
2720
+ return _def.metadata.get("db.patch.strategy") === "merge";
2721
+ },
2952
2722
  replace: forceNavNonOptional
2953
2723
  });
2954
- case "bulkReplace": return this.createValidator({
2955
- plugins,
2956
- replace: insertReplace
2957
- });
2958
- case "bulkUpdate": {
2959
- const navFields = this._meta.navFields;
2960
- return this.createValidator({
2961
- plugins,
2962
- partial: (_def, path) => {
2963
- if (path === "") return true;
2964
- const root = path.split(".")[0];
2965
- if (navFields.has(root)) return true;
2966
- return _def.metadata.get("db.patch.strategy") === "merge";
2967
- },
2968
- replace: forceNavNonOptional
2969
- });
2970
- }
2971
- default: return this.createValidator({ plugins });
2972
2724
  }
2725
+ return this.createValidator({ plugins: adapterPlugins });
2973
2726
  }
2974
2727
  };
2975
2728
  //#endregion
@@ -3106,4 +2859,4 @@ var AtscriptDbView = class extends AtscriptDbReadable {
3106
2859
  }
3107
2860
  };
3108
2861
  //#endregion
3109
- export { NoopLogger as _, getKeyProps as a, IntegrityStrategy as c, resolveDesignType as d, RelationalFieldMapper as f, TableMetadata as g, UniquSelect as h, createDbValidatorPlugin as i, NativeIntegrity as l, FieldMappingStrategy as m, AtscriptDbTable as n, ApplicationIntegrity as o, DocumentFieldMapper as p, decomposePatch as r, BaseDbAdapter as s, AtscriptDbView as t, AtscriptDbReadable as u };
2862
+ export { BaseDbAdapter as a, AtscriptDbReadable as c, DocumentFieldMapper as d, FieldMappingStrategy as f, NoopLogger as h, ApplicationIntegrity as i, resolveDesignType as l, TableMetadata as m, AtscriptDbTable as n, IntegrityStrategy as o, UniquSelect as p, decomposePatch as r, NativeIntegrity as s, AtscriptDbView as t, RelationalFieldMapper as u };