@atscript/db 0.1.140 → 0.1.142

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 (49) hide show
  1. package/dist/agg.d.cts +1 -1
  2. package/dist/agg.d.mts +1 -1
  3. package/dist/{buckets-C-27xmtq.d.cts → buckets-Bv4pah66.d.cts} +225 -22
  4. package/dist/{buckets-BFG2RYRW.d.mts → buckets-CjL7F-hp.d.mts} +225 -22
  5. package/dist/{column-diff-CgxgFKzx.cjs → column-diff-CfPNcP6e.cjs} +663 -239
  6. package/dist/{column-diff-BwOA5101.mjs → column-diff-CmFNXV8C.mjs} +638 -220
  7. package/dist/column-diff-DiBbXyLA.d.cts +211 -0
  8. package/dist/column-diff-n-k5KY0u.d.mts +211 -0
  9. package/dist/derived-rules-0sKn4f5C.mjs +44 -0
  10. package/dist/derived-rules-YstgIxG-.cjs +67 -0
  11. package/dist/index.cjs +38 -4
  12. package/dist/index.d.cts +23 -6
  13. package/dist/index.d.mts +23 -6
  14. package/dist/index.mjs +34 -4
  15. package/dist/{nested-writer-FWD5oOYh.mjs → nested-writer-BO3vhbkP.mjs} +8 -4
  16. package/dist/{nested-writer-BZNCuqI6.cjs → nested-writer-DYsRxZ5f.cjs} +8 -4
  17. package/dist/object-DSN0h9lB.d.cts +30 -0
  18. package/dist/object-DSN0h9lB.d.mts +30 -0
  19. package/dist/plugin.cjs +392 -139
  20. package/dist/plugin.mjs +392 -139
  21. package/dist/rel.cjs +2 -2
  22. package/dist/rel.d.cts +2 -2
  23. package/dist/rel.d.mts +2 -2
  24. package/dist/rel.mjs +2 -2
  25. package/dist/{relation-helpers-D3Zu0Mta.d.mts → relation-helpers-B59to_dG.d.mts} +5 -4
  26. package/dist/{relation-helpers-DxrvS6ar.d.cts → relation-helpers-DQ_nRsV9.d.cts} +5 -4
  27. package/dist/{relation-loader-6ZB_5KFq.cjs → relation-loader-CgJ8bK6X.cjs} +1 -1
  28. package/dist/{relation-loader-CTFaZpVa.mjs → relation-loader-CuhEBzFU.mjs} +1 -1
  29. package/dist/shared.cjs +6 -1
  30. package/dist/shared.d.cts +48 -9
  31. package/dist/shared.d.mts +48 -9
  32. package/dist/shared.mjs +2 -2
  33. package/dist/sync.cjs +331 -105
  34. package/dist/sync.d.cts +62 -163
  35. package/dist/sync.d.mts +62 -163
  36. package/dist/sync.mjs +331 -105
  37. package/dist/{validation-utils-B4h-GW4d.mjs → validation-utils-CMR4fe2M.mjs} +99 -34
  38. package/dist/{validation-utils-Dg0hW6dn.cjs → validation-utils-DOsB4e6G.cjs} +128 -33
  39. package/dist/{validator-Drb2N-YL.d.cts → validator-Bw6ks9Hy.d.cts} +1 -11
  40. package/dist/{validator-Drb2N-YL.d.mts → validator-Bw6ks9Hy.d.mts} +1 -11
  41. package/dist/{validator-Ch7UIQl9.mjs → validator-D8bPsXPN.mjs} +54 -2
  42. package/dist/{validator-BtZbcLN2.cjs → validator-DASnXf1j.cjs} +77 -1
  43. package/dist/validator.cjs +1 -1
  44. package/dist/validator.d.cts +2 -1
  45. package/dist/validator.d.mts +2 -1
  46. package/dist/validator.mjs +1 -1
  47. package/package.json +6 -6
  48. package/dist/column-diff-BmqvgBWw.d.cts +0 -24
  49. package/dist/column-diff-DPkbZIVE.d.mts +0 -24
package/dist/agg.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- import { n as TResolvedBucket } from "./buckets-C-27xmtq.cjs";
1
+ import { n as TResolvedBucket } from "./buckets-Bv4pah66.cjs";
2
2
  import { _ as TDbAggregateFn, a as AggregateResult, c as CalendarBucketLabel, d as WeekStart, f as isAggregateExpr, h as resolveAlias, i as AggregateQuery, l as ComputedExpr, m as resolveAggregateSearch, n as AggregateExpr, o as BucketExpr, p as isBucketExpr, r as AggregateFn, s as BucketUnit, t as AggregateControls, u as ResolvedBucket, v as assertAggregateFn } from "./agg-CV7y8nC6.cjs";
