@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/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import { a as bucketTimeZoneUnavailable, n as CasMismatchError, r as DbError, t as CasExhaustedError } from "./db-error-D5uilS_A.mjs";
2
- import { $ as isGeoIndexableType, A as vectorIndexNotFoundMessage, B as guardAggregate, C as createFailureCollector, D as resolveDesignType, E as AtscriptDbReadable, F as bucketSourceVerdict, G as narrowerFilterOps, H as guardPath, I as canFilterLeaf, J as RelationalFieldMapper, K as sortFieldNames, L as checkHavingKeys, M as ENCRYPTED_REASON, N as acceptedOperatorsHint, O as geoIndexNotFoundMessage, P as assertGeoPoint, Q as TableMetadata, R as classifyQueryPath, S as BaseDbAdapter, T as NativeIntegrity, U as guardPaths, V as guardFilter, W as guardQuery, X as FieldMappingStrategy, Y as DocumentFieldMapper, Z as UniquSelect, _ as AtscriptDbTable, at as normalizeComputedSelect, b as ApplicationIntegrity, et as isGeoPointType, g as isViewType, h as isAtscriptDbView, it as jsonValueAncestor, j as ADAPTER_FILTER_REASON, k as searchIndexNotFoundMessage, m as AtscriptDbView, n as isColumnTypeChanged, nt as isBucketableField, ot as resolveCalendarBuckets, q as unsupportedOperatorMessage, rt as isJsonValueField, st as NoopLogger, tt as aliasTargetOf, v as assertNoVersionWrites, w as IntegrityStrategy, x as ALL_BUCKET_UNITS, y as decomposePatch, z as collectQueryPaths } from "./column-diff-e2oHc71_.mjs";
3
- import { t as ALL_AGGREGATE_FNS } from "./aggregate-fns-CfsveE1w.mjs";
4
- import { T as tableNameOf } from "./nested-writer-CnOOAehr.mjs";
1
+ import { a as aggregateExpressionsNotSupported, c as isConflict, l as spaceClosedError, n as CasMismatchError, o as aggregateFailure, r as DbError, s as bucketTimeZoneUnavailable, t as CasExhaustedError } from "./db-error-Az85UhTX.mjs";
2
+ import { $ as FieldMappingStrategy, A as geoIndexNotFoundMessage, B as classifyQueryPath, C as ALL_VIEW_CAPABILITIES, D as NativeIntegrity, E as IntegrityStrategy, F as acceptedOperatorsHint, G as guardPath, H as groupSourceVerdict, I as assertGeoPoint, J as narrowerFilterOps, K as guardPaths, L as bucketSourceVerdict, M as vectorIndexNotFoundMessage, N as ADAPTER_FILTER_REASON, O as AtscriptDbReadable, P as ENCRYPTED_REASON, Q as DocumentFieldMapper, R as canFilterLeaf, S as ALL_BUCKET_UNITS, T as createFailureCollector, U as guardAggregate, V as collectQueryPaths, W as guardFilter, X as unsupportedOperatorMessage, Y as sortFieldNames, Z as RelationalFieldMapper, _ as isViewType, at as aliasTargetOf, b as decomposePatch, ct as jsonValueAncestor, dt as NoopLogger, et as UniquSelect, f as fkColumns, g as isAtscriptDbView, h as AtscriptDbView, it as isGeoPointType, j as searchIndexNotFoundMessage, k as resolveDesignType, lt as normalizeComputedSelect, n as isColumnTypeChanged, nt as TableMetadata, ot as isBucketableField, q as guardQuery, rt as isGeoIndexableType, st as isJsonValueField, tt as numericOperandProblem, ut as resolveCalendarBuckets, v as AtscriptDbTable, w as BaseDbAdapter, x as ApplicationIntegrity, y as assertNoVersionWrites, z as checkHavingKeys } from "./column-diff-Cp6ZoyRE.mjs";
3
+ import { n as ALL_AGGREGATE_FNS } from "./aggregate-fns-CyaZyb9I.mjs";
4
+ import { A as isResolvedRelationFilter, C as REL_FILTER_MAX_NODES, E as containsRelationFilter, G as isFieldRef, K as translateQueryTree, N as relationStaticFilter, O as forEachResolvedRelation, S as REL_FILTER_MAX_DEPTH, T as andFilters, V as tableNameOf, W as evaluateExpr, k as hasRelationOp, w as ResolvedRelationFilter, x as uniqueKeyTuple } from "./nested-writer-CUBoq1ZO.mjs";
5
5
  import { t as DB_ENTITY_ANNOTATIONS } from "./derived-rules-0sKn4f5C.mjs";
