@atscript/db 0.1.146 → 0.1.148

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 (59) hide show
  1. package/dist/{agg-CV7y8nC6.d.cts → agg-42CSpGDR.d.cts} +2 -2
  2. package/dist/{agg-D5DHsAby.d.mts → agg-Wo-smrYV.d.mts} +3 -3
  3. package/dist/agg.cjs +1 -1
  4. package/dist/agg.d.cts +2 -2
  5. package/dist/agg.d.mts +2 -2
  6. package/dist/agg.mjs +1 -1
  7. package/dist/{aggregate-fns-CGBv3E8S.cjs → aggregate-fns-C-UJRobm.cjs} +52 -5
  8. package/dist/{aggregate-fns-CfsveE1w.mjs → aggregate-fns-CyaZyb9I.mjs} +35 -6
  9. package/dist/aggregate-rules-D_bsCpUI.cjs +26 -0
  10. package/dist/aggregate-rules-jdPrxqWa.mjs +15 -0
  11. package/dist/{buckets-DRycmhOW.d.mts → buckets-CNdTOnei.d.mts} +832 -33
  12. package/dist/{buckets-DYFu0eZ8.d.cts → buckets-DJiYlMXc.d.cts} +832 -33
  13. package/dist/{column-diff-D_Kyuh0S.cjs → column-diff-CUU4GvYg.cjs} +1546 -193
  14. package/dist/{column-diff-e2oHc71_.mjs → column-diff-Cp6ZoyRE.mjs} +1529 -200
  15. package/dist/{db-error-D5uilS_A.mjs → db-error-Az85UhTX.mjs} +32 -1
  16. package/dist/{db-error-DTkkeu5b.cjs → db-error-DRQH4sLY.cjs} +55 -0
  17. package/dist/{column-diff-Q9UmWn5x.d.mts → fk-diff-BQ4krij8.d.cts} +48 -2
  18. package/dist/{column-diff-w-Mym_3w.d.cts → fk-diff-DsaIijVX.d.mts} +48 -2
  19. package/dist/index.cjs +95 -35
  20. package/dist/index.d.cts +92 -22
  21. package/dist/index.d.mts +92 -22
  22. package/dist/index.mjs +65 -35
  23. package/dist/{nested-writer-xfQwxplL.cjs → nested-writer-BUQvk6QT.cjs} +734 -2
  24. package/dist/{nested-writer-CnOOAehr.mjs → nested-writer-CUBoq1ZO.mjs} +598 -4
  25. package/dist/numeric-operand-B1jKH7x5.mjs +21 -0
  26. package/dist/numeric-operand-DKfiRLYp.cjs +26 -0
  27. package/dist/ops.cjs +1 -1
  28. package/dist/ops.mjs +1 -1
  29. package/dist/plugin.cjs +293 -5
  30. package/dist/plugin.mjs +294 -6
  31. package/dist/rel.cjs +2 -2
  32. package/dist/rel.d.cts +2 -2
  33. package/dist/rel.d.mts +2 -2
  34. package/dist/rel.mjs +2 -2
  35. package/dist/{relation-helpers-B-0NRKat.d.mts → relation-helpers-Ba0v49sn.d.mts} +1 -1
  36. package/dist/{relation-helpers-BOMm_HUI.d.cts → relation-helpers-kX7jjgME.d.cts} +1 -1
  37. package/dist/relation-loader-ByY1Byrl.mjs +370 -0
  38. package/dist/relation-loader-D8OrdH-r.cjs +369 -0
  39. package/dist/shared.cjs +4 -1
  40. package/dist/shared.d.cts +16 -4
  41. package/dist/shared.d.mts +16 -4
  42. package/dist/shared.mjs +3 -2
  43. package/dist/sync.cjs +11 -7
  44. package/dist/sync.d.cts +2 -25
  45. package/dist/sync.d.mts +2 -25
  46. package/dist/sync.mjs +11 -7
  47. package/dist/{validation-utils-DOsB4e6G.cjs → validation-utils-Da2GjobR.cjs} +35 -24
  48. package/dist/{validation-utils-CMR4fe2M.mjs → validation-utils-Dq0uZ7ef.mjs} +35 -24
  49. package/dist/{validator-Clu2q_7z.mjs → validator-BTiIOTKP.mjs} +9 -3
  50. package/dist/{validator-CVS-onRg.cjs → validator-UcuJxHNT.cjs} +8 -2
  51. package/dist/{validator-Bw6ks9Hy.d.mts → validator-tBNvM1qc.d.cts} +31 -7
  52. package/dist/{validator-Bw6ks9Hy.d.cts → validator-tBNvM1qc.d.mts} +31 -7
  53. package/dist/validator.cjs +2 -2
  54. package/dist/validator.d.cts +1 -1
  55. package/dist/validator.d.mts +1 -1
  56. package/dist/validator.mjs +2 -2
  57. package/package.json +8 -8
  58. package/dist/relation-loader-CBPY6kM7.cjs +0 -461
  59. package/dist/relation-loader-D9XuXaMv.mjs +0 -462
