@atscript/db 0.1.161 → 0.1.163

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 (65) hide show
  1. package/dist/agg.cjs +1 -1
  2. package/dist/agg.d.cts +1 -1
  3. package/dist/agg.d.mts +1 -1
  4. package/dist/agg.mjs +1 -1
  5. package/dist/{aggregate-fns-B_sgl4mB.mjs → aggregate-fns-DsS9UQVB.mjs} +1 -1
  6. package/dist/{aggregate-fns-DFtKAv7Q.cjs → aggregate-fns-DupYzFD7.cjs} +1 -1
  7. package/dist/{buckets-B4T_alUe.d.cts → buckets-B8UOod-v.d.cts} +488 -57
  8. package/dist/{buckets-8mG67Mtw.d.mts → buckets-CHyspjYP.d.mts} +488 -57
  9. package/dist/{column-diff-DpeUbhEI.cjs → column-diff-BIGX3sRH.cjs} +853 -232
  10. package/dist/{column-diff-DR1glykD.mjs → column-diff-BfNIlMwX.mjs} +836 -233
  11. package/dist/{validator-B3xlbrWf.d.cts → db-error-B_DRL1E9.d.cts} +18 -89
  12. package/dist/{validator-B3xlbrWf.d.mts → db-error-B_DRL1E9.d.mts} +18 -89
  13. package/dist/{db-error-JcfJqqpk.cjs → db-error-DmF1_xrz.cjs} +13 -0
  14. package/dist/{db-error-eSsQX7rt.mjs → db-error-hraC12B9.mjs} +8 -1
  15. package/dist/{db-validator-plugin-BWy60OvG.d.cts → db-validator-plugin-wRqMYNBI.d.cts} +6 -0
  16. package/dist/{db-validator-plugin-BWy60OvG.d.mts → db-validator-plugin-wRqMYNBI.d.mts} +6 -0
  17. package/dist/{fk-diff-5gX42hBt.d.mts → fk-diff-BNGawZi9.d.cts} +34 -10
  18. package/dist/{fk-diff-BWdQ7kRZ.d.cts → fk-diff-rj9N2QLw.d.mts} +34 -10
  19. package/dist/index.cjs +15 -11
  20. package/dist/index.d.cts +24 -21
  21. package/dist/index.d.mts +24 -21
  22. package/dist/index.mjs +10 -12
  23. package/dist/{nested-writer-BOj_c_lI.mjs → nested-writer-ClUX0DB0.mjs} +16 -22
  24. package/dist/{nested-writer-Bl1SZS7x.cjs → nested-writer-yCy6wGuN.cjs} +16 -22
  25. package/dist/{object-CtPYTIvy.d.cts → object-Czia_qD4.d.cts} +7 -1
  26. package/dist/{object-CtPYTIvy.d.mts → object-Czia_qD4.d.mts} +7 -1
  27. package/dist/{object-Djg28csK.cjs → object-GjsuPNqo.cjs} +19 -0
  28. package/dist/{object-TkiJQ-Dp.mjs → object-PQ1J8jri.mjs} +14 -1
  29. package/dist/ops.cjs +6 -21
  30. package/dist/ops.mjs +6 -21
  31. package/dist/plugin.cjs +263 -323
  32. package/dist/plugin.mjs +163 -223
  33. package/dist/rel.cjs +2 -2
  34. package/dist/rel.d.cts +3 -3
  35. package/dist/rel.d.mts +3 -3
  36. package/dist/rel.mjs +2 -2
  37. package/dist/{relation-helpers-17_2f5hX.d.mts → relation-helpers-DloMywNs.d.cts} +1 -1
  38. package/dist/{relation-helpers-BLBrLQYi.d.cts → relation-helpers-zwt19E7r.d.mts} +1 -1
  39. package/dist/{relation-loader-DeulLrAw.cjs → relation-loader-DujL_Mh9.cjs} +1 -1
  40. package/dist/{relation-loader-CNBMPfRr.mjs → relation-loader-Qv3LrQ42.mjs} +1 -1
  41. package/dist/{search-fields-CT_UZ9fg.cjs → search-fields-B49-RCWd.cjs} +65 -1
  42. package/dist/{search-fields-CE8cmj9X.mjs → search-fields-BPNsxrCk.mjs} +48 -2
  43. package/dist/search-fields-CHqqcC3W.d.cts +30 -0
  44. package/dist/search-fields-CHqqcC3W.d.mts +30 -0
  45. package/dist/server-stamped-B6XbUQ4p.cjs +33 -0
  46. package/dist/server-stamped-BoP56K9M.mjs +22 -0
  47. package/dist/shared.cjs +42 -26
  48. package/dist/shared.d.cts +98 -4
  49. package/dist/shared.d.mts +98 -4
  50. package/dist/shared.mjs +4 -2
  51. package/dist/sync.cjs +228 -65
  52. package/dist/sync.d.cts +41 -5
  53. package/dist/sync.d.mts +41 -5
  54. package/dist/sync.mjs +228 -66
  55. package/dist/{validator-B4YDLUkj.cjs → validator-DK9Ijpo7.cjs} +3 -2
  56. package/dist/validator-DX97RzC2.d.cts +108 -0
  57. package/dist/validator-DX97RzC2.d.mts +108 -0
  58. package/dist/{validator-B3fPJjS1.mjs → validator-DuDWsIdQ.mjs} +3 -2
  59. package/dist/validator.cjs +6 -3
  60. package/dist/validator.d.cts +5 -4
  61. package/dist/validator.d.mts +5 -4
  62. package/dist/validator.mjs +5 -4
  63. package/dist/{validation-utils-BGjqc2jU.mjs → view-validation-BcgDq7M9.mjs} +364 -20
  64. package/dist/{validation-utils-CtLNlBtB.cjs → view-validation-BiDLCYMw.cjs} +452 -18
  65. package/package.json +6 -6