6
6
  import { a as isPlainObject, i as isEmptyObject, n as findAncestorInSet, o as selfOrAncestor, r as getPath, t as deletePath } from "./object-TkiJQ-Dp.mjs";
7
7
  import { t as DEFAULT_DB_SPACE } from "./consts-C_-5_pFq.mjs";
8
8
  import { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, getDbFieldOp, isDbFieldOp, reconcileCas, separateCas, separateFieldOps } from "./ops.mjs";
9
- import { a as forceNavNonOptional, c as getKeyProps, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-Clu2q_7z.mjs";
9
+ import { a as forceNavNonOptional, c as getKeyProps, o as isNavRelation, r as buildValidationContext, s as createDbValidatorPlugin, t as buildDbValidator } from "./validator-BTiIOTKP.mjs";
10
10
  import { isAnnotatedType } from "@atscript/typescript/utils";
11
- import { computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
11
+ import { RELATION_OPS, computeInsights, isPrimitive, isRelationOp, walkFilter } from "@uniqu/core";
12
12
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
13
13
  //#region src/encryption.ts
14
14
  const ENVELOPE_VERSION = "aes1";
@@ -235,8 +235,14 @@ var DbSpace = class {
235
235
  _readables = /* @__PURE__ */ new WeakMap();
236
236
  /** All tables created in this space — used for reverse FK lookup during cascade. */
237
237
  _allTables = /* @__PURE__ */ new Set();
238
+ /** Every table / view handle the space created — flagged closed on {@link close}. */
239
+ _handles = /* @__PURE__ */ new Set();
238
240
  /** Lazily created adapter for administrative ops (drop table/view) that don't need a registered readable. */
239
241
  _adminAdapter;
242
+ /** Every adapter this space created (tables, views, admin) — disposed on close. */
243
+ _adapters = /* @__PURE__ */ new Set();
244
+ _onClose;
245
+ _closing;
240
246
  logger;
241
247
  /** Encryption service for `@db.encrypted` fields — validated eagerly at construction. */
242
248
  _encryption;
@@ -251,6 +257,7 @@ var DbSpace = class {
251
257
  else {
252
258
  const options = loggerOrOptions ?? {};
253
259
  this.logger = options.logger ?? NoopLogger;
260
+ this._onClose = options.onClose;
254
261
  if (options.encryption) this._encryption = new DbEncryption(options.encryption);
255
262
  }
256
263
  }
@@ -259,6 +266,7 @@ var DbSpace = class {
259
266
  * appropriate instance. Uses `@db.view` or `@db.view.for` presence to distinguish.
260
267
  */
261
268
  get(type, logger) {
269
+ this._assertOpen();
262
270
  if (isViewType(type)) return this.getView(type, logger);
263
271
  return this.getTable(type, logger);
264
272
  }
@@ -267,6 +275,7 @@ var DbSpace = class {
267
275
  * Creates the table + adapter on first access, caches for subsequent calls.
268
276
  */
269
277
  getTable(type, logger) {
278
+ this._assertOpen();
270
279
  let readable = this._readables.get(type);
271
280
  if (!readable) {
272
281
  assertNotAlias(type);
@@ -279,6 +288,7 @@ var DbSpace = class {
279
288
  readable.setFkLookupResolver((tableName) => this._getFkLookupTarget(tableName));
280
289
  readable.setEncryption(this._encryption);
281
290
  this._readables.set(type, readable);
291
+ this._handles.add(readable);
282
292
  }
283
293
  return readable;
284
294
  }
@@ -287,12 +297,14 @@ var DbSpace = class {
287
297
  * Creates the view + adapter on first access, caches for subsequent calls.
288
298
  */
289
299
  getView(type, logger) {
300
+ this._assertOpen();
290
301
  let readable = this._readables.get(type);
291
302
  if (!readable) {
292
303
  assertNotAlias(type);
293
304
  readable = new AtscriptDbView(type, this._createAdapter(), logger || this.logger, (t) => this.get(t));
294
305
  readable.setEncryption(this._encryption);
295
306
  this._readables.set(type, readable);
307
+ this._handles.add(readable);
296
308
  }
297
309
  return readable;
298
310
  }
@@ -301,6 +313,7 @@ var DbSpace = class {
301
313
  * Creates the table/view + adapter on first access if needed.
302
314
  */
303
315
  getAdapter(type) {
316
+ this._assertOpen();
304
317
  return this.get(type).dbAdapter;
305
318
  }
306
319
  /**
@@ -308,6 +321,7 @@ var DbSpace = class {
308
321
  * See `BaseDbAdapter.dropTableByName` for an adapter that does not support it.
309
322
  */
310
323
  async dropTableByName(tableName) {
324
+ this._assertOpen();
311
325
  await this._getAdminAdapter().dropTableByName(tableName);
312
326
  }
313
327
  /**
@@ -315,6 +329,7 @@ var DbSpace = class {
315
329
  * See `BaseDbAdapter.dropViewByName` for an adapter that does not support it.
316
330
  */
317
331
  async dropViewByName(viewName) {
332
+ this._assertOpen();
318
333
  await this._getAdminAdapter().dropViewByName(viewName);
319
334
  }
320
335
  /**
@@ -323,6 +338,7 @@ var DbSpace = class {
323
338
  * @since 0.1.128
324
339
  */
325
340
  async dropTablesByName(tableNames) {
341
+ this._assertOpen();
326
342
  await this._getAdminAdapter().dropTablesByName(tableNames);
327
343
  }
328
344
  /**
@@ -332,6 +348,7 @@ var DbSpace = class {
332
348
  * @since 0.1.128
333
349
  */
334
350
  async getReferencingForeignKeys(tableName) {
351
+ this._assertOpen();
335
352
  return this._getAdminAdapter().getReferencingForeignKeys?.(tableName);
336
353
  }
337
354
  /**
@@ -350,8 +367,46 @@ var DbSpace = class {
350
367
  _createAdapter() {
351
368
  const adapter = this.adapterFactory();
352
369
  adapter.registerSpace?.(this);
370
+ this._adapters.add(adapter);
353
371
  return adapter;
354
372
  }
373
+ /** `true` once {@link close} was called. @since 0.1.148 */
374
+ get closed() {
375
+ return this._closing !== void 0;
376
+ }
377
+ /** Throws `SPACE_CLOSED` once the space is closed. */
378
+ _assertOpen() {
379
+ if (this._closing) throw spaceClosedError();
380
+ }
381
+ /**
382
+ * Closes the space: marks it closed, disposes every adapter it created, then
383
+ * runs the `onClose` hook (the `createAdapter` helpers close their driver
384
+ * there). Idempotent — every call returns the first call's promise. Every
385
+ * step is attempted; failures are collected into an `AggregateError`.
386
+ *
387
+ * It does not cancel or drain in-flight queries: call it after the server
388
+ * stopped accepting requests. After close, `get*` and operations on existing
389
+ * table/view handles throw `DbError("SPACE_CLOSED")`.
390
+ * @since 0.1.148
391
+ */
392
+ close() {
393
+ return this._closing ??= this._doClose();
394
+ }
395
+ async _doClose() {
396
+ for (const readable of this._handles) readable._spaceClosed = true;
397
+ const errors = [];
398
+ for (const adapter of this._adapters) try {
399
+ await adapter.dispose?.();
400
+ } catch (error) {
401
+ errors.push(error);
402
+ }
403
+ try {
404
+ await this._onClose?.();
405
+ } catch (error) {
406
+ errors.push(error);
407
+ }
408
+ if (errors.length > 0) throw aggregateFailure("DbSpace close failed", errors);
409
+ }
355
410
  /**
356
411
  * Finds all child tables with FKs pointing to the given parent table name.
357
412
  * Accesses `table.foreignKeys` which triggers `_flatten()` if needed.
@@ -375,34 +430,9 @@ var DbSpace = class {
375
430
  for (const table of this._allTables) if (table.tableName === tableName) return { count: (filter) => table.count({ filter }) };
376
431
  }
377
432
  };
378
- //#endregion
379
- //#region src/query/query-tree.ts
380
- /**
381
- * `true` when a query-tree operand is a field reference (`{ field, type? }`)
382
- * rather than a literal — e.g. the right side of a field-to-field comparison.
383
- * @since 0.1.136
384
- */
385
- function isFieldRef(value) {
386
- return value !== null && typeof value === "object" && "field" in value;
387
- }
388
- /**
389
- * Translates a JS-emitted query tree into a FilterExpr.
390
- * Resolves field references (type + field path) to physical column names
391
- * via the provided resolver function.
392
- */
393
- function translateQueryTree(node, resolveField) {
394
- if ("$and" in node) return { $and: node.$and.map((n) => translateQueryTree(n, resolveField)) };
395
- if ("$or" in node) return { $or: node.$or.map((n) => translateQueryTree(n, resolveField)) };
396
- if ("$not" in node) return { $not: translateQueryTree(node.$not, resolveField) };
397
- const comp = node;
398
- const leftField = resolveField(comp.left);
399
- if (isFieldRef(comp.right)) {
400
- const rightField = resolveField(comp.right);
401
- return { [leftField]: { [comp.op]: { $field: rightField } } };
402
- }
403
- if (comp.op === "$exists") return { [leftField]: { $exists: comp.right !== false } };
404
- return { [leftField]: { [comp.op]: comp.right } };
405
- }
433
+ if (typeof Symbol.asyncDispose === "symbol") DbSpace.prototype[Symbol.asyncDispose] = function() {
434
+ return this.close();
435
+ };
406
436
  //#endregion
407
437
  //#region src/table/db-entity.ts
408
438
  /**
@@ -422,4 +452,4 @@ function isDbEntityType(value) {
422
452
  return DB_ENTITY_ANNOTATIONS.some((name) => value.metadata.has(name));
423
453
  }
424
454
  //#endregion
425
- export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, BaseDbAdapter, CasExhaustedError, CasMismatchError, DEFAULT_DB_SPACE, DbEncryption, DbError, DbSpace, DocumentFieldMapper, ENCRYPTED_REASON, FieldMappingStrategy, IntegrityStrategy, NativeIntegrity, NoopLogger, RelationalFieldMapper, TableMetadata, UniquSelect, acceptedOperatorsHint, aliasTargetOf, assertGeoPoint, assertNoVersionWrites, bucketSourceVerdict, bucketTimeZoneUnavailable, buildDbValidator, buildValidationContext, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, deletePath, findAncestorInSet, forceNavNonOptional, geoIndexNotFoundMessage, getDbFieldOp, getKeyProps, getPath, guardAggregate, guardFilter, guardPath, guardPaths, guardQuery, isAtscriptDbView, isBucketableField, isColumnTypeChanged, isDbEntityType, isDbFieldOp, isEmptyObject, isFieldRef, isGeoIndexableType, isGeoPointType, isJsonValueField, isNavRelation, isPlainObject, isPrimitive, isViewType, jsonValueAncestor, narrowerFilterOps, normalizeComputedSelect, reconcileCas, resolveCalendarBuckets, resolveDesignType, searchIndexNotFoundMessage, selfOrAncestor, separateCas, separateFieldOps, sortFieldNames, tableNameOf, translateQueryTree, unsupportedOperatorMessage, vectorIndexNotFoundMessage, walkFilter, withOptimisticRetry };
455
+ export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, ADAPTER_FILTER_REASON, ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ALL_VIEW_CAPABILITIES, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, BaseDbAdapter, CasExhaustedError, CasMismatchError, DEFAULT_DB_SPACE, DbEncryption, DbError, DbSpace, DocumentFieldMapper, ENCRYPTED_REASON, FieldMappingStrategy, IntegrityStrategy, NativeIntegrity, NoopLogger, RELATION_OPS, REL_FILTER_MAX_DEPTH, REL_FILTER_MAX_NODES, RelationalFieldMapper, ResolvedRelationFilter, TableMetadata, UniquSelect, acceptedOperatorsHint, aggregateExpressionsNotSupported, aggregateFailure, aliasTargetOf, andFilters, assertGeoPoint, assertNoVersionWrites, bucketSourceVerdict, bucketTimeZoneUnavailable, buildDbValidator, buildValidationContext, canFilterLeaf, checkHavingKeys, classifyQueryPath, collectQueryPaths, computeInsights, containsRelationFilter, createDbValidatorPlugin, createFailureCollector, decomposePatch, deletePath, evaluateExpr, findAncestorInSet, fkColumns, forEachResolvedRelation, forceNavNonOptional, geoIndexNotFoundMessage, getDbFieldOp, getKeyProps, getPath, groupSourceVerdict, guardAggregate, guardFilter, guardPath, guardPaths, guardQuery, hasRelationOp, isAtscriptDbView, isBucketableField, isColumnTypeChanged, isConflict, isDbEntityType, isDbFieldOp, isEmptyObject, isFieldRef, isGeoIndexableType, isGeoPointType, isJsonValueField, isNavRelation, isPlainObject, isPrimitive, isRelationOp, isResolvedRelationFilter, isViewType, jsonValueAncestor, narrowerFilterOps, normalizeComputedSelect, numericOperandProblem, reconcileCas, relationStaticFilter, resolveCalendarBuckets, resolveDesignType, searchIndexNotFoundMessage, selfOrAncestor, separateCas, separateFieldOps, sortFieldNames, tableNameOf, translateQueryTree, uniqueKeyTuple, unsupportedOperatorMessage, vectorIndexNotFoundMessage, walkFilter, withOptimisticRetry };