3
3
  export { type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, type BucketExpr, type BucketUnit, type CalendarBucketLabel, type ComputedExpr, type ResolvedBucket, type TDbAggregateFn, type TResolvedBucket, type WeekStart, assertAggregateFn, isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
package/dist/agg.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { n as TResolvedBucket } from "./buckets-BFG2RYRW.mjs";
1
+ import { n as TResolvedBucket } from "./buckets-CjL7F-hp.mjs";
2
2
  import { _ as TDbAggregateFn, a as AggregateResult, c as CalendarBucketLabel, d as WeekStart, f as isAggregateExpr, h as resolveAlias, i as AggregateQuery, l as ComputedExpr, m as resolveAggregateSearch, n as AggregateExpr, o as BucketExpr, p as isBucketExpr, r as AggregateFn, s as BucketUnit, t as AggregateControls, u as ResolvedBucket, v as assertAggregateFn } from "./agg-D5DHsAby.mjs";
3
3
  export { type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, type BucketExpr, type BucketUnit, type CalendarBucketLabel, type ComputedExpr, type ResolvedBucket, type TDbAggregateFn, type TResolvedBucket, type WeekStart, assertAggregateFn, isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
@@ -75,13 +75,39 @@ interface TGenericLogger {
75
75
  declare const NoopLogger: TGenericLogger;
76
76
  //#endregion
77
77
  //#region src/strategies/field-mapping.d.ts
78
+ /**
79
+ * The raw (logical, pre-translation) read controls a row was fetched with —
80
+ * what {@link FieldMappingStrategy.reconstructFromRead} needs to fill
81
+ * `@db.column.derived` fields on document adapters and to prune the source
82
+ * paths the caller did not ask for. `$select` is the uniqu shape (array,
83
+ * inclusion or exclusion object); `$groupBy` the grouped query's dimensions.
84
+ * @since 0.1.141
85
+ */
86
+ interface TReadControls {
87
+ $select?: unknown;
88
+ $groupBy?: unknown;
89
+ }
78
90
  /**
79
91
  * Strategy for mapping data between logical field shapes and physical storage.
80
92
  * Two implementations: {@link DocumentFieldMapper} (nested objects, NoSQL)
81
93
  * and `RelationalFieldMapper` (flattened columns, SQL).
82
94
  */
83
95
  declare abstract class FieldMappingStrategy {
84
- abstract reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
96
+ /**
97
+ * Physical row → logical row. `controls` (since 0.1.141) are the raw read
98
+ * controls the row was fetched with — document adapters fill
99
+ * `@db.column.derived` fields from their source paths and prune sources
100
+ * the caller did not select; relational adapters ignore them (the derived
101
+ * column is a real column).
102
+ */
103
+ abstract reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata, controls?: TReadControls): Record<string, unknown>;
104
+ /**
105
+ * {@link reconstructFromRead} over every row of one read — the per-read
106
+ * work (the derived read plan on document adapters) is done once for all
107
+ * of them. The default maps the rows one by one.
108
+ * @since 0.1.141
109
+ */
110
+ reconstructRows(rows: Record<string, unknown>[], meta: TableMetadata, controls?: TReadControls): Record<string, unknown>[];
85
111
  abstract translateQuery(query: Uniquery, meta: TableMetadata): DbQuery;
86
112
  /**
87
113
  * The physical path of a logical field path — a `__`-joined column
@@ -176,7 +202,19 @@ declare abstract class FieldMappingStrategy {
176
202
  * value coercion.
177
203
  */
178
204
  declare class DocumentFieldMapper extends FieldMappingStrategy {
179
- reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata): Record<string, unknown>;
205
+ reconstructFromRead(row: Record<string, unknown>, meta: TableMetadata, controls?: TReadControls): Record<string, unknown>;
206
+ reconstructRows(rows: Record<string, unknown>[], meta: TableMetadata, controls?: TReadControls): Record<string, unknown>[];
207
+ private _derivedPlanFor;
208
+ private _reconstruct;
209
+ /** See {@link TDerivedReadPlan}. */
210
+ private derivedReadPlan;
211
+ /**
212
+ * {@link FieldMappingStrategy.physicalSelect} plus the derived-field rules
213
+ * of an exclusion projection: a derived key is not a stored path (dropping
214
+ * it just leaves the field unfilled), and the source subtree of a wanted
215
+ * derived field is fetched even when excluded (pruned after the read).
216
+ */
217
+ protected physicalSelect(select: NonNullable<UniqueryControls["$select"]>, meta: TableMetadata): NonNullable<UniqueryControls["$select"]>;
180
218
  /**
181
219
  * Every field-path position goes through `@db.column` renames
182
220
  * ({@link TableMetadata.documentPath}): filter keys, `$select` fields
@@ -384,11 +422,22 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
384
422
  */
385
423
  get metaIdPhysical(): string | null;
386
424
  /**
387
- * Physical column name of the field annotated with `@db.column.version`, or
388
- * `undefined` when the table has no version column. Used by adapters and the
389
- * REST integration to drive optimistic concurrency control (OCC).
425
+ * Logical field name of the field annotated with `@db.column.version`, or
426
+ * `undefined` when the table has no version column. This is the key used in
427
+ * `$cas: { <versionColumn>: N }`, in write payloads, in rows read back, and in
428
+ * `/meta`'s `versionColumn` — a `@db.column 'physical_name'` rename on the
429
+ * field changes only the storage column (see {@link versionColumnPhysical}).
390
430
  */
391
431
  get versionColumn(): string | undefined;
432
+ /**
433
+ * Physical column name of the `@db.column.version` field (after any
434
+ * `@db.column` rename), or `undefined` when the table has no version column.
435
+ * Adapters use it for the auto-bump, the CAS predicate, and the insert-time
436
+ * `0` backfill — all of which operate on already-mapped physical rows.
437
+ *
438
+ * @internal Adapter-facing surface; not part of the consumer API.
439
+ */
440
+ get versionColumnPhysical(): string | undefined;
392
441
  /** Dimension fields from `@db.column.dimension`. */
393
442
  get dimensions(): readonly string[];
394
443
  /** Measure fields from `@db.column.measure`. */
@@ -401,6 +450,11 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
401
450
  get defaults(): ReadonlyMap<string, TDbDefaultValue>;
402
451
  /** Fields excluded from DB via `@db.ignore`. */
403
452
  get ignoredFields(): ReadonlySet<string>;
453
+ /**
454
+ * `@db.column.derived` fields (logical name → what they read) — computed
455
+ * from a JSON leaf of the same row, never written. Since 0.1.141.
456
+ */
457
+ get derivedFields(): ReadonlyMap<string, TDerivedColumn>;
404
458
  /** Navigational fields (`@db.rel.to` / `@db.rel.from`) — not stored as columns. */
405
459
  get navFields(): ReadonlySet<string>;
406
460
  /** Physical field names used to invert exclude-mode `$select` into a SELECT list. */
@@ -424,10 +478,30 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
424
478
  get physicalToPath(): ReadonlyMap<string, string>;
425
479
  /** Descriptor for the primary ID field(s). */
426
480
  getIdDescriptor(): TIdDescriptor;
481
+ /**
482
+ * Physical rows of one read → logical rows: the field mapper's per-read
483
+ * work (the derived read plan on document adapters) is done once for all
484
+ * of them. Every read path funnels through here.
485
+ */
486
+ private _fromRead;
427
487
  /**
428
488
  * Pre-computed field metadata for adapter use.
429
489
  */
430
490
  get fieldDescriptors(): readonly TDbFieldMeta[];
491
+ /**
492
+ * The descriptors schema sync manages as columns: non-ignored, and on
493
+ * nested-object adapters without the `@db.column.derived` fields (they store
494
+ * nothing there). See `TableMetadata.columnDescriptors`.
495
+ * @since 0.1.141
496
+ */
497
+ get columnDescriptors(): readonly TDbFieldMeta[];
498
+ /**
499
+ * The columns that hold a value of their own (non-ignored, not derived) —
500
+ * what a table recreation copies and a full replace assigns. See
501
+ * `TableMetadata.storedDescriptors`.
502
+ * @since 0.1.141
503
+ */
504
+ get storedDescriptors(): readonly TDbFieldMeta[];
431
505
  /**
432
506
  * The target table of the navigation relation `navField` (since 0.1.134),
433
507
  * resolved through the table resolver this readable was built with (the
@@ -887,7 +961,15 @@ declare function isFieldRef(value: unknown): value is AtscriptQueryFieldRef;
887
961
  /** A single join in a view query plan. */
888
962
  interface TViewJoin {
889
963
  targetType: () => TAtscriptAnnotatedType;
964
+ /** Physical table (or view) joined. */
890
965
  targetTable: string;
966
+ /**
967
+ * The name the join is addressed by in conditions, filters and column
968
+ * mappings: {@link targetTable} for a plain target, the alias's type name
969
+ * for a `@db.alias` target (`JOIN "employees" AS "Manager"`).
970
+ * @since 0.1.141
971
+ */
972
+ scope: string;
891
973
  condition: AtscriptQueryNode;
892
974
  /**
893
975
  * `inner` (default) drops entry rows without a match; `left` keeps them
@@ -941,10 +1023,14 @@ interface TViewSource {
941
1023
  */
942
1024
  optional: boolean;
943
1025
  }
1026
+ /**
1027
+ * The table / view a `@db.alias` type stands for, or `undefined` when `type`
1028
+ * is not an alias.
1029
+ * @since 0.1.141
1030
+ */
1031
+ declare function aliasTargetOf(type: TAtscriptAnnotatedType | undefined): TAtscriptAnnotatedType | undefined;
944
1032
  //#endregion
945
1033
  //#region src/table/db-view.d.ts
946
- /** Primitive result type of a JSON-leaf extraction. */
947
- type TViewJsonType = "string" | "number" | "boolean";
948
1034
  interface TViewColumnMapping {
949
1035
  /**
950
1036
  * The view's own physical column — its `@db.column` / flattened `__` name
@@ -1027,10 +1113,13 @@ declare class AtscriptDbView<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
1027
1113
  private get _nested();
1028
1114
  /**
1029
1115
  * Resolves a view query field ref (join condition, `@db.view.filter`,
1030
- * conditional-aggregate predicate) to its table name and PHYSICAL source on
1116
+ * conditional-aggregate predicate) to its scope name and PHYSICAL source on
1031
1117
  * this view's adapter — the column (or document path) with `TableMetadata`'s
1032
1118
  * layout rules, the path inside a JSON column, and whether the value may be
1033
- * absent. An unqualified ref resolves against the entry table.
1119
+ * absent. An unqualified ref resolves against the entry table. `table` is
1120
+ * the physical table / view name, or the alias name for a `@db.alias`
1121
+ * target (since 0.1.141); a source that is itself a managed view resolves
1122
+ * to that view's own columns.
1034
1123
  * @throws for a ref without storage (`@db.ignore`, navigation relation) or
1035
1124
  * inside an `@db.encrypted` field (relational adapters).
1036
1125
  * @since 0.1.136
@@ -1926,12 +2015,6 @@ declare abstract class BaseDbAdapter {
1926
2015
  }
1927
2016
  //#endregion
1928
2017
  //#region src/table/table-metadata.d.ts
1929
- /**
1930
- * Finds the nearest ancestor of `path` that belongs to `set`.
1931
- * Used by both the build pipeline (in `_classifyFields`) and
1932
- * runtime reconstruction on the Readable.
1933
- */
1934
- declare function findAncestorInSet(path: string, set: ReadonlySet<string>): string | undefined;
1935
2018
  /** Returns true if the annotated type IS the `db.geoPoint` primitive (tag-based). */
1936
2019
  declare function isGeoPointType(fieldType: TAtscriptAnnotatedType): boolean;
1937
2020
  /**
@@ -1955,6 +2038,22 @@ declare class TableMetadata {
1955
2038
  readonly nestedObjects: boolean;
1956
2039
  flatMap: Map<string, TAtscriptAnnotatedType>;
1957
2040
  fieldDescriptors: readonly TDbFieldMeta[];
2041
+ /**
2042
+ * The descriptors schema sync manages as columns of this table: the
2043
+ * non-ignored ones — on nested-object adapters without the
2044
+ * `@db.column.derived` fields, which store nothing there (their
2045
+ * `physicalName` is the source's document path). The desired side of every
2046
+ * column diff and the column list of a fresh create.
2047
+ * @since 0.1.141
2048
+ */
2049
+ columnDescriptors: readonly TDbFieldMeta[];
2050
+ /**
2051
+ * The columns that hold a value of their own — non-ignored and not derived
2052
+ * (a generated column is computed, never assigned): what a table recreation
2053
+ * copies and a full replace assigns.
2054
+ * @since 0.1.141
2055
+ */
2056
+ storedDescriptors: readonly TDbFieldMeta[];
1958
2057
  primaryKeys: string[];
1959
2058
  preferredId: string[];
1960
2059
  originalMetaIdFields: string[];
@@ -1975,6 +2074,13 @@ declare class TableMetadata {
1975
2074
  quantityRefByField: Map<string, string>;
1976
2075
  /** Logical paths annotated with `@db.encrypted` — stored as one opaque ciphertext column. */
1977
2076
  encryptedFields: Set<string>;
2077
+ /**
2078
+ * `@db.column.derived` fields (top-level logical name → what they read),
2079
+ * since 0.1.141. A generated column on relational adapters; on nested-object
2080
+ * adapters nothing is stored — {@link physicalPath} maps the name to the
2081
+ * source's document path and reads fill the field from it.
2082
+ */
2083
+ derivedFields: Map<string, TDerivedColumn>;
1978
2084
  pathToPhysical: Map<string, string>;
1979
2085
  physicalToPath: Map<string, string>;
1980
2086
  flattenedParents: Set<string>;
@@ -2027,7 +2133,10 @@ declare class TableMetadata {
2027
2133
  private _columnFromMap;
2028
2134
  constructor(nestedObjects: boolean);
2029
2135
  get isBuilt(): boolean;
2030
- /** {@link documentPath} over this table's `columnMap`. */
2136
+ /**
2137
+ * {@link documentPath} over this table's `columnMap`. A `@db.column.derived`
2138
+ * field has no stored path of its own: it maps to its source leaf.
2139
+ */
2031
2140
  documentPath(path: string): string;
2032
2141
  /**
2033
2142
  * Physical name of a logical path: the document path on nested-object
@@ -2035,6 +2144,13 @@ declare class TableMetadata {
2035
2144
  * `@db.column` override).
2036
2145
  */
2037
2146
  physicalPath(logical: string): string;
2147
+ /**
2148
+ * Drops the `@db.column.derived` keys of a write payload in place (a
2149
+ * derived field is always top-level): the column is computed from the row
2150
+ * and never written, so a row read back can be written back as-is.
2151
+ * @since 0.1.141
2152
+ */
2153
+ stripDerived(data: Record<string, unknown>): void;
2038
2154
  /**
2039
2155
  * Runs the full metadata compilation pipeline. Called once by
2040
2156
  * `AtscriptDbReadable._ensureBuilt()` on first metadata access.
@@ -2067,6 +2183,14 @@ declare class TableMetadata {
2067
2183
  * from pre-compiled types still fail fast.
2068
2184
  */
2069
2185
  private _validateEncryptedField;
2186
+ /**
2187
+ * Build-time diagnostics for `@db.column.derived` (rules D1–D8 of the
2188
+ * derived-column design) — the runtime mirror of the compile-time check, so
2189
+ * pre-compiled models fail fast — and the resolution of what the field
2190
+ * reads: the source leaf's JSON column + path (relational layout, via the
2191
+ * views' `resolveViewSource`) and its declared type.
2192
+ */
2193
+ private _validateDerivedField;
2070
2194
  /** Build-time diagnostics for `@db.index.geo` (§3 of the geo-index spec). */
2071
2195
  private _validateGeoIndexField;
2072
2196
  private _addIndexField;
@@ -2188,6 +2312,13 @@ interface TFieldMeta {
2188
2312
  * (`bucketUnits`). Since 0.1.132.
2189
2313
  */
2190
2314
  bucketable?: true;
2315
+ /**
2316
+ * Present (true) when the field is a `@db.column.derived` column: its value
2317
+ * is computed from a `@db.json` field of the same row and is never written
2318
+ * — a write payload carrying it is accepted and the key is dropped. UIs
2319
+ * render it read-only. Since 0.1.141.
2320
+ */
2321
+ derived?: true;
2191
2322
  }
2192
2323
  /** Built-in CRUD operation names; map 1:1 to public method names. */
2193
2324
  type TCrudOp = "query" | "pages" | "one" | "geo" | "insert" | "update" | "replace" | "remove";
@@ -2213,9 +2344,11 @@ interface TMetaResponse {
2213
2344
  actions: TDbActionInfo[];
2214
2345
  crud: TCrudPermissions;
2215
2346
  /**
2216
- * Physical column name annotated with `@db.column.version`, when the table
2217
- * opts into optimistic concurrency control (OCC). Absent for tables without
2218
- * the annotation, i.e. last-write-wins (default) behavior.
2347
+ * Logical field name of the `@db.column.version` field, when the table opts
2348
+ * into optimistic concurrency control (OCC) — the key a client sends in a
2349
+ * write body / `$cas` and reads back on rows. A `@db.column` rename on the
2350
+ * field changes only the storage column, never this name. Absent for tables
2351
+ * without the annotation, i.e. last-write-wins (default) behavior.
2219
2352
  */
2220
2353
  versionColumn?: string;
2221
2354
  /**
@@ -2288,11 +2421,13 @@ interface TDbActionInfo {
2288
2421
  /**
2289
2422
  * Stringified gate predicate (`fn.toString()`). Present only for `'row'`
2290
2423
  * and `'rows'` level actions whose decorator declared a `disabled` function.
2291
- * The function is the batch shape `(rows: TRow[]) => boolean[]` (sync). The
2424
+ * The function is the batch shape `(rows: TRow[]) => (boolean | string)[]`
2425
+ * (sync). Per entry: truthy = disabled — test truthiness, not `=== true`; a
2426
+ * non-empty string is also the human-readable reason (since 0.1.141). The
2292
2427
  * UI evaluates against a level-specific scope to grey-out / hide the
2293
2428
  * button. The server has already enforced this predicate before the
2294
2429
  * action's handler ran — the server is authoritative; this field is purely
2295
- * a UI hint.
2430
+ * a UI hint. Server-evaluated reasons arrive per row in `$disabledReasons`.
2296
2431
  */
2297
2432
  disabled?: string;
2298
2433
  /**
@@ -2385,6 +2520,26 @@ interface TIdentification {
2385
2520
  source: string;
2386
2521
  }
2387
2522
  type TDbStorageType = "column" | "flattened" | "json";
2523
+ /** Primitive result type of a JSON-leaf extraction (view JSON leaves, derived columns). */
2524
+ type TViewJsonType = "string" | "number" | "boolean";
2525
+ /**
2526
+ * Where a `@db.column.derived` field reads its value from: a primitive leaf
2527
+ * inside a `@db.json` field of the SAME table (since 0.1.141).
2528
+ */
2529
+ interface TDerivedColumn {
2530
+ /** Logical path of the source leaf (`payload.customer.id`). */
2531
+ sourcePath: string;
2532
+ /**
2533
+ * Physical column of the JSON field the leaf lives in (relational layout:
2534
+ * `@db.column` rename applied, unqualified) — what the generated column's
2535
+ * expression reads.
2536
+ */
2537
+ sourceColumn: string;
2538
+ /** Segments inside {@link sourceColumn} down to the leaf. */
2539
+ jsonPath: string[];
2540
+ /** Declared leaf type — the extraction's type guard. */
2541
+ type: TViewJsonType;
2542
+ }
2388
2543
  interface TDbFieldMeta {
2389
2544
  /** The dot-notation path to this field (logical name). */
2390
2545
  path: string;
@@ -2454,6 +2609,16 @@ interface TDbFieldMeta {
2454
2609
  * Adapters map this to their native geo storage (e.g. MongoDB GeoJSON Point).
2455
2610
  */
2456
2611
  isGeoPoint?: boolean;
2612
+ /**
2613
+ * `@db.column.derived` (since 0.1.141): the value is computed from a JSON
2614
+ * leaf of the same row. Relational adapters store it as a generated column
2615
+ * (`physicalName` is that column); document adapters store nothing —
2616
+ * `physicalName` is the source's document path, which filters, sorts,
2617
+ * projections and indexes address, and reads fill the field from it.
2618
+ * Never written: write payloads drop it, `$inc` / `$dec` / `$mul` on it are
2619
+ * rejected.
2620
+ */
2621
+ derived?: TDerivedColumn;
2457
2622
  }
2458
2623
  interface TValueFormatterPair {
2459
2624
  /** Converts a JS value to storage representation (write + filter paths). */
@@ -2486,7 +2651,23 @@ interface TExistingColumn {
2486
2651
  pk: boolean;
2487
2652
  /** Serialized default value (e.g., "'active'", "NULL"). */
2488
2653
  dflt_value?: string;
2654
+ /**
2655
+ * `true` for a generated (computed) column — what a `@db.column.derived`
2656
+ * field is stored as on relational adapters. Adapters that introspect it
2657
+ * set it (SQLite `table_xinfo.hidden`, MySQL `EXTRA`, PostgreSQL
2658
+ * `is_generated`); the column diff then decides kind changes by it.
2659
+ * @since 0.1.141
2660
+ */
2661
+ generated?: boolean;
2489
2662
  }
2663
+ /**
2664
+ * Why a `@db.column.derived` column is dropped and re-added by schema sync:
2665
+ * `kind` — a regular column became derived or a derived one became regular;
2666
+ * `expression` — the source column, path or leaf type changed (compared with
2667
+ * the stored snapshot); `type` — the mapped column type differs.
2668
+ * @since 0.1.141
2669
+ */
2670
+ type TDerivedChangeReason = "kind" | "expression" | "type";
2490
2671
  /** Result of comparing desired schema against existing database columns. */
2491
2672
  interface TColumnDiff {
2492
2673
  added: TDbFieldMeta[];
@@ -2513,6 +2694,28 @@ interface TColumnDiff {
2513
2694
  oldName: string;
2514
2695
  conflictsWith: string;
2515
2696
  }>;
2697
+ /**
2698
+ * Derived columns whose live column no longer matches the model and must
2699
+ * be dropped and re-added (a generated column's expression cannot be
2700
+ * altered in place): `kind` — a regular column became derived or a derived
2701
+ * one became regular (the column-drop policy applies: normal mode rebuilds,
2702
+ * safe mode skips); `expression` — the source path or leaf type in the
2703
+ * stored snapshot differs (engines normalize expression text, so the
2704
+ * snapshot is the baseline); `type` — the mapped column type differs.
2705
+ * Absent (or empty) when nothing changed.
2706
+ *
2707
+ * Invariant: a derived field, and a live generated column, is reported
2708
+ * HERE only — never in `typeChanged`, `nullableChanged` or
2709
+ * `defaultChanged` (a generated column is nullable and has no DEFAULT). On
2710
+ * nested-object adapters derived fields are not part of the diff at all
2711
+ * (`TableMetadata.columnDescriptors` leaves them out: they store nothing
2712
+ * there), so `added` never carries one either.
2713
+ * @since 0.1.141
2714
+ */
2715
+ derivedChanged?: Array<{
2716
+ field: TDbFieldMeta;
2717
+ reason: TDerivedChangeReason;
2718
+ }>;
2516
2719
  /**
2517
2720
  * The primary-key FIELD SET differs between the live table and the model
2518
2721
  * (set semantics — a composite-key reorder is not a change, consistent with
@@ -2906,4 +3109,4 @@ declare function isJsonValueField(fd: TDbFieldMeta): boolean;
2906
3109
  */
2907
3110
  declare function jsonValueAncestor(path: string, jsonValueParents: ReadonlySet<string>): string | undefined;
2908
3111
  //#endregion
2909
- export { TDbWriteGuard as $, AtscriptDbReadable as $t, TDbActionInfo as A, findAncestorInSet as At, TDbIndex as B, TViewJsonType as Bt, OwnPropsOf$1 as C, TWriteOptions as Ct, TColumnDiff as D, UniqueryControls$1 as Dt, TCascadeTarget as E, Uniquery$1 as Et, TDbDefaultFn as F, DbSpace as Ft, TDbObjectKind as G, AtscriptRef as Gt, TDbIndexType as H, AtscriptQueryComparison as Ht, TDbDefaultValue as I, TAdapterFactory as It, TDbRemoveGuard as J, isFieldRef as Jt, TDbReferentialAction as K, TViewJoin as Kt, TDbDeleteResult as L, TDbSpaceOptions as Lt, TDbActionLevel as M, isGeoPointType as Mt, TDbActionProcessor as N, ALL_BUCKET_UNITS as Nt, TCrudOp as O, WithRelation$1 as Ot, TDbCollation as P, BaseDbAdapter as Pt, TDbWriteAction as Q, NativeIntegrity as Qt, TDbFieldMeta as R, AtscriptDbView as Rt, NullableOptional as S, TValueFormatterPair as St, TCascadeResolver as T, TypedWithRelation as Tt, TDbInsertManyResult as U, AtscriptQueryFieldRef$1 as Ut, TDbIndexField as V, isAtscriptDbView as Vt, TDbInsertResult as W, AtscriptQueryNode$1 as Wt, TDbStorageType as X, AtscriptDbTable as Xt, TDbRemoveGuardContext as Y, translateQueryTree as Yt, TDbUpdateResult as Z, IntegrityStrategy as Zt, DbRow as _, TSearchIndexInfo as _t, jsonValueAncestor as a, FieldMappingStrategy as an, TExistingTableOption as at, FlatOf$1 as b, TTableResolver as bt, AggregateControls as c, UniquSelect as cn, TFkLookupTarget as ct, AggregateQuery$1 as d, TIdentification as dt, DbResponse as en, TDbWriteGuardContext as et, AggregateResult as f, TMetaResponse as ft, DbQuery as g, TRelationInfo as gt, DbPatch as h, TReferencingForeignKey as ht, isJsonValueField as i, DocumentFieldMapper as in, TExistingForeignKey as it, TDbActionIntent as j, isGeoIndexableType as jt, TCrudPermissions as k, TableMetadata as kt, AggregateExpr$1 as l, TIdDescriptor as lt, DbControls as m, TPrimaryKeyChange as mt, TResolvedBucket as n, DbEncryption as nn, TEnsureTableOptions as nt, normalizeComputedSelect as o, NoopLogger as on, TFieldMeta as ot, AtscriptDbWritable as p, TMetadataOverrides as pt, TDbRelation as q, TViewPlan as qt, isBucketableField as r, TDbEncryptionOptions as rn, TExistingColumn as rt, resolveCalendarBuckets as s, TGenericLogger as sn, TFkLookupResolver as st, TBucketFieldSource as t, resolveDesignType as tn, TDeleteOptions as tt, AggregateFn$1 as u, TIdResolveOptions as ut, FieldOpsFor as v, TSyncColumnResult as vt, PrimaryKeyOf$1 as w, TWriteTableResolver as wt, NavPropsOf$1 as x, TTouchManyOptions as xt, FilterExpr$1 as y, TTableOptionDiff as yt, TDbForeignKey as z, TViewColumnMapping as zt };
3112
+ export { TDbWriteGuard as $, IntegrityStrategy as $t, TDbActionInfo as A, UniqueryControls$1 as At, TDbIndex as B, AtscriptDbView as Bt, OwnPropsOf$1 as C, TTouchManyOptions as Ct, TColumnDiff as D, TWriteTableResolver as Dt, TCascadeTarget as E, TWriteOptions as Et, TDbDefaultFn as F, ALL_BUCKET_UNITS as Ft, TDbObjectKind as G, AtscriptQueryFieldRef$1 as Gt, TDbIndexType as H, isAtscriptDbView as Ht, TDbDefaultValue as I, BaseDbAdapter as It, TDbRemoveGuard as J, TViewJoin as Jt, TDbReferentialAction as K, AtscriptQueryNode$1 as Kt, TDbDeleteResult as L, DbSpace as Lt, TDbActionLevel as M, TableMetadata as Mt, TDbActionProcessor as N, isGeoIndexableType as Nt, TCrudOp as O, TypedWithRelation as Ot, TDbCollation as P, isGeoPointType as Pt, TDbWriteAction as Q, AtscriptDbTable as Qt, TDbFieldMeta as R, TAdapterFactory as Rt, NullableOptional as S, TTableResolver as St, TCascadeResolver as T, TViewJsonType as Tt, TDbInsertManyResult as U, aliasTargetOf as Ut, TDbIndexField as V, TViewColumnMapping as Vt, TDbInsertResult as W, AtscriptQueryComparison as Wt, TDbStorageType as X, isFieldRef as Xt, TDbRemoveGuardContext as Y, TViewPlan as Yt, TDbUpdateResult as Z, translateQueryTree as Zt, DbRow as _, TReferencingForeignKey as _t, jsonValueAncestor as a, TDbEncryptionOptions as an, TExistingColumn as at, FlatOf$1 as b, TSyncColumnResult as bt, AggregateControls as c, TReadControls as cn, TFieldMeta as ct, AggregateQuery$1 as d, UniquSelect as dn, TIdDescriptor as dt, NativeIntegrity as en, TDbWriteGuardContext as et, AggregateResult as f, TIdResolveOptions as ft, DbQuery as g, TPrimaryKeyChange as gt, DbPatch as h, TMetadataOverrides as ht, isJsonValueField as i, DbEncryption as in, TEnsureTableOptions as it, TDbActionIntent as j, WithRelation$1 as jt, TCrudPermissions as k, Uniquery$1 as kt, AggregateExpr$1 as l, NoopLogger as ln, TFkLookupResolver as lt, DbControls as m, TMetaResponse as mt, TResolvedBucket as n, DbResponse as nn, TDerivedChangeReason as nt, normalizeComputedSelect as o, DocumentFieldMapper as on, TExistingForeignKey as ot, AtscriptDbWritable as p, TIdentification as pt, TDbRelation as q, AtscriptRef as qt, isBucketableField as r, resolveDesignType as rn, TDerivedColumn as rt, resolveCalendarBuckets as s, FieldMappingStrategy as sn, TExistingTableOption as st, TBucketFieldSource as t, AtscriptDbReadable as tn, TDeleteOptions as tt, AggregateFn$1 as u, TGenericLogger as un, TFkLookupTarget as ut, FieldOpsFor as v, TRelationInfo as vt, PrimaryKeyOf$1 as w, TValueFormatterPair as wt, NavPropsOf$1 as x, TTableOptionDiff as xt, FilterExpr$1 as y, TSearchIndexInfo as yt, TDbForeignKey as z, TDbSpaceOptions as zt };