package/dist/sync.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { r as DbError } from "./db-error-D5uilS_A.mjs";
2
- import { a as hasForeignKeyChanges, c as computeTableHash, d as snapshotToExistingColumns, f as snapshotToExistingTableOptions, i as fkKey, l as computeTableSnapshot, o as canonicalizeQueryNode, p as viewSnapshotSources, r as computeForeignKeyDiff, s as computeSchemaHash, st as NoopLogger, t as computeColumnDiff, tt as aliasTargetOf, u as computeViewSnapshot } from "./column-diff-e2oHc71_.mjs";
1
+ import { r as DbError } from "./db-error-Az85UhTX.mjs";
2
+ import { a as computeTableHash, at as aliasTargetOf, c as snapshotToExistingColumns, d as computeForeignKeyDiff, dt as NoopLogger, f as fkColumns, i as computeSchemaHash, l as snapshotToExistingTableOptions, m as hasForeignKeyChanges, o as computeTableSnapshot, p as fkKey, r as canonicalizeQueryNode, s as computeViewSnapshot, t as computeColumnDiff, u as viewSnapshotSources } from "./column-diff-Cp6ZoyRE.mjs";
3
3
  //#region src/schema/table-option-diff.ts
4
4
  /**
5
5
  * Computes the difference between desired and existing table options.
@@ -744,7 +744,7 @@ async function executeSyncTable(facts, safe, deps, exec) {
744
744
  };
745
745
  } else {
746
746
  if (hasFkChanges && fkDiff && adapter.dropForeignKeys) {
747
- const keysToDrop = [...fkDiff.removed.map((fk) => fkKey(fk.fields)), ...fkDiff.changed.map((fk) => fkKey(fk.desired.fields))];
747
+ const keysToDrop = [...fkDiff.removed.map((fk) => fkKey(fk.fields)), ...fkDiff.changed.map((fk) => fkKey(fkColumns(fk.desired).fields))];
748
748
  if (keysToDrop.length > 0) {
749
749
  await adapter.dropForeignKeys(keysToDrop);
750
750
  droppedFks.push(...keysToDrop);
@@ -1610,7 +1610,7 @@ var SchemaSync = class {
1610
1610
  const fkDiff = facts.fkDiff;
1611
1611
  init.status = "alter";
1612
1612
  init.fkAdded = fkDiff.added.map((fk) => ({
1613
- fields: fk.fields,
1613
+ fields: fkColumns(fk).fields,
1614
1614
  targetTable: fk.targetTable
1615
1615
  }));
1616
1616
  init.fkRemoved = fkDiff.removed.map((fk) => ({
@@ -1618,9 +1618,12 @@ var SchemaSync = class {
1618
1618
  targetTable: fk.targetTable
1619
1619
  }));
1620
1620
  init.fkChanged = fkDiff.changed.map((fk) => ({
1621
- fields: fk.desired.fields,
1621
+ fields: fkColumns(fk.desired).fields,
1622
1622
  targetTable: fk.desired.targetTable,
1623
- details: buildFkChangeDetails(fk.desired, fk.existing)
1623
+ details: buildFkChangeDetails({
1624
+ ...fk.desired,
1625
+ targetFields: fkColumns(fk.desired).targetFields
1626
+ }, fk.existing)
1624
1627
  }));
1625
1628
  }
1626
1629
  if (facts.diff?.primaryKeyChanged) facts.populated = await adapter.hasRows(pendingRename ? dbName : void 0) ?? "unknown";
@@ -1658,7 +1661,7 @@ var SchemaSync = class {
1658
1661
  addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but the referencing table "${child.name}" is renamed in the same run (from "${child.pendingRename}") — rename it in a separate run first, then retarget the foreign key and re-run.`);
1659
1662
  continue;
1660
1663
  }
1661
- if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && fkKey(desired.fields) === fkKey(fk.fields) && fkKey(desired.targetFields) === fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
1664
+ if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && fkKey(fkColumns(desired).fields) === fkKey(fk.fields) && fkKey(fkColumns(desired).targetFields) === fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
1662
1665
  }
1663
1666
  for (const f of t.readable.fieldDescriptors) if (!f.ignored && !f.isPrimaryKey && f.defaultValue?.kind === "fn" && f.defaultValue.fn === "increment") addRefusal(refusals, t.name, `"${t.name}.${f.physicalName}" is auto-increment but no longer part of the primary key; auto-increment columns must be primary-key columns.`);
1664
1667
  }
@@ -1673,6 +1676,7 @@ var SchemaSync = class {
1673
1676
  if (d.viewObjectKinds.get(view.tableName) === "table") addRefusal(refusals, view.tableName, `A physical table "${view.tableName}" exists where managed view "${view.tableName}" is declared — drop or rename it`);
1674
1677
  const fns = view.dbAdapter.aggregateFns();
1675
1678
  for (const col of view.getViewColumnMappings()) if (col.aggFn && !fns.has(col.aggFn)) addRefusal(refusals, view.tableName, `View "${view.tableName}" field "${col.viewPath}": aggregate "${col.aggFn}" is not supported by this adapter (aggregateFns())`);
1679
+ for (const problem of view.viewCapabilityProblems()) addRefusal(refusals, view.tableName, problem);
1676
1680
  for (const source of d.viewSources.get(view.tableName)) if (d.externalTargets.get(source) === false) addRefusal(refusals, view.tableName, `View "${view.tableName}" reads "${source}" which is neither in the sync inventory nor present in the database`);
1677
1681
  }
1678
1682
  if (!safe) for (const r of d.removed) {
@@ -344,44 +344,55 @@ function hasAnyViewAnnotation(node) {
344
344
  return viewAnnotationNames.some((name) => node.countAnnotations(name) > 0);
345
345
  }
346
346
  /**
347
- * Validate that all field refs in a query expression are within `scope` —
348
- * the same {@link TQueryScope} the editor completes (`lsp-scopes`):
347
+ * Every field ref of a backtick argument — a predicate (`queryNode`), an
348
+ * arithmetic expression (`exprNode`) or an ordering (`orderNode`) — in source
349
+ * order. `[]` when the argument did not parse.
350
+ * @since 0.1.147
351
+ */
352
+ function backtickFieldRefs(token) {
353
+ if (token.queryNode) {
354
+ const refs = [];
355
+ forEachFieldRef(token.queryNode.expression, (ref) => refs.push(ref));
356
+ return refs;
357
+ }
358
+ return (token.exprNode ?? token.orderNode)?.fieldRefs() ?? [];
359
+ }
360
+ /**
361
+ * Validate that all field refs in a backtick argument (a query, an `expr` or
362
+ * an `order`) are within `scope` — the same {@link TQueryScope} the editor
363
+ * completes (`lsp-scopes`):
349
364
  * qualified refs must name one of `scope.allowedTypes`; an unqualified ref
350
365
  * (a dotted path included) must be a field of `scope.unqualifiedTarget`, or
351
366
  * is rejected outright when that is `null`.
352
367
  *
353
- * @param queryToken - The query arg token (must have .queryNode)
368
+ * @param queryToken - The backtick arg token (with `.queryNode`, `.exprNode` or `.orderNode`)
354
369
  * @param scope - The scope of the argument
355
370
  * @param doc - The document for type lookups
356
371
  * @param scopeHint - Replaces the default "expected 'A' or 'B'" tail of the out-of-scope message
357
372
  */