@@ -1,5 +1,3 @@
1
- import { TAtscriptAnnotatedType, TAtscriptTypeArray, TAtscriptTypeObject, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
2
-
3
1
  //#region src/db-error.d.ts
4
2
  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
3
  /**
@@ -33,9 +31,25 @@ type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" |
33
31
  * PostgreSQL could not serialize the transaction (`40001`: under
34
32
  * `REPEATABLE READ` / `SERIALIZABLE`, e.g. a row locked or updated after it
35
33
  * changed since the snapshot). The transaction is aborted — retry it whole.
34
+ * Also thrown (since 0.1.162, path `limit`) by a bounded `updateMany` /
35
+ * `deleteMany` whose picked rows concurrent writers kept taking while rows
36
+ * still matched — retry the call (or its transaction).
36
37
  * `retryable` is `true`. @since 0.1.153
37
38
  */
38
- | "SERIALIZATION_FAILURE";
39
+ | "SERIALIZATION_FAILURE"
40
+ /**
41
+ * The adapter cannot take a row lock on a read (`findOne` / `findMany`
42
+ * with `{ lock }`) — MongoDB, or an adapter whose `supportsReadLocks()` is
43
+ * false. Use optimistic concurrency (`$cas`, `withOptimisticRetry`) there.
44
+ */
45
+ | "LOCK_NOT_SUPPORTED"
46
+ /**
47
+ * The adapter cannot run a transaction at the requested isolation level
48
+ * (`withTransaction(fn, { isolation })`) — e.g. `serializable` on MongoDB,
49
+ * any level on a MongoDB without transactions, or an adapter whose
50
+ * `isolationLevels()` lacks it.
51
+ */
52
+ | "ISOLATION_NOT_SUPPORTED";
39
53
  declare class DbError extends Error {
40
54
  readonly code: DbErrorCode;
41
55
  readonly errors: Array<{
@@ -111,89 +125,4 @@ declare function bucketTimeZoneUnavailable(message: string): DbError;
111
125
  */
112
126
  declare function aggregateExpressionsNotSupported(): DbError;
113
127
  //#endregion
114
- //#region src/patch/patch-types.d.ts
115
- interface TArrayPatch<A extends readonly unknown[]> {
116
- $replace?: A;
117
- $insert?: A;
118
- $upsert?: A;
119
- $update?: Array<Partial<TArrayElement<A>>>;
120
- $remove?: Array<Partial<TArrayElement<A>>>;
121
- }
122
- type TArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends ReadonlyArray<infer ElementType> ? ElementType : never;
123
- /**
124
- * Maps each property of T into a patch payload:
125
- * - Array properties become `TArrayPatch<T[K]>`
126
- * - Non-array properties become `Partial<T[K]>`
127
- */
128
- type TDbPatch<T> = { [K in keyof T]?: T[K] extends Array<infer _> ? TArrayPatch<T[K]> : Partial<T[K]> };
129
- /**
130
- * Extracts `@expect.array.key` properties from an array-of-objects type.
131
- * These keys uniquely identify an element inside the array and are used
132
- * for `$update`, `$remove`, and `$upsert` operations.
133
- *
134
- * @param def - Atscript array type definition.
135
- * @returns Set of property names marked as keys; empty set if none.
136
- */
137
- declare function getKeyProps(def: TAtscriptAnnotatedType<TAtscriptTypeArray>): Set<string>;
138
- //#endregion
139
- //#region src/validator.d.ts
140
- /** Write operation mode for validator configuration. */
141
- type ValidatorMode = "insert" | "patch" | "replace";
142
- /** Singleton db validator plugin — stateless, safe to share across all validators. */
143
- declare const dbPlugin: TValidatorPlugin;
144
- /**
145
- * Builds a validator for a given write mode.
146
- *
147
- * Shared between server-side (`AtscriptDbTable`) and client-side (`ClientValidator`).
148
- * Both use the same plugin, same `replace`, same `partial` logic.
149
- *
150
- * @param type - The annotated type to validate against.
151
- * @param mode - The write operation mode.
152
- * @param extraPlugins - Additional adapter-specific plugins (prepended before the db plugin).
153
- * @param opts - `unknownProps` overrides the validator's unknown-property policy
154
- * (used by db-client's `lenientWrites`, where the served type may be a
155
- * projection of the full server-side type).
156
- */
157
- declare function buildDbValidator(type: TAtscriptAnnotatedType, mode: ValidatorMode, extraPlugins?: TValidatorPlugin[], opts?: {
158
- unknownProps?: "strip" | "ignore" | "error";
159
- }): Validator<any>;
160
- /**
161
- * Path-aware `partial` callback for patch/update validation — the single
162
- * implementation shared by the server's `bulkUpdate` validator and the
163
- * client's patch preflight:
164
- *
165
- * - the root object is partial (a patch names only the fields it touches)
166
- * - nav-relation subtrees are partial (nested data is validated by its own table)
167
- * - `@db.patch.strategy "merge"` blocks are partial (the decomposer merges
168
- * per leaf, so absent keys survive server-side by design)
169
- *
170
- * Every other nested object stays strict: non-merge blocks are `$set` as a
171
- * whole (replace semantics), so their required fields really are required.
172
- */
173
- declare function buildPatchPartial(navPaths: ReadonlySet<string>): (def: TAtscriptAnnotatedType<TAtscriptTypeObject>, path: string) => boolean;
174
- /** Returns true if the annotated type is a navigation relation (TO/FROM/VIA). */
175
- declare function isNavRelation(type: TAtscriptAnnotatedType): boolean;
176
- /**
177
- * Forces nav fields non-optional so the plugin handles null/undefined checks.
178
- * The Validator caches replace results internally, so this allocates at most once per type node.
179
- */
180
- declare function forceNavNonOptional(type: TAtscriptAnnotatedType): TAtscriptAnnotatedType;
181
- /** Result of {@link buildValidationContext}. */
182
- interface ValidationContext {
183
- /** Flat map of dotted field paths → annotated types (same shape the server builds). */
184
- flatMap: Map<string, TAtscriptAnnotatedType>;
185
- /** Set of field paths that are navigation relations (TO/FROM/VIA). */
186
- navFields: ReadonlySet<string>;
187
- }
188
- /**
189
- * Builds a lightweight validation context from a deserialized Atscript type.
190
- *
191
- * This is the client-side equivalent of the server's `TableMetadata.build()`,
192
- * without any adapter-specific processing (physical columns, index resolution, etc.).
193
- *
194
- * @param type - A deserialized annotated type (from `deserializeAnnotatedType(meta.type)`).
195
- * @returns `flatMap` and `navFields` suitable for passing to `createDbValidatorPlugin` via `DbValidationContext`.
196
- */
197
- declare function buildValidationContext(type: TAtscriptAnnotatedType<TAtscriptTypeObject>): ValidationContext;
198
- //#endregion
199
- export { aggregateFailure as _, buildValidationContext as a, isRetryableDbError as b, 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 };
128
+ export { aggregateExpressionsNotSupported as a, isConflict as c, DbErrorCode as i, isRetryableDbError as l, CasMismatchError as n, aggregateFailure as o, DbError as r, bucketTimeZoneUnavailable as s, CasExhaustedError as t };
@@ -1,5 +1,3 @@
1
- import { TAtscriptAnnotatedType, TAtscriptTypeArray, TAtscriptTypeObject, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
2
-
3
1
  //#region src/db-error.d.ts
4
2
  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
3
  /**
@@ -33,9 +31,25 @@ type DbErrorCode = "CONFLICT" | "FK_VIOLATION" | "NOT_FOUND" | "CASCADE_CYCLE" |
33
31
  * PostgreSQL could not serialize the transaction (`40001`: under
34
32
  * `REPEATABLE READ` / `SERIALIZABLE`, e.g. a row locked or updated after it
35
33
  * changed since the snapshot). The transaction is aborted — retry it whole.
34
+ * Also thrown (since 0.1.162, path `limit`) by a bounded `updateMany` /
35
+ * `deleteMany` whose picked rows concurrent writers kept taking while rows
36
+ * still matched — retry the call (or its transaction).
36
37
  * `retryable` is `true`. @since 0.1.153
37
38
  */
38
- | "SERIALIZATION_FAILURE";
39
+ | "SERIALIZATION_FAILURE"
40
+ /**
41
+ * The adapter cannot take a row lock on a read (`findOne` / `findMany`
42
+ * with `{ lock }`) — MongoDB, or an adapter whose `supportsReadLocks()` is
43
+ * false. Use optimistic concurrency (`$cas`, `withOptimisticRetry`) there.
44
+ */
45
+ | "LOCK_NOT_SUPPORTED"
46
+ /**
47
+ * The adapter cannot run a transaction at the requested isolation level
48
+ * (`withTransaction(fn, { isolation })`) — e.g. `serializable` on MongoDB,
49
+ * any level on a MongoDB without transactions, or an adapter whose
50
+ * `isolationLevels()` lacks it.
51
+ */
52
+ | "ISOLATION_NOT_SUPPORTED";
39
53
  declare class DbError extends Error {
40
54
  readonly code: DbErrorCode;
41
55
  readonly errors: Array<{
@@ -111,89 +125,4 @@ declare function bucketTimeZoneUnavailable(message: string): DbError;
111
125
  */
112
126
  declare function aggregateExpressionsNotSupported(): DbError;
113
127
  //#endregion
114
- //#region src/patch/patch-types.d.ts
115
- interface TArrayPatch<A extends readonly unknown[]> {
116
- $replace?: A;
117
- $insert?: A;
118
- $upsert?: A;
119
- $update?: Array<Partial<TArrayElement<A>>>;
120
- $remove?: Array<Partial<TArrayElement<A>>>;
121
- }
122
- type TArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends ReadonlyArray<infer ElementType> ? ElementType : never;
123
- /**
124
- * Maps each property of T into a patch payload:
125
- * - Array properties become `TArrayPatch<T[K]>`
126
- * - Non-array properties become `Partial<T[K]>`
127
- */
128
- type TDbPatch<T> = { [K in keyof T]?: T[K] extends Array<infer _> ? TArrayPatch<T[K]> : Partial<T[K]> };
129
- /**
130
- * Extracts `@expect.array.key` properties from an array-of-objects type.
131
- * These keys uniquely identify an element inside the array and are used
132
- * for `$update`, `$remove`, and `$upsert` operations.
133
- *
134
- * @param def - Atscript array type definition.
135
- * @returns Set of property names marked as keys; empty set if none.
136
- */
137
- declare function getKeyProps(def: TAtscriptAnnotatedType<TAtscriptTypeArray>): Set<string>;
138
- //#endregion
139
- //#region src/validator.d.ts
140
- /** Write operation mode for validator configuration. */
141
- type ValidatorMode = "insert" | "patch" | "replace";
142
- /** Singleton db validator plugin — stateless, safe to share across all validators. */
143
- declare const dbPlugin: TValidatorPlugin;
144
- /**
145
- * Builds a validator for a given write mode.
146
- *
147
- * Shared between server-side (`AtscriptDbTable`) and client-side (`ClientValidator`).
148
- * Both use the same plugin, same `replace`, same `partial` logic.
149
- *
150
- * @param type - The annotated type to validate against.
151
- * @param mode - The write operation mode.
152
- * @param extraPlugins - Additional adapter-specific plugins (prepended before the db plugin).
153
- * @param opts - `unknownProps` overrides the validator's unknown-property policy
154
- * (used by db-client's `lenientWrites`, where the served type may be a
155
- * projection of the full server-side type).
156
- */
157
- declare function buildDbValidator(type: TAtscriptAnnotatedType, mode: ValidatorMode, extraPlugins?: TValidatorPlugin[], opts?: {
158
- unknownProps?: "strip" | "ignore" | "error";
159
- }): Validator<any>;
160
- /**
161
- * Path-aware `partial` callback for patch/update validation — the single
162
- * implementation shared by the server's `bulkUpdate` validator and the
163
- * client's patch preflight:
164
- *
165
- * - the root object is partial (a patch names only the fields it touches)
166
- * - nav-relation subtrees are partial (nested data is validated by its own table)
167
- * - `@db.patch.strategy "merge"` blocks are partial (the decomposer merges
168
- * per leaf, so absent keys survive server-side by design)
169
- *
170
- * Every other nested object stays strict: non-merge blocks are `$set` as a
171
- * whole (replace semantics), so their required fields really are required.
172
- */
173
- declare function buildPatchPartial(navPaths: ReadonlySet<string>): (def: TAtscriptAnnotatedType<TAtscriptTypeObject>, path: string) => boolean;
174
- /** Returns true if the annotated type is a navigation relation (TO/FROM/VIA). */
175
- declare function isNavRelation(type: TAtscriptAnnotatedType): boolean;
176
- /**
177
- * Forces nav fields non-optional so the plugin handles null/undefined checks.
178
- * The Validator caches replace results internally, so this allocates at most once per type node.
179
- */
180
- declare function forceNavNonOptional(type: TAtscriptAnnotatedType): TAtscriptAnnotatedType;
181
- /** Result of {@link buildValidationContext}. */
182
- interface ValidationContext {
183
- /** Flat map of dotted field paths → annotated types (same shape the server builds). */
184
- flatMap: Map<string, TAtscriptAnnotatedType>;
185
- /** Set of field paths that are navigation relations (TO/FROM/VIA). */
186
- navFields: ReadonlySet<string>;
187
- }
188
- /**
189
- * Builds a lightweight validation context from a deserialized Atscript type.
190
- *
191
- * This is the client-side equivalent of the server's `TableMetadata.build()`,
192
- * without any adapter-specific processing (physical columns, index resolution, etc.).
193
- *
194
- * @param type - A deserialized annotated type (from `deserializeAnnotatedType(meta.type)`).
195
- * @returns `flatMap` and `navFields` suitable for passing to `createDbValidatorPlugin` via `DbValidationContext`.
196
- */
197
- declare function buildValidationContext(type: TAtscriptAnnotatedType<TAtscriptTypeObject>): ValidationContext;
198
- //#endregion
199
- export { aggregateFailure as _, buildValidationContext as a, isRetryableDbError as b, 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 };
128
+ export { aggregateExpressionsNotSupported as a, isConflict as c, DbErrorCode as i, isRetryableDbError as l, CasMismatchError as n, aggregateFailure as o, DbError as r, bucketTimeZoneUnavailable as s, CasExhaustedError as t };
@@ -37,6 +37,13 @@ function isRetryableDbError(error) {
37
37
  function isConflict(error) {
38
38
  return error instanceof DbError && error.code === "CONFLICT";
39
39
  }
40
+ /** @internal An `INVALID_QUERY` error with a single `{ path, message }` entry. */
41
+ function invalidQuery(path, message) {
42
+ return new DbError("INVALID_QUERY", [{
43
+ path,
44
+ message
45
+ }]);
46
+ }
40
47
  /** @internal The error every handle of a closed `DbSpace` throws. */
41
48
  function spaceClosedError() {
42
49
  return new DbError("SPACE_CLOSED", [{
@@ -180,6 +187,12 @@ Object.defineProperty(exports, "bucketTimeZoneUnavailable", {
180
187
  return bucketTimeZoneUnavailable;
181
188
  }
182
189
  });
190
+ Object.defineProperty(exports, "invalidQuery", {
191
+ enumerable: true,
192
+ get: function() {
193
+ return invalidQuery;
194
+ }
195
+ });
183
196
  Object.defineProperty(exports, "isConflict", {
184
197
  enumerable: true,
185
198
  get: function() {
@@ -37,6 +37,13 @@ function isRetryableDbError(error) {
37
37
  function isConflict(error) {
38
38
  return error instanceof DbError && error.code === "CONFLICT";
39
39
  }
40
+ /** @internal An `INVALID_QUERY` error with a single `{ path, message }` entry. */
41
+ function invalidQuery(path, message) {
42
+ return new DbError("INVALID_QUERY", [{
43
+ path,
44
+ message
45
+ }]);
46
+ }
40
47
  /** @internal The error every handle of a closed `DbSpace` throws. */
41
48
  function spaceClosedError() {
42
49
  return new DbError("SPACE_CLOSED", [{
@@ -138,4 +145,4 @@ function aggregateExpressionsNotSupported() {
138
145
  }]);
139
146
  }
140
147
  //#endregion
141
- export { aggregateExpressionsNotSupported as a, isConflict as c, DepthLimitExceededError as i, isRetryableDbError as l, CasMismatchError as n, aggregateFailure as o, DbError as r, bucketTimeZoneUnavailable as s, CasExhaustedError as t, spaceClosedError as u };
148
+ export { aggregateExpressionsNotSupported as a, invalidQuery as c, spaceClosedError as d, DepthLimitExceededError as i, isConflict as l, CasMismatchError as n, aggregateFailure as o, DbError as r, bucketTimeZoneUnavailable as s, CasExhaustedError as t, isRetryableDbError as u };
@@ -5,6 +5,12 @@ interface DbValidationContext {
5
5
  mode: "insert" | "replace" | "patch";
6
6
  /** Flat map from the table — used to check if an array is a top-level array. */
7
7
  flatMap?: Map<string, TAtscriptAnnotatedType>;
8
+ /**
9
+ * The write picks its rows by a filter, not by the payload's primary key
10
+ * (`replaceMany(filter, data)`, since 0.1.162): a missing top-level
11
+ * `@meta.id` is accepted in `replace` mode.
12
+ */
13
+ keyless?: boolean;
8
14
  /** Precomputed nav field names — used to skip field-op validation inside TO/FROM/VIA relations. */
9
15
  navFields?: ReadonlySet<string>;
10
16
  /**
@@ -5,6 +5,12 @@ interface DbValidationContext {
5
5
  mode: "insert" | "replace" | "patch";
6
6
  /** Flat map from the table — used to check if an array is a top-level array. */
7
7
  flatMap?: Map<string, TAtscriptAnnotatedType>;
8
+ /**
9
+ * The write picks its rows by a filter, not by the payload's primary key
10
+ * (`replaceMany(filter, data)`, since 0.1.162): a missing top-level
11
+ * `@meta.id` is accepted in `replace` mode.
12
+ */
13
+ keyless?: boolean;
8
14
  /** Precomputed nav field names — used to skip field-op validation inside TO/FROM/VIA relations. */
9
15
  navFields?: ReadonlySet<string>;
10
16
  /**
@@ -1,4 +1,4 @@
1
- import { A as TColumnDiff, B as TDbDefaultFn, En as AtscriptDbReadable, U as TDbFieldMeta, V as TDbDefaultValue, W as TDbForeignKey, _t as TExistingColumn, an as AtscriptDbView, at as TDbStorageType, hn as AtscriptQueryNode, ht as TDerivedColumn, mn as AtscriptQueryFieldRef, yt as TExistingTableOption, z as TDbCollation } from "./buckets-8mG67Mtw.mjs";
1
+ import { B as TDbCollation, Bn as AtscriptDbReadable, Et as TExistingTableOption, G as TDbFieldMeta, H as TDbDefaultValue, K as TDbForeignKey, On as AtscriptQueryFieldRef, St as TDerivedColumn, V as TDbDefaultFn, dt as TDbStorageType, j as TColumnDiff, kn as AtscriptQueryNode, wt as TExistingColumn, yn as AtscriptDbView } from "./buckets-B8UOod-v.cjs";
2
2
 
3
3
  //#region src/schema/schema-hash.d.ts
4
4
  interface TFieldSnapshot {
@@ -208,6 +208,36 @@ declare function snapshotToExistingTableOptions(snapshot: TTableSnapshot): TExis
208
208
  * @since 0.1.137
209
209
  */
210
210
  declare function isColumnTypeChanged(existingType: string, expectedType: string): boolean;
211
+ /**
212
+ * Whether a live column default (as the adapter's introspection normalized
213
+ * it) and a model default (`serializeDefaultValue`) denote the same value for
214
+ * `field` — compared in a canonical, type-aware form, because the DDL writes a
215
+ * literal that differs from the annotation text and the engine reformats it
216
+ * again: booleans as `1` / `0` (`true` / `1` → `1`), numbers numerically
217
+ * (`1.0` = `1`, a DECIMAL's `0.00` = `0`), JSON-stored values as parsed,
218
+ * key-sorted JSON (`{"a": 1}` = `{"a":1}`). With a column type `liveType`
219
+ * of a fixed scale (`DECIMAL(10,2)`, `NUMERIC(8,3)`) — the type the column
220
+ * has once synced, i.e. the model's — a model value is also the value the
221
+ * column stores for it (`2.345` = `2.35`).
222
+ * Function defaults (`fn:now`, `fn:uuid`, …) and every other value compare as
223
+ * strings. Exported for adapters that must agree with schema sync.
224
+ * @since 0.1.162
225
+ */
226
+ declare function sameDefaultValue(field: Pick<TDbFieldMeta, "designType" | "storage">, live: string | undefined, desired: string | undefined, liveType?: string): boolean;
227
+ /** Options of {@link computeColumnDiff}. */
228
+ interface TColumnDiffOptions {
229
+ /**
230
+ * The table's stored snapshot (since 0.1.141) — the baseline a derived
231
+ * column's expression is compared with (the engine normalizes the
232
+ * expression it stores, so the live column cannot be). Without one, only a
233
+ * kind or type drift is seen.
234
+ */
235
+ snapshot?: TTableSnapshot | null;
236
+ /** The adapter's `nativeDefaultFns()`: a column missing such a default drifts. */
237
+ nativeDefaultFns?: ReadonlySet<TDbDefaultFn>;
238
+ /** The adapter's `reportedDefault` hook (since 0.1.162): a live default equal to it is unchanged. */
239
+ reportedDefault?: (desired: string, field: TDbFieldMeta) => string;
240
+ }
211
241
  /**
212
242
  * Computes the difference between desired schema fields and existing database columns.
213
243
  *
@@ -218,15 +248,9 @@ declare function isColumnTypeChanged(existingType: string, expectedType: string)
218
248
  * Receives the full field meta (design type, annotations, PK status, etc.)
219
249
  * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
220
250
  * Required for type change detection.
221
- * @param opts.snapshot - The table's stored snapshot (since 0.1.141) — the baseline a
222
- * derived column's expression is compared with (the engine normalizes
223
- * the expression it stores, so the live column cannot be). Without
224
- * one, only a kind or type drift is seen.
251
+ * @param opts - See {@link TColumnDiffOptions}.
225
252
  */
226
- declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string, opts?: {
227
- snapshot?: TTableSnapshot | null;
228
- nativeDefaultFns?: ReadonlySet<TDbDefaultFn>;
229
- }): TColumnDiff;
253
+ declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string, opts?: TColumnDiffOptions): TColumnDiff;
230
254
  //#endregion
231
255
  //#region src/schema/fk-diff.d.ts
232
256
  /**
@@ -263,4 +287,4 @@ declare function computeForeignKeyDiff(desired: ReadonlyMap<string, TDbForeignKe
263
287
  /** Whether the FK diff contains any changes. */
264
288
  declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
265
289
  //#endregion
266
- export { computeTableSnapshot as _, hasForeignKeyChanges as a, snapshotToExistingTableOptions as b, TFieldSnapshot as c, TViewColumnSnapshot as d, TViewJoinSnapshot as f, computeTableHash as g, computeSchemaHash as h, fkKey as i, TForeignKeySnapshot as l, canonicalizeQueryNode as m, computeForeignKeyDiff as n, computeColumnDiff as o, TViewSnapshot as p, fkColumns as r, isColumnTypeChanged as s, TForeignKeyDiff as t, TTableSnapshot as u, computeViewSnapshot as v, snapshotToExistingColumns as y };
290
+ export { snapshotToExistingTableOptions as S, computeSchemaHash as _, hasForeignKeyChanges as a, computeViewSnapshot as b, isColumnTypeChanged as c, TForeignKeySnapshot as d, TTableSnapshot as f, canonicalizeQueryNode as g, TViewSnapshot as h, fkKey as i, sameDefaultValue as l, TViewJoinSnapshot as m, computeForeignKeyDiff as n, TColumnDiffOptions as o, TViewColumnSnapshot as p, fkColumns as r, computeColumnDiff as s, TForeignKeyDiff as t, TFieldSnapshot as u, computeTableHash as v, snapshotToExistingColumns as x, computeTableSnapshot as y };
@@ -1,4 +1,4 @@
1
- import { A as TColumnDiff, B as TDbDefaultFn, En as AtscriptDbReadable, U as TDbFieldMeta, V as TDbDefaultValue, W as TDbForeignKey, _t as TExistingColumn, an as AtscriptDbView, at as TDbStorageType, hn as AtscriptQueryNode, ht as TDerivedColumn, mn as AtscriptQueryFieldRef, yt as TExistingTableOption, z as TDbCollation } from "./buckets-B4T_alUe.cjs";
1
+ import { B as TDbCollation, Bn as AtscriptDbReadable, Et as TExistingTableOption, G as TDbFieldMeta, H as TDbDefaultValue, K as TDbForeignKey, On as AtscriptQueryFieldRef, St as TDerivedColumn, V as TDbDefaultFn, dt as TDbStorageType, j as TColumnDiff, kn as AtscriptQueryNode, wt as TExistingColumn, yn as AtscriptDbView } from "./buckets-CHyspjYP.mjs";
2
2
 
3
3
  //#region src/schema/schema-hash.d.ts
4
4
  interface TFieldSnapshot {
@@ -208,6 +208,36 @@ declare function snapshotToExistingTableOptions(snapshot: TTableSnapshot): TExis
208
208
  * @since 0.1.137
209
209
  */
210
210
  declare function isColumnTypeChanged(existingType: string, expectedType: string): boolean;
211
+ /**
212
+ * Whether a live column default (as the adapter's introspection normalized
213
+ * it) and a model default (`serializeDefaultValue`) denote the same value for
214
+ * `field` — compared in a canonical, type-aware form, because the DDL writes a
215
+ * literal that differs from the annotation text and the engine reformats it
216
+ * again: booleans as `1` / `0` (`true` / `1` → `1`), numbers numerically
217
+ * (`1.0` = `1`, a DECIMAL's `0.00` = `0`), JSON-stored values as parsed,
218
+ * key-sorted JSON (`{"a": 1}` = `{"a":1}`). With a column type `liveType`
219
+ * of a fixed scale (`DECIMAL(10,2)`, `NUMERIC(8,3)`) — the type the column
220
+ * has once synced, i.e. the model's — a model value is also the value the
221
+ * column stores for it (`2.345` = `2.35`).
222
+ * Function defaults (`fn:now`, `fn:uuid`, …) and every other value compare as
223
+ * strings. Exported for adapters that must agree with schema sync.
224
+ * @since 0.1.162
225
+ */
226
+ declare function sameDefaultValue(field: Pick<TDbFieldMeta, "designType" | "storage">, live: string | undefined, desired: string | undefined, liveType?: string): boolean;
227
+ /** Options of {@link computeColumnDiff}. */
228
+ interface TColumnDiffOptions {
229
+ /**
230
+ * The table's stored snapshot (since 0.1.141) — the baseline a derived
231
+ * column's expression is compared with (the engine normalizes the
232
+ * expression it stores, so the live column cannot be). Without one, only a
233
+ * kind or type drift is seen.
234
+ */
235
+ snapshot?: TTableSnapshot | null;
236
+ /** The adapter's `nativeDefaultFns()`: a column missing such a default drifts. */
237
+ nativeDefaultFns?: ReadonlySet<TDbDefaultFn>;
238
+ /** The adapter's `reportedDefault` hook (since 0.1.162): a live default equal to it is unchanged. */
239
+ reportedDefault?: (desired: string, field: TDbFieldMeta) => string;
240
+ }
211
241
  /**
212
242
  * Computes the difference between desired schema fields and existing database columns.
213
243
  *
@@ -218,15 +248,9 @@ declare function isColumnTypeChanged(existingType: string, expectedType: string)
218
248
  * Receives the full field meta (design type, annotations, PK status, etc.)
219
249
  * so adapters can produce context-aware types (e.g., `VARCHAR(255)` from maxLength).
220
250
  * Required for type change detection.
221
- * @param opts.snapshot - The table's stored snapshot (since 0.1.141) — the baseline a
222
- * derived column's expression is compared with (the engine normalizes
223
- * the expression it stores, so the live column cannot be). Without
224
- * one, only a kind or type drift is seen.
251
+ * @param opts - See {@link TColumnDiffOptions}.
225
252
  */
226
- declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string, opts?: {
227
- snapshot?: TTableSnapshot | null;
228
- nativeDefaultFns?: ReadonlySet<TDbDefaultFn>;
229
- }): TColumnDiff;
253
+ declare function computeColumnDiff(desired: readonly TDbFieldMeta[], existing: TExistingColumn[], typeMapper?: (field: TDbFieldMeta) => string, opts?: TColumnDiffOptions): TColumnDiff;
230
254
  //#endregion
231
255
  //#region src/schema/fk-diff.d.ts
232
256
  /**
@@ -263,4 +287,4 @@ declare function computeForeignKeyDiff(desired: ReadonlyMap<string, TDbForeignKe
263
287
  /** Whether the FK diff contains any changes. */
264
288
  declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
265
289
  //#endregion
266
- export { computeTableSnapshot as _, hasForeignKeyChanges as a, snapshotToExistingTableOptions as b, TFieldSnapshot as c, TViewColumnSnapshot as d, TViewJoinSnapshot as f, computeTableHash as g, computeSchemaHash as h, fkKey as i, TForeignKeySnapshot as l, canonicalizeQueryNode as m, computeForeignKeyDiff as n, computeColumnDiff as o, TViewSnapshot as p, fkColumns as r, isColumnTypeChanged as s, TForeignKeyDiff as t, TTableSnapshot as u, computeViewSnapshot as v, snapshotToExistingColumns as y };
290
+ export { snapshotToExistingTableOptions as S, computeSchemaHash as _, hasForeignKeyChanges as a, computeViewSnapshot as b, isColumnTypeChanged as c, TForeignKeySnapshot as d, TTableSnapshot as f, canonicalizeQueryNode as g, TViewSnapshot as h, fkKey as i, sameDefaultValue as l, TViewJoinSnapshot as m, computeForeignKeyDiff as n, TColumnDiffOptions as o, TViewColumnSnapshot as p, fkColumns as r, computeColumnDiff as s, TForeignKeyDiff as t, TFieldSnapshot as u, computeTableHash as v, snapshotToExistingColumns as x, computeTableSnapshot as y };
package/dist/index.cjs CHANGED
@@ -1,11 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_db_error = require("./db-error-JcfJqqpk.cjs");
3
- const require_column_diff = require("./column-diff-DpeUbhEI.cjs");
4
- const require_aggregate_fns = require("./aggregate-fns-DFtKAv7Q.cjs");
5
- const require_nested_writer = require("./nested-writer-Bl1SZS7x.cjs");
6
- const require_validator = require("./validator-B4YDLUkj.cjs");
7
- const require_search_fields = require("./search-fields-CT_UZ9fg.cjs");
8
- const require_object = require("./object-Djg28csK.cjs");
2
+ const require_db_error = require("./db-error-DmF1_xrz.cjs");
3
+ const require_column_diff = require("./column-diff-BIGX3sRH.cjs");
4
+ const require_aggregate_fns = require("./aggregate-fns-DupYzFD7.cjs");
5
+ const require_nested_writer = require("./nested-writer-yCy6wGuN.cjs");
6
+ const require_validator = require("./validator-DK9Ijpo7.cjs");
7
+ const require_server_stamped = require("./server-stamped-B6XbUQ4p.cjs");
8
+ const require_search_fields = require("./search-fields-B49-RCWd.cjs");
9
+ const require_object = require("./object-GjsuPNqo.cjs");
9
10
  const require_consts = require("./consts-BzRfCcH2.cjs");
10
11
  const require_ops = require("./ops.cjs");
11
12
  let _atscript_typescript_utils = require("@atscript/typescript/utils");
@@ -175,10 +176,7 @@ var DbEncryption = class {
175
176
  */
176
177
  async function withOptimisticRetry(table, filter, mutator, opts) {
177
178
  const versionColumn = table.versionColumn;
178
- if (versionColumn === void 0) throw new require_db_error.DbError("INVALID_QUERY", [{
179
- path: "$cas",
180
- message: `withOptimisticRetry: table "${table.tableName}" has no @db.column.version column — CAS cannot be applied`
181
- }]);
179
+ if (versionColumn === void 0) throw require_db_error.invalidQuery("$cas", `withOptimisticRetry: table "${table.tableName}" has no @db.column.version column — CAS cannot be applied`);
182
180
  const maxAttempts = opts?.maxAttempts ?? 5;
183
181
  let lastSeenVersion;
184
182
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
@@ -573,6 +571,7 @@ exports.$upsert = require_ops.$upsert;
573
571
  exports.ADAPTER_FILTER_REASON = require_column_diff.ADAPTER_FILTER_REASON;
574
572
  exports.ALL_AGGREGATE_FNS = require_aggregate_fns.ALL_AGGREGATE_FNS;
575
573
  exports.ALL_BUCKET_UNITS = require_column_diff.ALL_BUCKET_UNITS;
574
+ exports.ALL_ISOLATION_LEVELS = require_column_diff.ALL_ISOLATION_LEVELS;
576
575
  exports.ALL_VIEW_CAPABILITIES = require_column_diff.ALL_VIEW_CAPABILITIES;
577
576
  exports.ApplicationIntegrity = require_column_diff.ApplicationIntegrity;
578
577
  exports.AtscriptDbReadable = require_column_diff.AtscriptDbReadable;
@@ -602,6 +601,7 @@ exports.REL_FILTER_MAX_DEPTH = require_nested_writer.REL_FILTER_MAX_DEPTH;
602
601
  exports.REL_FILTER_MAX_NODES = require_nested_writer.REL_FILTER_MAX_NODES;
603
602
  exports.RelationalFieldMapper = require_column_diff.RelationalFieldMapper;
604
603
  exports.ResolvedRelationFilter = require_nested_writer.ResolvedRelationFilter;
604
+ exports.SERVER_STAMPED_ON_UPDATE_KEYS = require_server_stamped.SERVER_STAMPED_ON_UPDATE_KEYS;
605
605
  exports.TableMetadata = require_column_diff.TableMetadata;
606
606
  exports.UniquSelect = require_column_diff.UniquSelect;
607
607
  exports.acceptedOperatorsHint = require_column_diff.acceptedOperatorsHint;
@@ -626,6 +626,7 @@ Object.defineProperty(exports, "computeInsights", {
626
626
  }
627
627
  });
628
628
  exports.containsRelationFilter = require_nested_writer.containsRelationFilter;
629
+ exports.createChangeRecorder = require_column_diff.createChangeRecorder;
629
630
  exports.createDbValidatorPlugin = require_validator.createDbValidatorPlugin;
630
631
  exports.createFailureCollector = require_column_diff.createFailureCollector;
631
632
  exports.decomposePatch = require_column_diff.decomposePatch;
@@ -635,6 +636,7 @@ exports.describeFulltext = require_column_diff.describeFulltext;
635
636
  exports.evaluateExpr = require_nested_writer.evaluateExpr;
636
637
  exports.findAncestorInSet = require_object.findAncestorInSet;
637
638
  exports.fkColumns = require_column_diff.fkColumns;
639
+ exports.fkKey = require_column_diff.fkKey;
638
640
  exports.forEachResolvedRelation = require_nested_writer.forEachResolvedRelation;
639
641
  exports.forceNavNonOptional = require_validator.forceNavNonOptional;
640
642
  exports.geoIndexNotFoundMessage = require_column_diff.geoIndexNotFoundMessage;
@@ -675,6 +677,7 @@ Object.defineProperty(exports, "isRelationOp", {
675
677
  });
676
678
  exports.isResolvedRelationFilter = require_nested_writer.isResolvedRelationFilter;
677
679
  exports.isRetryableDbError = require_db_error.isRetryableDbError;
680
+ exports.isServerStampedOnUpdate = require_server_stamped.isServerStampedOnUpdate;
678
681
  exports.isVersionExemptPatch = require_column_diff.isVersionExemptPatch;
679
682
  exports.isViewType = require_column_diff.isViewType;
680
683
  exports.jsonValueAncestor = require_column_diff.jsonValueAncestor;
@@ -694,6 +697,7 @@ exports.separateCas = require_ops.separateCas;
694
697
  exports.separateFieldOps = require_ops.separateFieldOps;
695
698
  exports.sortFieldNames = require_column_diff.sortFieldNames;
696
699
  exports.splitFulltextFields = require_column_diff.splitFulltextFields;
700
+ exports.stableJson = require_object.stableJson;
697
701
  exports.tableNameOf = require_nested_writer.tableNameOf;
698
702
  exports.translateQueryTree = require_nested_writer.translateQueryTree;
699
703
  exports.uniqueKeyTuple = require_nested_writer.uniqueKeyTuple;