358
373
  function validateQueryScope(queryToken, scope, doc, scopeHint) {
359
374
  const errors = [];
360
- const queryNode = queryToken.queryNode;
361
- if (!queryNode) return errors;
362
375
  const { allowedTypes, unqualifiedTarget } = scope;
363
- forEachFieldRef(queryNode.expression, (ref) => {
364
- if (ref.typeRef) {
365
- const typeName = ref.typeRef.text;
366
- if (!allowedTypes.includes(typeName)) errors.push({
367
- message: `Query references '${typeName}' which is not in scope — ${scopeHint ?? `expected ${allowedTypes.map((t) => `'${t}'`).join(" or ")}`}`,
368
- severity: 1,
369
- range: ref.typeRef.range
370
- });
371
- } else if (unqualifiedTarget === null) errors.push({
372
- message: `Unqualified field reference '${ref.fieldRef.text}' — use qualified form (e.g., Type.${ref.fieldRef.text})`,
376
+ for (const ref of backtickFieldRefs(queryToken)) if (ref.typeRef) {
377
+ const typeName = ref.typeRef.text;
378
+ if (!allowedTypes.includes(typeName)) errors.push({
379
+ message: `Query references '${typeName}' which is not in scope — ${scopeHint ?? `expected ${allowedTypes.map((t) => `'${t}'`).join(" or ")}`}`,
373
380
  severity: 1,
374
- range: ref.fieldRef.range
381
+ range: ref.typeRef.range
375
382
  });
376
- else {
377
- const targetDef = doc.unwindType(unqualifiedTarget)?.def;
378
- if (targetDef && ((0, _atscript_core.isInterface)(targetDef) || (0, _atscript_core.isStructure)(targetDef)) && !doc.unwindType(unqualifiedTarget, ref.fieldRef.text.split("."))) errors.push({
379
- message: `Field '${ref.fieldRef.text}' does not exist on '${unqualifiedTarget}'`,
380
- severity: 1,
381
- range: ref.fieldRef.range
382
- });
383
- }
383
+ } else if (unqualifiedTarget === null) errors.push({
384
+ message: `Unqualified field reference '${ref.fieldRef.text}' — use qualified form (e.g., Type.${ref.fieldRef.text})`,
385
+ severity: 1,
386
+ range: ref.fieldRef.range
384
387
  });
388
+ else {
389
+ const targetDef = doc.unwindType(unqualifiedTarget)?.def;
390
+ if (targetDef && ((0, _atscript_core.isInterface)(targetDef) || (0, _atscript_core.isStructure)(targetDef)) && !doc.unwindType(unqualifiedTarget, ref.fieldRef.text.split("."))) errors.push({
391
+ message: `Field '${ref.fieldRef.text}' does not exist on '${unqualifiedTarget}'`,
392
+ severity: 1,
393
+ range: ref.fieldRef.range
394
+ });
395
+ }
385
396
  return errors;
386
397
  }
387
398
  /**
@@ -344,44 +344,55 @@ function hasAnyViewAnnotation(node) {
344
344
  return viewAnnotationNames.some((name) => node.countAnnotations(name) > 0);
345
345
  }
346
346
  /**
347
- * Validate that all field refs in a query expression are within `scope` —
348
- * the same {@link TQueryScope} the editor completes (`lsp-scopes`):
347
+ * Every field ref of a backtick argument — a predicate (`queryNode`), an
348
+ * arithmetic expression (`exprNode`) or an ordering (`orderNode`) — in source
349
+ * order. `[]` when the argument did not parse.
350
+ * @since 0.1.147
351
+ */
352
+ function backtickFieldRefs(token) {
353
+ if (token.queryNode) {
354
+ const refs = [];
355
+ forEachFieldRef(token.queryNode.expression, (ref) => refs.push(ref));
356
+ return refs;
357
+ }
358
+ return (token.exprNode ?? token.orderNode)?.fieldRefs() ?? [];
359
+ }
360
+ /**
361
+ * Validate that all field refs in a backtick argument (a query, an `expr` or
362
+ * an `order`) are within `scope` — the same {@link TQueryScope} the editor
363
+ * completes (`lsp-scopes`):
349
364
  * qualified refs must name one of `scope.allowedTypes`; an unqualified ref
350
365
  * (a dotted path included) must be a field of `scope.unqualifiedTarget`, or
351
366
  * is rejected outright when that is `null`.
352
367
  *
353
- * @param queryToken - The query arg token (must have .queryNode)
368
+ * @param queryToken - The backtick arg token (with `.queryNode`, `.exprNode` or `.orderNode`)
354
369
  * @param scope - The scope of the argument
355
370
  * @param doc - The document for type lookups
356
371
  * @param scopeHint - Replaces the default "expected 'A' or 'B'" tail of the out-of-scope message
357
372
  */
358
373
  function validateQueryScope(queryToken, scope, doc, scopeHint) {
359
374
  const errors = [];
360
- const queryNode = queryToken.queryNode;
361
- if (!queryNode) return errors;
362
375
  const { allowedTypes, unqualifiedTarget } = scope;
363
- forEachFieldRef(queryNode.expression, (ref) => {
364
- if (ref.typeRef) {
365
- const typeName = ref.typeRef.text;
366
- if (!allowedTypes.includes(typeName)) errors.push({
367
- message: `Query references '${typeName}' which is not in scope — ${scopeHint ?? `expected ${allowedTypes.map((t) => `'${t}'`).join(" or ")}`}`,
368
- severity: 1,
369
- range: ref.typeRef.range
370
- });
371
- } else if (unqualifiedTarget === null) errors.push({
372
- message: `Unqualified field reference '${ref.fieldRef.text}' — use qualified form (e.g., Type.${ref.fieldRef.text})`,
376
+ for (const ref of backtickFieldRefs(queryToken)) if (ref.typeRef) {
377
+ const typeName = ref.typeRef.text;
378
+ if (!allowedTypes.includes(typeName)) errors.push({
379
+ message: `Query references '${typeName}' which is not in scope — ${scopeHint ?? `expected ${allowedTypes.map((t) => `'${t}'`).join(" or ")}`}`,
373
380
  severity: 1,
374
- range: ref.fieldRef.range
381
+ range: ref.typeRef.range
375
382
  });
376
- else {
377
- const targetDef = doc.unwindType(unqualifiedTarget)?.def;
378
- if (targetDef && (isInterface(targetDef) || isStructure(targetDef)) && !doc.unwindType(unqualifiedTarget, ref.fieldRef.text.split("."))) errors.push({
379
- message: `Field '${ref.fieldRef.text}' does not exist on '${unqualifiedTarget}'`,
380
- severity: 1,
381
- range: ref.fieldRef.range
382
- });
383
- }
383
+ } else if (unqualifiedTarget === null) errors.push({
384
+ message: `Unqualified field reference '${ref.fieldRef.text}' — use qualified form (e.g., Type.${ref.fieldRef.text})`,
385
+ severity: 1,
386
+ range: ref.fieldRef.range
384
387
  });
388
+ else {
389
+ const targetDef = doc.unwindType(unqualifiedTarget)?.def;
390
+ if (targetDef && (isInterface(targetDef) || isStructure(targetDef)) && !doc.unwindType(unqualifiedTarget, ref.fieldRef.text.split("."))) errors.push({
391
+ message: `Field '${ref.fieldRef.text}' does not exist on '${unqualifiedTarget}'`,
392
+ severity: 1,
393
+ range: ref.fieldRef.range
394
+ });
395
+ }
385
396
  return errors;
386
397
  }
387
398
  /**
@@ -1,5 +1,5 @@
1
- import { i as DepthLimitExceededError } from "./db-error-D5uilS_A.mjs";
2
- import { isDbFieldOp } from "./ops.mjs";
1
+ import { i as DepthLimitExceededError } from "./db-error-Az85UhTX.mjs";
2
+ import { getDbFieldOp } from "./ops.mjs";
3
3
  import { flattenAnnotatedType } from "@atscript/typescript/utils";
4
4
  //#region src/patch/patch-types.ts
5
5
  /**
@@ -83,7 +83,8 @@ function createDbValidatorPlugin() {
83
83
  }
84
84
  }
85
85
  if (dbCtx.mode === "patch") {
86
- if (isDbFieldOp(value)) {
86
+ const fieldOp = getDbFieldOp(value);
87
+ if (fieldOp) {
87
88
  if (def.metadata.has("db.column.derived")) {
88
89
  ctx.error("Field operations ($inc/$dec/$mul) are not allowed on a @db.column.derived field — it is computed from its @db.json source; patch the source leaf instead");
89
90
  return false;
@@ -96,6 +97,11 @@ function createDbValidatorPlugin() {
96
97
  ctx.error("Field operations ($inc/$dec/$mul) can only be applied to numeric fields");
97
98
  return false;
98
99
  }
100
+ const operand = fieldOp.value;
101
+ if (!Number.isFinite(operand)) {
102
+ ctx.error(`Field operation operand must be a finite number, got ${operand}`);
103
+ return false;
104
+ }
99
105
  return true;
100
106
  }
101
107
  if (def.type.kind === "array" && dbCtx.flatMap) {
@@ -1,4 +1,4 @@
1
- const require_db_error = require("./db-error-DTkkeu5b.cjs");
1
+ const require_db_error = require("./db-error-DRQH4sLY.cjs");
2
2
  const require_ops = require("./ops.cjs");
3
3
  let _atscript_typescript_utils = require("@atscript/typescript/utils");
4
4
  //#region src/patch/patch-types.ts
@@ -83,7 +83,8 @@ function createDbValidatorPlugin() {
83
83
  }
84
84
  }
85
85
  if (dbCtx.mode === "patch") {
86
- if (require_ops.isDbFieldOp(value)) {
86
+ const fieldOp = require_ops.getDbFieldOp(value);
87
+ if (fieldOp) {
87
88
  if (def.metadata.has("db.column.derived")) {
88
89
  ctx.error("Field operations ($inc/$dec/$mul) are not allowed on a @db.column.derived field — it is computed from its @db.json source; patch the source leaf instead");
89
90
  return false;
@@ -96,6 +97,11 @@ function createDbValidatorPlugin() {
96
97
  ctx.error("Field operations ($inc/$dec/$mul) can only be applied to numeric fields");
97
98
  return false;
98
99
  }
100
+ const operand = fieldOp.value;
101
+ if (!Number.isFinite(operand)) {
102
+ ctx.error(`Field operation operand must be a finite number, got ${operand}`);
103
+ return false;
104
+ }
99
105
  return true;
100
106
  }
101
107
  if (def.type.kind === "array" && dbCtx.flatMap) {
@@ -1,7 +1,20 @@
1
1
  import { TAtscriptAnnotatedType, TAtscriptTypeArray, TAtscriptTypeObject, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
2
2
 
3
3
  //#region src/db-error.d.ts
4
- type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED" | "VERSION_COLUMN_WRITE" | "CAS_EXHAUSTED" | "CAS_MISMATCH" | "ENC_CONFIG_MISSING" | "ENC_KEY_INVALID" | "ENC_NOT_ENCRYPTED" | "ENC_DECRYPT_FAILED" | "ENC_FIELD_FILTER" | "ENC_FIELD_SORT" | "ENC_FIELD_AGG" | "ENC_FIELD_PATCH_OP" | "GEO_INDEX_MISSING" | "GEO_NOT_SUPPORTED" | "FILTER_TYPE_MISMATCH" /** The adapter's `calendarBucketUnits()` lacks the requested unit (moost-db: 400). */ | "BUCKET_NOT_SUPPORTED" /** The engine cannot resolve the bucket's time zone — a store-configuration condition (moost-db: 501). */ | "BUCKET_TZ_UNAVAILABLE" /** A known aggregate function the adapter's `aggregateFns()` lacks (moost-db: 400). @since 0.1.136 */ | "AGG_FN_NOT_SUPPORTED" | "TX_WAIT_TIMEOUT";
4
+ type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED" | "VERSION_COLUMN_WRITE" | "CAS_EXHAUSTED" | "CAS_MISMATCH" | "ENC_CONFIG_MISSING" | "ENC_KEY_INVALID" | "ENC_NOT_ENCRYPTED" | "ENC_DECRYPT_FAILED" | "ENC_FIELD_FILTER" | "ENC_FIELD_SORT" | "ENC_FIELD_AGG" | "ENC_FIELD_PATCH_OP" | "GEO_INDEX_MISSING" | "GEO_NOT_SUPPORTED" | "FILTER_TYPE_MISMATCH" /** The adapter's `calendarBucketUnits()` lacks the requested unit (moost-db: 400). */ | "BUCKET_NOT_SUPPORTED" /** The engine cannot resolve the bucket's time zone — a store-configuration condition (moost-db: 501). */ | "BUCKET_TZ_UNAVAILABLE" /** A known aggregate function the adapter's `aggregateFns()` lacks (moost-db: 400). @since 0.1.136 */ | "AGG_FN_NOT_SUPPORTED"
5
+ /**
6
+ * The adapter's `supportsAggregateExpressions()` is false and the query uses
7
+ * arithmetic (`{ $expr }`, `{ $fn, $expr }`) in an aggregate `$select`
8
+ * (moost-db: 400). @since 0.1.148
9
+ */
10
+ | "AGG_EXPR_NOT_SUPPORTED"
11
+ /**
12
+ * The adapter (or the table's wiring) cannot run a relational predicate:
13
+ * `supportsRelationFilters()` is false for the read/write mode, the related
14
+ * table lives on a different adapter, or the table was built without a
15
+ * `DbSpace` (moost-db: 400). @since 0.1.147
16
+ */
17
+ | "REL_FILTER_NOT_SUPPORTED" /** The `DbSpace` was closed; the table/view handle can no longer be used (moost-db: 503). @since 0.1.148 */ | "SPACE_CLOSED" /** The adapter does not implement `insertManyIgnore` (moost-db: 400). @since 0.1.148 */ | "ON_CONFLICT_NOT_SUPPORTED" | "TX_WAIT_TIMEOUT";
5
18
  declare class DbError extends Error {
6
19
  readonly code: DbErrorCode;
7
20
  readonly errors: Array<{
@@ -14,6 +27,14 @@ declare class DbError extends Error {
14
27
  message: string;
15
28
  }>, message?: string);
16
29
  }
30
+ /** Whether `error` is a `DbError` with code `CONFLICT` (unique / primary-key violation). */
31
+ declare function isConflict(error: unknown): error is DbError;
32
+ /**
33
+ * Collapses the failures of a multi-step shutdown into one `AggregateError`
34
+ * (message lists every failure).
35
+ * @internal
36
+ */
37
+ declare function aggregateFailure(label: string, errors: unknown[]): AggregateError;
17
38
  /**
18
39
  * Thrown by {@link withOptimisticRetry} when `maxAttempts` is reached
19
40
  * without a successful CAS commit — the target row kept changing under
@@ -39,11 +60,7 @@ declare class CasMismatchError extends DbError {
39
60
  /** Keys passed to `touchMany`. */
40
61
  readonly expected: number;
41
62
  name: string;
42
- constructor(/** Rows whose primary key + version matched. */
43
-
44
- matched: number, /** Keys passed to `touchMany`. */
45
-
46
- expected: number);
63
+ constructor(/** Rows whose primary key + version matched. */matched: number, /** Keys passed to `touchMany`. */expected: number);
47
64
  }
48
65
  /**
49
66
  * The engine cannot resolve a calendar bucket's time zone (`BUCKET_TZ_UNAVAILABLE`,
@@ -52,6 +69,13 @@ declare class CasMismatchError extends DbError {
52
69
  * missing server time zone database — never a malformed query. Since 0.1.132.
53
70
  */
54
71
  declare function bucketTimeZoneUnavailable(message: string): DbError;
72
+ /**
73
+ * The adapter's `supportsAggregateExpressions()` is false (or its SQL dialect
74
+ * cannot cast to a double) and the query uses arithmetic in an aggregate
75
+ * `$select` (`AGG_EXPR_NOT_SUPPORTED`, `path` `$select`; moost-db: 400).
76
+ * @since 0.1.148
77
+ */
78
+ declare function aggregateExpressionsNotSupported(): DbError;
55
79
  //#endregion
56
80
  //#region src/patch/patch-types.d.ts
57
81
  interface TArrayPatch<A extends readonly unknown[]> {
@@ -138,4 +162,4 @@ interface ValidationContext {
138
162
  */
139
163
  declare function buildValidationContext(type: TAtscriptAnnotatedType<TAtscriptTypeObject>): ValidationContext;
140
164
  //#endregion
141
- export { buildValidationContext as a, isNavRelation as c, getKeyProps as d, CasExhaustedError as f, bucketTimeZoneUnavailable as g, DbErrorCode as h, buildPatchPartial as i, TArrayPatch as l, DbError as m, ValidatorMode as n, dbPlugin as o, CasMismatchError as p, buildDbValidator as r, forceNavNonOptional as s, ValidationContext as t, TDbPatch as u };
165
+ export { aggregateFailure as _, buildValidationContext as a, isNavRelation as c, getKeyProps as d, CasExhaustedError as f, aggregateExpressionsNotSupported as g, DbErrorCode as h, buildPatchPartial as i, TArrayPatch as l, DbError as m, ValidatorMode as n, dbPlugin as o, CasMismatchError as p, buildDbValidator as r, forceNavNonOptional as s, ValidationContext as t, TDbPatch as u, bucketTimeZoneUnavailable as v, isConflict as y };
@@ -1,7 +1,20 @@
1
1
  import { TAtscriptAnnotatedType, TAtscriptTypeArray, TAtscriptTypeObject, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
2
2
 
3
3
  //#region src/db-error.d.ts
4
- type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED" | "VERSION_COLUMN_WRITE" | "CAS_EXHAUSTED" | "CAS_MISMATCH" | "ENC_CONFIG_MISSING" | "ENC_KEY_INVALID" | "ENC_NOT_ENCRYPTED" | "ENC_DECRYPT_FAILED" | "ENC_FIELD_FILTER" | "ENC_FIELD_SORT" | "ENC_FIELD_AGG" | "ENC_FIELD_PATCH_OP" | "GEO_INDEX_MISSING" | "GEO_NOT_SUPPORTED" | "FILTER_TYPE_MISMATCH" /** The adapter's `calendarBucketUnits()` lacks the requested unit (moost-db: 400). */ | "BUCKET_NOT_SUPPORTED" /** The engine cannot resolve the bucket's time zone — a store-configuration condition (moost-db: 501). */ | "BUCKET_TZ_UNAVAILABLE" /** A known aggregate function the adapter's `aggregateFns()` lacks (moost-db: 400). @since 0.1.136 */ | "AGG_FN_NOT_SUPPORTED" | "TX_WAIT_TIMEOUT";
4
+ type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" | "INVALID_QUERY" | "DEPTH_EXCEEDED" | "VERSION_COLUMN_WRITE" | "CAS_EXHAUSTED" | "CAS_MISMATCH" | "ENC_CONFIG_MISSING" | "ENC_KEY_INVALID" | "ENC_NOT_ENCRYPTED" | "ENC_DECRYPT_FAILED" | "ENC_FIELD_FILTER" | "ENC_FIELD_SORT" | "ENC_FIELD_AGG" | "ENC_FIELD_PATCH_OP" | "GEO_INDEX_MISSING" | "GEO_NOT_SUPPORTED" | "FILTER_TYPE_MISMATCH" /** The adapter's `calendarBucketUnits()` lacks the requested unit (moost-db: 400). */ | "BUCKET_NOT_SUPPORTED" /** The engine cannot resolve the bucket's time zone — a store-configuration condition (moost-db: 501). */ | "BUCKET_TZ_UNAVAILABLE" /** A known aggregate function the adapter's `aggregateFns()` lacks (moost-db: 400). @since 0.1.136 */ | "AGG_FN_NOT_SUPPORTED"
5
+ /**
6
+ * The adapter's `supportsAggregateExpressions()` is false and the query uses
7
+ * arithmetic (`{ $expr }`, `{ $fn, $expr }`) in an aggregate `$select`
8
+ * (moost-db: 400). @since 0.1.148
9
+ */
10
+ | "AGG_EXPR_NOT_SUPPORTED"
11
+ /**
12
+ * The adapter (or the table's wiring) cannot run a relational predicate:
13
+ * `supportsRelationFilters()` is false for the read/write mode, the related
14
+ * table lives on a different adapter, or the table was built without a
15
+ * `DbSpace` (moost-db: 400). @since 0.1.147
16
+ */
17
+ | "REL_FILTER_NOT_SUPPORTED" /** The `DbSpace` was closed; the table/view handle can no longer be used (moost-db: 503). @since 0.1.148 */ | "SPACE_CLOSED" /** The adapter does not implement `insertManyIgnore` (moost-db: 400). @since 0.1.148 */ | "ON_CONFLICT_NOT_SUPPORTED" | "TX_WAIT_TIMEOUT";
5
18
  declare class DbError extends Error {
6
19
  readonly code: DbErrorCode;
7
20
  readonly errors: Array<{
@@ -14,6 +27,14 @@ declare class DbError extends Error {
14
27
  message: string;
15
28
  }>, message?: string);
16
29
  }
30
+ /** Whether `error` is a `DbError` with code `CONFLICT` (unique / primary-key violation). */
31
+ declare function isConflict(error: unknown): error is DbError;
32
+ /**
33
+ * Collapses the failures of a multi-step shutdown into one `AggregateError`
34
+ * (message lists every failure).
35
+ * @internal
36
+ */
37
+ declare function aggregateFailure(label: string, errors: unknown[]): AggregateError;
17
38
  /**
18
39
  * Thrown by {@link withOptimisticRetry} when `maxAttempts` is reached
19
40
  * without a successful CAS commit — the target row kept changing under
@@ -39,11 +60,7 @@ declare class CasMismatchError extends DbError {
39
60
  /** Keys passed to `touchMany`. */
40
61
  readonly expected: number;
41
62
  name: string;
42
- constructor(/** Rows whose primary key + version matched. */
43
-
44
- matched: number, /** Keys passed to `touchMany`. */
45
-
46
- expected: number);
63
+ constructor(/** Rows whose primary key + version matched. */matched: number, /** Keys passed to `touchMany`. */expected: number);
47
64
  }
48
65
  /**
49
66
  * The engine cannot resolve a calendar bucket's time zone (`BUCKET_TZ_UNAVAILABLE`,
@@ -52,6 +69,13 @@ declare class CasMismatchError extends DbError {
52
69
  * missing server time zone database — never a malformed query. Since 0.1.132.
53
70
  */
54
71
  declare function bucketTimeZoneUnavailable(message: string): DbError;
72
+ /**
73
+ * The adapter's `supportsAggregateExpressions()` is false (or its SQL dialect
74
+ * cannot cast to a double) and the query uses arithmetic in an aggregate
75
+ * `$select` (`AGG_EXPR_NOT_SUPPORTED`, `path` `$select`; moost-db: 400).
76
+ * @since 0.1.148
77
+ */
78
+ declare function aggregateExpressionsNotSupported(): DbError;
55
79
  //#endregion
56
80
  //#region src/patch/patch-types.d.ts
57
81
  interface TArrayPatch<A extends readonly unknown[]> {
@@ -138,4 +162,4 @@ interface ValidationContext {
138
162
  */
139
163
  declare function buildValidationContext(type: TAtscriptAnnotatedType<TAtscriptTypeObject>): ValidationContext;
140
164
  //#endregion
141
- export { buildValidationContext as a, isNavRelation as c, getKeyProps as d, CasExhaustedError as f, bucketTimeZoneUnavailable as g, DbErrorCode as h, buildPatchPartial as i, TArrayPatch as l, DbError as m, ValidatorMode as n, dbPlugin as o, CasMismatchError as p, buildDbValidator as r, forceNavNonOptional as s, ValidationContext as t, TDbPatch as u };
165
+ export { aggregateFailure as _, buildValidationContext as a, isNavRelation as c, getKeyProps as d, CasExhaustedError as f, aggregateExpressionsNotSupported as g, DbErrorCode as h, buildPatchPartial as i, TArrayPatch as l, DbError as m, ValidatorMode as n, dbPlugin as o, CasMismatchError as p, buildDbValidator as r, forceNavNonOptional as s, ValidationContext as t, TDbPatch as u, bucketTimeZoneUnavailable as v, isConflict as y };
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_db_error = require("./db-error-DTkkeu5b.cjs");
2
+ const require_db_error = require("./db-error-DRQH4sLY.cjs");
3
3
  const require_object = require("./object-Djg28csK.cjs");
4
4
  const require_ops = require("./ops.cjs");
5
- const require_validator = require("./validator-CVS-onRg.cjs");
5
+ const require_validator = require("./validator-UcuJxHNT.cjs");
6
6
  exports.$cas = require_ops.$cas;
7
7
  exports.$dec = require_ops.$dec;
8
8
  exports.$inc = require_ops.$inc;
@@ -1,5 +1,5 @@
1
1
  import { a as $mul, c as $update, d as TDbFieldOp, g as separateCas, h as reconcileCas, i as $insert, l as $upsert, m as isDbFieldOp, n as $dec, o as $remove, r as $inc, s as $replace, t as $cas, u as TDbCas } from "./ops-AqhV7s9o.cjs";
2
2
  import { a as isPlainObject, i as isEmptyObject } from "./object-CtPYTIvy.cjs";
3
- import { a as buildValidationContext, c as isNavRelation, d as getKeyProps, i as buildPatchPartial, l as TArrayPatch, m as DbError, n as ValidatorMode, o as dbPlugin, r as buildDbValidator, s as forceNavNonOptional, t as ValidationContext, u as TDbPatch } from "./validator-Bw6ks9Hy.cjs";
3
+ import { a as buildValidationContext, c as isNavRelation, d as getKeyProps, i as buildPatchPartial, l as TArrayPatch, m as DbError, n as ValidatorMode, o as dbPlugin, r as buildDbValidator, s as forceNavNonOptional, t as ValidationContext, u as TDbPatch } from "./validator-tBNvM1qc.cjs";
4
4
  import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-BWy60OvG.cjs";
5
5
  export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, DbError, type DbValidationContext, type TArrayPatch, type TDbCas, type TDbFieldOp, type TDbPatch, ValidationContext, ValidatorMode, buildDbValidator, buildPatchPartial, buildValidationContext, createDbValidatorPlugin, dbPlugin, forceNavNonOptional, getKeyProps, isDbFieldOp, isEmptyObject, isNavRelation, isPlainObject, reconcileCas, separateCas };
@@ -1,5 +1,5 @@
1
1
  import { a as $mul, c as $update, d as TDbFieldOp, g as separateCas, h as reconcileCas, i as $insert, l as $upsert, m as isDbFieldOp, n as $dec, o as $remove, r as $inc, s as $replace, t as $cas, u as TDbCas } from "./ops-AqhV7s9o.mjs";
2
2
  import { a as isPlainObject, i as isEmptyObject } from "./object-CtPYTIvy.mjs";
3
- import { a as buildValidationContext, c as isNavRelation, d as getKeyProps, i as buildPatchPartial, l as TArrayPatch, m as DbError, n as ValidatorMode, o as dbPlugin, r as buildDbValidator, s as forceNavNonOptional, t as ValidationContext, u as TDbPatch } from "./validator-Bw6ks9Hy.mjs";
3
+ import { a as buildValidationContext, c as isNavRelation, d as getKeyProps, i as buildPatchPartial, l as TArrayPatch, m as DbError, n as ValidatorMode, o as dbPlugin, r as buildDbValidator, s as forceNavNonOptional, t as ValidationContext, u as TDbPatch } from "./validator-tBNvM1qc.mjs";
4
4
  import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-validator-plugin-BWy60OvG.mjs";
5
5
  export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, DbError, type DbValidationContext, type TArrayPatch, type TDbCas, type TDbFieldOp, type TDbPatch, ValidationContext, ValidatorMode, buildDbValidator, buildPatchPartial, buildValidationContext, createDbValidatorPlugin, dbPlugin, forceNavNonOptional, getKeyProps, isDbFieldOp, isEmptyObject, isNavRelation, isPlainObject, reconcileCas, separateCas };
@@ -1,5 +1,5 @@
1
- import { r as DbError } from "./db-error-D5uilS_A.mjs";
1
+ import { r as DbError } from "./db-error-Az85UhTX.mjs";
2
2
  import { a as isPlainObject, i as isEmptyObject } from "./object-TkiJQ-Dp.mjs";
3
3
  import { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, isDbFieldOp, reconcileCas, separateCas } from "./ops.mjs";
4
- import { a as forceNavNonOptional, c as getKeyProps, i as dbPlugin, n as buildPatchPartial, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-Clu2q_7z.mjs";
4
+ import { a as forceNavNonOptional, c as getKeyProps, i as dbPlugin, n as buildPatchPartial, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-BTiIOTKP.mjs";
5
5
  export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, DbError, buildDbValidator, buildPatchPartial, buildValidationContext, createDbValidatorPlugin, dbPlugin, forceNavNonOptional, getKeyProps, isDbFieldOp, isEmptyObject, isNavRelation, isPlainObject, reconcileCas, separateCas };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db",
3
- "version": "0.1.146",
3
+ "version": "0.1.148",
4
4
  "description": "Database adapter utilities for atscript.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -71,15 +71,15 @@
71
71
  "access": "public"
72
72
  },
73
73
  "devDependencies": {
74
- "@atscript/core": "^0.1.98",
75
- "@atscript/typescript": "^0.1.98",
76
- "@uniqu/core": "^0.1.11",
77
- "unplugin-atscript": "^0.1.98"
74
+ "@atscript/core": "^0.1.100",
75
+ "@atscript/typescript": "^0.1.100",
76
+ "@uniqu/core": "^0.1.13",
77
+ "unplugin-atscript": "^0.1.100"
78
78
  },
79
79
  "peerDependencies": {
80
- "@atscript/core": "^0.1.98",
81
- "@atscript/typescript": "^0.1.98",
82
- "@uniqu/core": "^0.1.11"
80
+ "@atscript/core": "^0.1.100",
81
+ "@atscript/typescript": "^0.1.100",
82
+ "@uniqu/core": "^0.1.13"
83
83
  },
84
84
  "scripts": {
85
85
  "postinstall": "asc -f dts",