@atscript/db 0.1.134 → 0.1.136

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 (45) hide show
  1. package/dist/agg-CV7y8nC6.d.cts +53 -0
  2. package/dist/agg-D5DHsAby.d.mts +53 -0
  3. package/dist/agg.cjs +2 -0
  4. package/dist/agg.d.cts +3 -35
  5. package/dist/agg.d.mts +3 -35
  6. package/dist/agg.mjs +2 -1
  7. package/dist/aggregate-fns-CGBv3E8S.cjs +87 -0
  8. package/dist/aggregate-fns-CfsveE1w.mjs +58 -0
  9. package/dist/{buckets-Bo2IcPZ_.d.cts → buckets-kKY0RKYN.d.cts} +61 -17
  10. package/dist/{buckets-Bys2QXyk.d.mts → buckets-y4EzoX7D.d.mts} +61 -17
  11. package/dist/{db-space-DtGx5HIC.d.cts → db-space-BX4K3vb6.d.mts} +127 -8
  12. package/dist/{db-space-grfuZcPR.d.mts → db-space-ClG41vJh.d.cts} +127 -8
  13. package/dist/{db-view-pgm2dHIo.cjs → db-view-BAzhEUxB.cjs} +391 -90
  14. package/dist/{db-view-B64IpZ2j.mjs → db-view-BrAtbaOx.mjs} +386 -91
  15. package/dist/index.cjs +17 -3
  16. package/dist/index.d.cts +12 -10
  17. package/dist/index.d.mts +12 -10
  18. package/dist/index.mjs +14 -4
  19. package/dist/{nested-writer-wk1EFUNY.cjs → nested-writer-BZNCuqI6.cjs} +16 -2
  20. package/dist/{nested-writer-CqL24ojl.mjs → nested-writer-FWD5oOYh.mjs} +11 -3
  21. package/dist/plugin.cjs +215 -75
  22. package/dist/plugin.mjs +215 -76
  23. package/dist/rel.cjs +2 -2
  24. package/dist/rel.d.cts +2 -20
  25. package/dist/rel.d.mts +2 -20
  26. package/dist/rel.mjs +2 -2
  27. package/dist/relation-helpers-BVjQflL_.d.cts +30 -0
  28. package/dist/relation-helpers-D4haLo1n.d.mts +30 -0
  29. package/dist/{relation-loader-BD4xANQJ.cjs → relation-loader-6ZB_5KFq.cjs} +1 -1
  30. package/dist/{relation-loader-B68R1LET.mjs → relation-loader-CTFaZpVa.mjs} +1 -1
  31. package/dist/shared.cjs +5 -1
  32. package/dist/shared.d.cts +16 -3
  33. package/dist/shared.d.mts +16 -3
  34. package/dist/shared.mjs +2 -2
  35. package/dist/sync.cjs +37 -10
  36. package/dist/sync.d.cts +24 -4
  37. package/dist/sync.d.mts +24 -4
  38. package/dist/sync.mjs +37 -10
  39. package/dist/{validation-utils-MWOP1Ts4.mjs → validation-utils-B4h-GW4d.mjs} +29 -7
  40. package/dist/{validation-utils-B7SXPkm7.cjs → validation-utils-Dg0hW6dn.cjs} +52 -6
  41. package/dist/{validator-CewfnGZj.d.mts → validator-Drb2N-YL.d.cts} +1 -1
  42. package/dist/{validator-CewfnGZj.d.cts → validator-Drb2N-YL.d.mts} +1 -1
  43. package/dist/validator.d.cts +1 -1
  44. package/dist/validator.d.mts +1 -1
  45. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import { f as TFieldOps } from "./ops-AqhV7s9o.mjs";
2
2
  import { FlatOf, FlatOf as FlatOf$1, NavPropsOf, NavPropsOf as NavPropsOf$1, OwnPropsOf, OwnPropsOf as OwnPropsOf$1, PrimaryKeyOf, PrimaryKeyOf as PrimaryKeyOf$1, TAtscriptAnnotatedType, TAtscriptDataType, TAtscriptTypeObject, TMetadataMap, TSerializedAnnotatedType, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
3
- import { AggregateControls, AggregateExpr, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateQuery, AggregateQuery as AggregateQuery$1, AggregateResult, BucketUnit, FieldOpsFor, FilterExpr, FilterExpr as FilterExpr$1, ResolvedBucket, TypedWithRelation, Uniquery, Uniquery as Uniquery$1, UniqueryControls, UniqueryControls as UniqueryControls$1, UniqueryInsights, WithRelation, WithRelation as WithRelation$1 } from "@uniqu/core";
3
+ import { AggregateControls, AggregateExpr, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateFn as AggregateFn$1, AggregateQuery, AggregateQuery as AggregateQuery$1, AggregateResult, BucketUnit, FieldOpsFor, FilterExpr, FilterExpr as FilterExpr$1, ResolvedBucket, TypedWithRelation, Uniquery, Uniquery as Uniquery$1, UniqueryControls, UniqueryControls as UniqueryControls$1, UniqueryInsights, WithRelation, WithRelation as WithRelation$1 } from "@uniqu/core";
4
4
 
5
5
  //#region src/query/uniqu-select.d.ts
6
6
  /**
@@ -15,7 +15,7 @@ import { AggregateControls, AggregateExpr, AggregateExpr as AggregateExpr$1, Agg
15
15
  * An array `$select` holds plain field names and computed entries —
16
16
  * aggregates (`{ $fn, $field }`, {@link aggregates}) and calendar buckets
17
17
  * (`{ $bucket, $field }`, {@link buckets}). Entries arrive normalized
18
- * (`resolveCalendarBuckets` rejects any other shape before translation).
18
+ * (`normalizeComputedSelect` rejects any other shape before translation).
19
19
  */
20
20
  declare class UniquSelect {
21
21
  private static readonly UNRESOLVED;
@@ -101,7 +101,7 @@ declare abstract class FieldMappingStrategy {
101
101
  * equals a field name).
102
102
  *
103
103
  * `buckets` are the query's calendar buckets as the core's normalizer
104
- * resolved them (`resolveCalendarBuckets` — `AtscriptDbReadable.aggregate`
104
+ * resolved them (`normalizeComputedSelect` — `AtscriptDbReadable.aggregate`
105
105
  * runs it before the guards); they reach adapters with `field` made
106
106
  * physical and the source descriptor as `fd`.
107
107
  */
@@ -111,7 +111,10 @@ declare abstract class FieldMappingStrategy {
111
111
  /**
112
112
  * `$select` with its field paths made physical: array-form names and
113
113
  * computed `$field`s (`'*'` kept), or the keys of the object
114
- * (inclusion / exclusion) form.
114
+ * (inclusion / exclusion) form. An aggregate's output alias is fixed
115
+ * (`$as`) from its LOGICAL field first, so a default alias never leaks a
116
+ * physical name (`sum(amount)` over `@db.column 'amount_cents'` stays
117
+ * `sum_amount`); a bucket's alias is already resolved.
115
118
  */
116
119
  protected physicalSelect(select: NonNullable<UniqueryControls["$select"]>, meta: TableMetadata): NonNullable<UniqueryControls["$select"]>;
117
120
  /** `$sort` with physical keys; computed `aliases` (grouped queries) pass through. */
@@ -478,13 +481,15 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
478
481
  *
479
482
  * Validates:
480
483
  * - `$select` computed entries and calendar buckets (the shared normalizer,
481
- * `resolveCalendarBuckets`: shapes, unit, zone, alias, grouping)
484
+ * `normalizeComputedSelect`: shapes, unit, zone, alias, grouping)
482
485
  * - Plain fields in $select are a subset of $groupBy
483
486
  * - When dimensions/measures are defined (strict mode): $groupBy fields
484
- * must be dimensions, aggregate $field values must be measures (or '*')
487
+ * must be dimensions, aggregate $field values must be measures (or '*';
488
+ * a `countDistinct` field may also be a dimension)
485
489
  * - the path guard (a bucket source must pass `bucketSourceVerdict` —
486
490
  * timestamp type, no JSON ancestor, a dimension in strict mode, an
487
- * adapter with calendar buckets) and the adapter's calendar-bucket units
491
+ * adapter with calendar buckets), the adapter's aggregate functions
492
+ * (`AGG_FN_NOT_SUPPORTED`) and calendar-bucket units
488
493
  * (`BUCKET_NOT_SUPPORTED`)
489
494
  *
490
495
  * Translates field names, delegates to adapter.aggregate(),
@@ -497,6 +502,8 @@ declare class AtscriptDbReadable<T extends TAtscriptAnnotatedType = TAtscriptAnn
497
502
  canFilterField(fd: TDbFieldMeta): boolean;
498
503
  /** Calendar-bucket units the adapter can group by (proxies adapter capability; empty = none). */
499
504
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
505
+ /** Aggregate functions the adapter renders (proxies adapter capability). @since 0.1.136 */
506
+ aggregateFns(): ReadonlySet<AggregateFn>;
500
507
  /** Whether the adapter can sort by a given field (proxies adapter capability). */
501
508
  canSortField(fd: TDbFieldMeta): boolean;
502
509
  /** Returns available search indexes from the adapter. */
@@ -799,6 +806,18 @@ declare abstract class BaseDbAdapter {
799
806
  * out-of-range source, uniqu's `bucketLabel` semantics). Since 0.1.132.
800
807
  */
801
808
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
809
+ /**
810
+ * Aggregate functions (`{ $fn, $field }` in an aggregate `$select`) this
811
+ * adapter renders. The default is `sum`, `count`, `avg`, `min` and `max`;
812
+ * an adapter that also implements `countDistinct` (distinct non-null
813
+ * values) returns `ALL_AGGREGATE_FNS`. The core rejects a known function
814
+ * missing from this set with `AGG_FN_NOT_SUPPORTED` before dispatch, so
815
+ * `aggregate()` only ever receives functions listed here; moost-db's
816
+ * `/meta` advertises the set as `aggregateFns`.
817
+ *
818
+ * @since 0.1.136
819
+ */
820
+ aggregateFns(): ReadonlySet<AggregateFn>;
802
821
  /**
803
822
  * Whether this adapter enforces foreign key constraints natively.
804
823
  * When `true`, the generic layer skips application-level cascade/setNull
@@ -1468,8 +1487,6 @@ declare class TableMetadata {
1468
1487
  * Builds the bidirectional pathToPhysical / physicalToPath maps.
1469
1488
  */
1470
1489
  private _classifyFields;
1471
- /** Returns the `__`-separated parent prefix for a dot-separated path, or empty string for top-level paths. */
1472
- private _flattenedPrefix;
1473
1490
  /** Nearest `@db.encrypted` ancestor of `path` (exclusive), or `undefined`. */
1474
1491
  /**
1475
1492
  * Indexes non-ignored descriptors by logical path and retains the JSON-parent
@@ -1619,6 +1636,14 @@ interface TMetaResponse {
1619
1636
  * none. Since 0.1.132.
1620
1637
  */
1621
1638
  bucketUnits?: BucketUnit[];
1639
+ /**
1640
+ * Aggregate functions the adapter renders (`{ $fn }` in an aggregate
1641
+ * `$select`, URL `sum(field)` / `countDistinct(field)` …) — see
1642
+ * `BaseDbAdapter.aggregateFns()`.
1643
+ *
1644
+ * @since 0.1.136
1645
+ */
1646
+ aggregateFns?: AggregateFn[];
1622
1647
  }
1623
1648
  /** Where the action applies on the UI. */
1624
1649
  type TDbActionLevel = "table" | "row" | "rows";
@@ -1684,12 +1709,24 @@ interface TDbActionInfo {
1684
1709
  disabled?: string;
1685
1710
  /**
1686
1711
  * Name of the `.as` interface the action's `@InputForm()` parameter expects
1687
- * (the compiled class's `.name`). Present only when the handler declares an
1688
- * `@InputForm(FormType)` parameter. Clients fetch the serialized schema via
1689
- * `GET /meta/form/:name` on the same controller and render a form to
1690
- * collect the `input` field of the action's request envelope.
1712
+ * (the compiled class's `.name`). Present for an `@InputForm(FormType)`
1713
+ * parameter or a class-level `inputForm` entry. Clients fetch the
1714
+ * serialized schema via `GET /meta/form/:name` on the same controller and
1715
+ * render a form to collect the `input` field of the action's request
1716
+ * envelope. A class-level entry may name a form served elsewhere — then
1717
+ * {@link formUrl} is present and clients fetch it instead of `meta/form/:name`.
1691
1718
  */
1692
1719
  inputForm?: string;
1720
+ /**
1721
+ * Server-absolute path of the serialized form schema —
1722
+ * same convention as `value` for `'backend'` actions: clients prefix
1723
+ * their base URL. Present only together with {@link inputForm}, when the
1724
+ * form is served by another endpoint than this controller's
1725
+ * `meta/form/:name`; clients fetch it instead of the relative route.
1726
+ *
1727
+ * @since 0.1.136
1728
+ */
1729
+ formUrl?: string;
1693
1730
  }
1694
1731
  interface TDbInsertResult {
1695
1732
  insertedId: unknown;
@@ -2217,13 +2254,15 @@ interface TBucketFieldSource {
2217
2254
  navFields: ReadonlySet<string>;
2218
2255
  }
2219
2256
  /**
2220
- * The one normalizer of `$select` computed entries (since 0.1.132) — uniqu's
2257
+ * The one normalizer of `$select` computed entries — uniqu's
2221
2258
  * `resolveBuckets` (entry shapes, unit, time zone canonicalization, week
2222
2259
  * start, alias syntax and uniqueness, "grouped queries only", "must also
2223
2260
  * appear in $groupBy", string `$groupBy` entries) with the table's names as
2224
2261
  * the collision set: a bucket alias may not equal a logical path, a physical
2225
2262
  * column or a navigation field, so a label is never reverse-mapped as a
2226
- * column.
2263
+ * column. Aggregate entries are checked against `SUPPORTED_AGGREGATE_FNS`
2264
+ * (and `'*'` is `count`'s only); whether the adapter renders a function is
2265
+ * `guardAggregate`'s (`aggregateFns()` → `AGG_FN_NOT_SUPPORTED`).
2227
2266
  *
2228
2267
  * Which layer validates what:
2229
2268
  * - **Shapes** (this normalizer) run FIRST at every entry point — the core's
@@ -2245,10 +2284,15 @@ interface TBucketFieldSource {
2245
2284
  *
2246
2285
  * @throws DbError `INVALID_QUERY` carrying every issue (`path` `$select` / `$groupBy`).
2247
2286
  */
2248
- declare function resolveCalendarBuckets(controls: {
2287
+ declare function normalizeComputedSelect(controls: {
2249
2288
  $select?: unknown;
2250
2289
  $groupBy?: unknown;
2251
2290
  } | undefined, fields: TBucketFieldSource, aggregate?: boolean): ResolvedBucket[];
2291
+ /**
2292
+ * @deprecated since 0.1.136 — renamed {@link normalizeComputedSelect} (it
2293
+ * normalizes every computed `$select` entry, aggregates included).
2294
+ */
2295
+ declare const resolveCalendarBuckets: typeof normalizeComputedSelect;
2252
2296
  /**
2253
2297
  * Whether a field's TYPE allows it to be the source of a calendar bucket: a
2254
2298
  * `number` / `integer` leaf carrying the `timestamp` tag
@@ -2274,4 +2318,4 @@ declare function isJsonValueField(fd: TDbFieldMeta): boolean;
2274
2318
  */
2275
2319
  declare function jsonValueAncestor(path: string, jsonValueParents: ReadonlySet<string>): string | undefined;
2276
2320
  //#endregion
2277
- export { TDbWriteGuardContext as $, TDbActionIntent as A, isGeoIndexableType as At, TDbIndexField as B, FieldMappingStrategy as Bt, PrimaryKeyOf$1 as C, TWriteTableResolver as Ct, TCrudOp as D, WithRelation$1 as Dt, TColumnDiff as E, UniqueryControls$1 as Et, TDbDefaultValue as F, DbResponse as Ft, TDbReferentialAction as G, TDbInsertManyResult as H, TGenericLogger as Ht, TDbDeleteResult as I, resolveDesignType as It, TDbRemoveGuardContext as J, TDbRelation as K, TDbFieldMeta as L, DbEncryption as Lt, TDbActionProcessor as M, ALL_BUCKET_UNITS as Mt, TDbCollation as N, BaseDbAdapter as Nt, TCrudPermissions as O, TableMetadata as Ot, TDbDefaultFn as P, AtscriptDbReadable as Pt, TDbWriteGuard as Q, TDbForeignKey as R, TDbEncryptionOptions as Rt, OwnPropsOf$1 as S, TWriteOptions as St, TCascadeTarget as T, Uniquery$1 as Tt, TDbInsertResult as U, UniquSelect as Ut, TDbIndexType as V, NoopLogger as Vt, TDbObjectKind as W, TDbUpdateResult as X, TDbStorageType as Y, TDbWriteAction as Z, FieldOpsFor as _, TSyncColumnResult as _t, jsonValueAncestor as a, TFieldMeta as at, NavPropsOf$1 as b, TTouchManyOptions as bt, AggregateExpr$1 as c, TIdDescriptor as ct, AggregateResult as d, TMetaResponse as dt, TDeleteOptions as et, AtscriptDbWritable as f, TMetadataOverrides as ft, DbRow as g, TSearchIndexInfo as gt, DbQuery as h, TRelationInfo as ht, isJsonValueField as i, TExistingTableOption as it, TDbActionLevel as j, isGeoPointType as jt, TDbActionInfo as k, findAncestorInSet as kt, AggregateFn as l, TIdResolveOptions as lt, DbPatch as m, TReferencingForeignKey as mt, TResolvedBucket as n, TExistingColumn as nt, resolveCalendarBuckets as o, TFkLookupResolver as ot, DbControls as p, TPrimaryKeyChange as pt, TDbRemoveGuard as q, isBucketableField as r, TExistingForeignKey as rt, AggregateControls as s, TFkLookupTarget as st, TBucketFieldSource as t, TEnsureTableOptions as tt, AggregateQuery$1 as u, TIdentification as ut, FilterExpr$1 as v, TTableOptionDiff as vt, TCascadeResolver as w, TypedWithRelation as wt, NullableOptional as x, TValueFormatterPair as xt, FlatOf$1 as y, TTableResolver as yt, TDbIndex as z, DocumentFieldMapper as zt };
2321
+ export { TDbWriteGuard as $, TDbActionInfo as A, findAncestorInSet as At, TDbIndex as B, DocumentFieldMapper 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, AtscriptDbReadable as Ft, TDbObjectKind as G, TDbIndexType as H, NoopLogger as Ht, TDbDefaultValue as I, DbResponse as It, TDbRemoveGuard as J, TDbReferentialAction as K, TDbDeleteResult as L, resolveDesignType 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, TDbFieldMeta as R, DbEncryption as Rt, NullableOptional as S, TValueFormatterPair as St, TCascadeResolver as T, TypedWithRelation as Tt, TDbInsertManyResult as U, TGenericLogger as Ut, TDbIndexField as V, FieldMappingStrategy as Vt, TDbInsertResult as W, UniquSelect as Wt, TDbStorageType as X, TDbRemoveGuardContext as Y, TDbUpdateResult as Z, DbRow as _, TSearchIndexInfo as _t, jsonValueAncestor as a, TExistingTableOption as at, FlatOf$1 as b, TTableResolver as bt, AggregateControls as c, TFkLookupTarget as ct, AggregateQuery$1 as d, TIdentification as dt, TDbWriteGuardContext as et, AggregateResult as f, TMetaResponse as ft, DbQuery as g, TRelationInfo as gt, DbPatch as h, TReferencingForeignKey as ht, isJsonValueField as i, 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, TEnsureTableOptions as nt, normalizeComputedSelect as o, TFieldMeta as ot, AtscriptDbWritable as p, TMetadataOverrides as pt, TDbRelation as q, isBucketableField as r, TExistingColumn as rt, resolveCalendarBuckets as s, TFkLookupResolver as st, TBucketFieldSource as t, 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, TDbEncryptionOptions as zt };
@@ -1,6 +1,6 @@
1
- import { Ct as TWriteTableResolver, H as TDbInsertManyResult, Ht as TGenericLogger, I as TDbDeleteResult, Lt as DbEncryption, Nt as BaseDbAdapter, Ot as TableMetadata, Pt as AtscriptDbReadable, Rt as TDbEncryptionOptions, St as TWriteOptions, U as TDbInsertResult, X as TDbUpdateResult, bt as TTouchManyOptions, et as TDeleteOptions, g as DbRow, lt as TIdResolveOptions, m as DbPatch, mt as TReferencingForeignKey, ot as TFkLookupResolver, w as TCascadeResolver, x as NullableOptional, yt as TTableResolver } from "./buckets-Bo2IcPZ_.cjs";
2
- import { FilterExpr } from "@uniqu/core";
1
+ import { Ct as TWriteOptions, Ft as AtscriptDbReadable, L as TDbDeleteResult, Pt as BaseDbAdapter, Rt as DbEncryption, S as NullableOptional, T as TCascadeResolver, U as TDbInsertManyResult, Ut as TGenericLogger, W as TDbInsertResult, Z as TDbUpdateResult, _ as DbRow, bt as TTableResolver, h as DbPatch, ht as TReferencingForeignKey, kt as TableMetadata, st as TFkLookupResolver, tt as TDeleteOptions, ut as TIdResolveOptions, wt as TWriteTableResolver, xt as TTouchManyOptions, zt as TDbEncryptionOptions } from "./buckets-y4EzoX7D.mjs";
3
2
  import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
3
+ import { FilterExpr } from "@uniqu/core";
4
4
 
5
5
  //#region src/strategies/integrity.d.ts
6
6
  /**
@@ -241,11 +241,23 @@ declare class AtscriptDbTable<T extends TAtscriptAnnotatedType = TAtscriptAnnota
241
241
  }
242
242
  //#endregion
243
243
  //#region src/query/query-tree.d.ts
244
+ /**
245
+ * `true` when a query-tree operand is a field reference (`{ field, type? }`)
246
+ * rather than a literal — e.g. the right side of a field-to-field comparison.
247
+ * @since 0.1.136
248
+ */
249
+ declare function isFieldRef(value: unknown): value is AtscriptQueryFieldRef;
244
250
  /** A single join in a view query plan. */
245
251
  interface TViewJoin {
246
252
  targetType: () => TAtscriptAnnotatedType;
247
253
  targetTable: string;
248
254
  condition: AtscriptQueryNode;
255
+ /**
256
+ * `inner` (default) drops entry rows without a match; `left` keeps them
257
+ * with the target's columns as NULL. Joins apply in declaration order.
258
+ * @since 0.1.136
259
+ */
260
+ kind: "inner" | "left";
249
261
  }
250
262
  /** Resolved view query plan produced by AtscriptDbView. */
251
263
  interface TViewPlan {
@@ -263,15 +275,84 @@ interface TViewPlan {
263
275
  */
264
276
  declare function translateQueryTree(node: AtscriptQueryNode, resolveField: (ref: AtscriptQueryFieldRef) => string): FilterExpr;
265
277
  //#endregion
278
+ //#region src/table/view-source.d.ts
279
+ /**
280
+ * Where a view reads one logical source path from, in PHYSICAL terms.
281
+ *
282
+ * Produced by {@link resolveViewSource} — a pure function of the source
283
+ * table's annotated type that lays the table out with `TableMetadata`'s
284
+ * rules (flattened `__` columns, `@db.column` renames, `@db.json` / array
285
+ * JSON columns, document paths on nested-object adapters).
286
+ * @since 0.1.136
287
+ */
288
+ interface TViewSource {
289
+ /**
290
+ * Physical column (relational) or document path (nested-object adapters).
291
+ * For a path inside a JSON column this is the JSON column; for a flattened
292
+ * object it is the object's `__` prefix (no such column exists — its leaves do).
293
+ */
294
+ column: string;
295
+ /** Segments inside {@link column} when the path descends into a JSON column (relational only). */
296
+ jsonPath?: string[];
297
+ /** Design type of the addressed node (`string`, `number`, `object`, `array`, …; `unknown` when undeclared). */
298
+ designType: string;
299
+ /** Set for a relational object stored as one column per leaf. */
300
+ flattened?: true;
301
+ /**
302
+ * `true` when the value may be absent: the path or an ancestor segment is
303
+ * optional, or it reads inside a JSON-stored value.
304
+ */
305
+ optional: boolean;
306
+ }
307
+ //#endregion
266
308
  //#region src/table/db-view.d.ts
309
+ /** Primitive result type of a JSON-leaf extraction. */
310
+ type TViewJsonType = "string" | "number" | "boolean";
267
311
  interface TViewColumnMapping {
312
+ /**
313
+ * The view's own physical column — its `@db.column` / flattened `__` name
314
+ * on relational adapters, its document key on nested-object adapters.
315
+ */
268
316
  viewColumn: string;
317
+ /**
318
+ * Logical view field path (`address.city` for a flattened object leaf) —
319
+ * how `@db.view.having` refers to the column.
320
+ * @since 0.1.136
321
+ */
322
+ viewPath: string;
269
323
  sourceTable: string;
324
+ /** Physical source column (or document path). `"*"` for `COUNT(*)`. */
270
325
  sourceColumn: string;
271
- /** Aggregate function name ('sum'|'avg'|'count'|'min'|'max') if this is an aggregate column. */
326
+ /**
327
+ * Set when the source value may be missing for some row: an optional
328
+ * source field, a leaf inside a JSON-stored value, an undeclared path, or a
329
+ * column of a left-joined table. Document adapters coalesce such a source
330
+ * to `null`; a required source is read as a plain path (index-friendly).
331
+ * @since 0.1.136
332
+ */
333
+ nullable?: true;
334
+ /**
335
+ * Set when the source is a primitive leaf inside a JSON column
336
+ * ({@link sourceColumn}): the path within it and the leaf's declared type.
337
+ * @since 0.1.136
338
+ */
339
+ json?: {
340
+ path: string[];
341
+ type: TViewJsonType;
342
+ };
343
+ /**
344
+ * Aggregate function name (`sum` | `avg` | `count` | `countDistinct` |
345
+ * `min` | `max`) if this is an aggregate column.
346
+ */
272
347
  aggFn?: string;
273
348
  /** Source field for the aggregate function ('*' for COUNT(*)). */
274
349
  aggField?: string;
350
+ /**
351
+ * Row predicate of a conditional aggregate — the `@db.agg.*` 2nd argument:
352
+ * only rows where it holds are aggregated. Refs resolve like
353
+ * `@db.view.filter` (entry table + joins). @since 0.1.136
354
+ */
355
+ aggFilter?: AtscriptQueryNode;
275
356
  }
276
357
  /**
277
358
  * Database view abstraction driven by Atscript `@db.view.*` annotations.
@@ -288,6 +369,7 @@ interface TViewColumnMapping {
288
369
  */
289
370
  declare class AtscriptDbView<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>, FlatType = NullableOptional<FlatOf<T>>, A extends BaseDbAdapter = BaseDbAdapter, IdType = PrimaryKeyOf<T>, OwnProps = NullableOptional<OwnPropsOf<T>>, NavType extends Record<string, unknown> = NavPropsOf<T>> extends AtscriptDbReadable<T, DataType, FlatType, A, IdType, OwnProps, NavType> {
290
371
  private _viewPlan?;
372
+ private _columnMappings?;
291
373
  get isView(): boolean;
292
374
  /**
293
375
  * Whether this is an external view — declared with `@db.view` only,
@@ -304,19 +386,56 @@ declare class AtscriptDbView<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
304
386
  * - `db.view.materialized` → boolean (optional)
305
387
  */
306
388
  get viewPlan(): TViewPlan;
307
- /**
308
- * Resolves a query field ref to a quoted `table.column` SQL fragment.
389
+ /** Whether the adapter stores nested objects natively (document paths, no JSON columns). */
390
+ private get _nested();
391
+ /**
392
+ * Resolves a view query field ref (join condition, `@db.view.filter`,
393
+ * conditional-aggregate predicate) to its table name and PHYSICAL source on
394
+ * this view's adapter — the column (or document path) with `TableMetadata`'s
395
+ * layout rules, the path inside a JSON column, and whether the value may be
396
+ * absent. An unqualified ref resolves against the entry table.
397
+ * @throws for a ref without storage (`@db.ignore`, navigation relation) or
398
+ * inside an `@db.encrypted` field (relational adapters).
399
+ * @since 0.1.136
400
+ */
401
+ resolveRefSource(ref: AtscriptQueryFieldRef): {
402
+ table: string;
403
+ source: TViewSource;
404
+ };
405
+ /**
406
+ * Resolves a query field ref (join condition, `@db.view.filter`) to a
407
+ * quoted `table.column` SQL fragment — the PHYSICAL column (flattened
408
+ * `__` name, `@db.column` rename). An unqualified ref
409
+ * resolves against the entry table.
309
410
  *
310
411
  * @param ref - The field reference from the query tree.
311
412
  * @param qi - Identifier quoting function (e.g. backtick for MySQL, double-quote for SQLite).
312
413
  * Defaults to double-quote wrapping for backwards compatibility.
414
+ * @throws when the ref reads inside a JSON column (not supported in view conditions).
313
415
  */
314
416
  resolveFieldRef(ref: AtscriptQueryFieldRef, qi?: (name: string) => string): string;
315
417
  /**
316
- * Maps each view field to its source table and column via ref chain.
317
- * Fields without refs (inline definitions) map to the entry table with the same name.
418
+ * Maps each view column to its source table and PHYSICAL source column.
419
+ *
420
+ * View fields resolve through their chain ref; fields without a ref read
421
+ * the entry table under the same name; aggregates read their `@db.agg.*`
422
+ * field from the entry table (or their ref). Source names are
423
+ * physical (flattened `__` names, `@db.column`, document paths), `viewColumn`
424
+ * is the view's own physical name, an object field whose source is a
425
+ * flattened object expands to one mapping per leaf, and a primitive leaf
426
+ * inside a JSON column carries `json` (rendered by adapters that support
427
+ * JSON extraction).
428
+ *
429
+ * Computed once per view (the plan and the type are immutable).
430
+ *
431
+ * @throws for an object field over a JSON column without `@db.json` on the
432
+ * view field, a JSON leaf that is not a string / number / boolean, or an
433
+ * aggregate other than `count` over `'*'`.
318
434
  */
319
435
  getViewColumnMappings(): TViewColumnMapping[];
436
+ private _buildColumnMappings;
437
+ /** One view column over one physical source (a column or a JSON leaf). */
438
+ private _leafMapping;
320
439
  }
321
440
  /**
322
441
  * Structural type guard for views: `true` when the readable reports
@@ -436,4 +555,4 @@ declare class DbSpace {
436
555
  private _getFkLookupTarget;
437
556
  }
438
557
  //#endregion
439
- export { TViewColumnMapping as a, AtscriptQueryFieldRef$1 as c, TViewJoin as d, TViewPlan as f, NativeIntegrity as g, IntegrityStrategy as h, AtscriptDbView as i, AtscriptQueryNode$1 as l, AtscriptDbTable as m, TAdapterFactory as n, isAtscriptDbView as o, translateQueryTree as p, TDbSpaceOptions as r, AtscriptQueryComparison as s, DbSpace as t, AtscriptRef as u };
558
+ export { IntegrityStrategy as _, TViewColumnMapping as a, AtscriptQueryComparison as c, AtscriptRef as d, TViewJoin as f, AtscriptDbTable as g, translateQueryTree as h, AtscriptDbView as i, AtscriptQueryFieldRef$1 as l, isFieldRef as m, TAdapterFactory as n, TViewJsonType as o, TViewPlan as p, TDbSpaceOptions as r, isAtscriptDbView as s, DbSpace as t, AtscriptQueryNode$1 as u, NativeIntegrity as v };
@@ -1,6 +1,6 @@
1
- import { Ct as TWriteTableResolver, H as TDbInsertManyResult, Ht as TGenericLogger, I as TDbDeleteResult, Lt as DbEncryption, Nt as BaseDbAdapter, Ot as TableMetadata, Pt as AtscriptDbReadable, Rt as TDbEncryptionOptions, St as TWriteOptions, U as TDbInsertResult, X as TDbUpdateResult, bt as TTouchManyOptions, et as TDeleteOptions, g as DbRow, lt as TIdResolveOptions, m as DbPatch, mt as TReferencingForeignKey, ot as TFkLookupResolver, w as TCascadeResolver, x as NullableOptional, yt as TTableResolver } from "./buckets-Bys2QXyk.mjs";
2
- import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
1
+ import { Ct as TWriteOptions, Ft as AtscriptDbReadable, L as TDbDeleteResult, Pt as BaseDbAdapter, Rt as DbEncryption, S as NullableOptional, T as TCascadeResolver, U as TDbInsertManyResult, Ut as TGenericLogger, W as TDbInsertResult, Z as TDbUpdateResult, _ as DbRow, bt as TTableResolver, h as DbPatch, ht as TReferencingForeignKey, kt as TableMetadata, st as TFkLookupResolver, tt as TDeleteOptions, ut as TIdResolveOptions, wt as TWriteTableResolver, xt as TTouchManyOptions, zt as TDbEncryptionOptions } from "./buckets-kKY0RKYN.cjs";
3
2
  import { FilterExpr } from "@uniqu/core";
3
+ import { AtscriptQueryComparison, AtscriptQueryFieldRef, AtscriptQueryFieldRef as AtscriptQueryFieldRef$1, AtscriptQueryNode, AtscriptQueryNode as AtscriptQueryNode$1, AtscriptRef, FlatOf, NavPropsOf, OwnPropsOf, PrimaryKeyOf, TAtscriptAnnotatedType, TAtscriptDataType, Validator } from "@atscript/typescript/utils";
4
4
 
5
5
  //#region src/strategies/integrity.d.ts
6
6
  /**
@@ -241,11 +241,23 @@ declare class AtscriptDbTable<T extends TAtscriptAnnotatedType = TAtscriptAnnota
241
241
  }
242
242
  //#endregion
243
243
  //#region src/query/query-tree.d.ts
244
+ /**
245
+ * `true` when a query-tree operand is a field reference (`{ field, type? }`)
246
+ * rather than a literal — e.g. the right side of a field-to-field comparison.
247
+ * @since 0.1.136
248
+ */
249
+ declare function isFieldRef(value: unknown): value is AtscriptQueryFieldRef;
244
250
  /** A single join in a view query plan. */
245
251
  interface TViewJoin {
246
252
  targetType: () => TAtscriptAnnotatedType;
247
253
  targetTable: string;
248
254
  condition: AtscriptQueryNode;
255
+ /**
256
+ * `inner` (default) drops entry rows without a match; `left` keeps them
257
+ * with the target's columns as NULL. Joins apply in declaration order.
258
+ * @since 0.1.136
259
+ */
260
+ kind: "inner" | "left";
249
261
  }
250
262
  /** Resolved view query plan produced by AtscriptDbView. */
251
263
  interface TViewPlan {
@@ -263,15 +275,84 @@ interface TViewPlan {
263
275
  */
264
276
  declare function translateQueryTree(node: AtscriptQueryNode, resolveField: (ref: AtscriptQueryFieldRef) => string): FilterExpr;
265
277
  //#endregion
278
+ //#region src/table/view-source.d.ts
279
+ /**
280
+ * Where a view reads one logical source path from, in PHYSICAL terms.
281
+ *
282
+ * Produced by {@link resolveViewSource} — a pure function of the source
283
+ * table's annotated type that lays the table out with `TableMetadata`'s
284
+ * rules (flattened `__` columns, `@db.column` renames, `@db.json` / array
285
+ * JSON columns, document paths on nested-object adapters).
286
+ * @since 0.1.136
287
+ */
288
+ interface TViewSource {
289
+ /**
290
+ * Physical column (relational) or document path (nested-object adapters).
291
+ * For a path inside a JSON column this is the JSON column; for a flattened
292
+ * object it is the object's `__` prefix (no such column exists — its leaves do).
293
+ */
294
+ column: string;
295
+ /** Segments inside {@link column} when the path descends into a JSON column (relational only). */
296
+ jsonPath?: string[];
297
+ /** Design type of the addressed node (`string`, `number`, `object`, `array`, …; `unknown` when undeclared). */
298
+ designType: string;
299
+ /** Set for a relational object stored as one column per leaf. */
300
+ flattened?: true;
301
+ /**
302
+ * `true` when the value may be absent: the path or an ancestor segment is
303
+ * optional, or it reads inside a JSON-stored value.
304
+ */
305
+ optional: boolean;
306
+ }
307
+ //#endregion
266
308
  //#region src/table/db-view.d.ts
309
+ /** Primitive result type of a JSON-leaf extraction. */
310
+ type TViewJsonType = "string" | "number" | "boolean";
267
311
  interface TViewColumnMapping {
312
+ /**
313
+ * The view's own physical column — its `@db.column` / flattened `__` name
314
+ * on relational adapters, its document key on nested-object adapters.
315
+ */
268
316
  viewColumn: string;
317
+ /**
318
+ * Logical view field path (`address.city` for a flattened object leaf) —
319
+ * how `@db.view.having` refers to the column.
320
+ * @since 0.1.136
321
+ */
322
+ viewPath: string;
269
323
  sourceTable: string;
324
+ /** Physical source column (or document path). `"*"` for `COUNT(*)`. */
270
325
  sourceColumn: string;
271
- /** Aggregate function name ('sum'|'avg'|'count'|'min'|'max') if this is an aggregate column. */
326
+ /**
327
+ * Set when the source value may be missing for some row: an optional
328
+ * source field, a leaf inside a JSON-stored value, an undeclared path, or a
329
+ * column of a left-joined table. Document adapters coalesce such a source
330
+ * to `null`; a required source is read as a plain path (index-friendly).
331
+ * @since 0.1.136
332
+ */
333
+ nullable?: true;
334
+ /**
335
+ * Set when the source is a primitive leaf inside a JSON column
336
+ * ({@link sourceColumn}): the path within it and the leaf's declared type.
337
+ * @since 0.1.136
338
+ */
339
+ json?: {
340
+ path: string[];
341
+ type: TViewJsonType;
342
+ };
343
+ /**
344
+ * Aggregate function name (`sum` | `avg` | `count` | `countDistinct` |
345
+ * `min` | `max`) if this is an aggregate column.
346
+ */
272
347
  aggFn?: string;
273
348
  /** Source field for the aggregate function ('*' for COUNT(*)). */
274
349
  aggField?: string;
350
+ /**
351
+ * Row predicate of a conditional aggregate — the `@db.agg.*` 2nd argument:
352
+ * only rows where it holds are aggregated. Refs resolve like
353
+ * `@db.view.filter` (entry table + joins). @since 0.1.136
354
+ */
355
+ aggFilter?: AtscriptQueryNode;
275
356
  }
276
357
  /**
277
358
  * Database view abstraction driven by Atscript `@db.view.*` annotations.
@@ -288,6 +369,7 @@ interface TViewColumnMapping {
288
369
  */
289
370
  declare class AtscriptDbView<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>, FlatType = NullableOptional<FlatOf<T>>, A extends BaseDbAdapter = BaseDbAdapter, IdType = PrimaryKeyOf<T>, OwnProps = NullableOptional<OwnPropsOf<T>>, NavType extends Record<string, unknown> = NavPropsOf<T>> extends AtscriptDbReadable<T, DataType, FlatType, A, IdType, OwnProps, NavType> {
290
371
  private _viewPlan?;
372
+ private _columnMappings?;
291
373
  get isView(): boolean;
292
374
  /**
293
375
  * Whether this is an external view — declared with `@db.view` only,
@@ -304,19 +386,56 @@ declare class AtscriptDbView<T extends TAtscriptAnnotatedType = TAtscriptAnnotat
304
386
  * - `db.view.materialized` → boolean (optional)
305
387
  */
306
388
  get viewPlan(): TViewPlan;
307
- /**
308
- * Resolves a query field ref to a quoted `table.column` SQL fragment.
389
+ /** Whether the adapter stores nested objects natively (document paths, no JSON columns). */
390
+ private get _nested();
391
+ /**
392
+ * Resolves a view query field ref (join condition, `@db.view.filter`,
393
+ * conditional-aggregate predicate) to its table name and PHYSICAL source on
394
+ * this view's adapter — the column (or document path) with `TableMetadata`'s
395
+ * layout rules, the path inside a JSON column, and whether the value may be
396
+ * absent. An unqualified ref resolves against the entry table.
397
+ * @throws for a ref without storage (`@db.ignore`, navigation relation) or
398
+ * inside an `@db.encrypted` field (relational adapters).
399
+ * @since 0.1.136
400
+ */
401
+ resolveRefSource(ref: AtscriptQueryFieldRef): {
402
+ table: string;
403
+ source: TViewSource;
404
+ };
405
+ /**
406
+ * Resolves a query field ref (join condition, `@db.view.filter`) to a
407
+ * quoted `table.column` SQL fragment — the PHYSICAL column (flattened
408
+ * `__` name, `@db.column` rename). An unqualified ref
409
+ * resolves against the entry table.
309
410
  *
310
411
  * @param ref - The field reference from the query tree.
311
412
  * @param qi - Identifier quoting function (e.g. backtick for MySQL, double-quote for SQLite).
312
413
  * Defaults to double-quote wrapping for backwards compatibility.
414
+ * @throws when the ref reads inside a JSON column (not supported in view conditions).
313
415
  */
314
416
  resolveFieldRef(ref: AtscriptQueryFieldRef, qi?: (name: string) => string): string;
315
417
  /**
316
- * Maps each view field to its source table and column via ref chain.
317
- * Fields without refs (inline definitions) map to the entry table with the same name.
418
+ * Maps each view column to its source table and PHYSICAL source column.
419
+ *
420
+ * View fields resolve through their chain ref; fields without a ref read
421
+ * the entry table under the same name; aggregates read their `@db.agg.*`
422
+ * field from the entry table (or their ref). Source names are
423
+ * physical (flattened `__` names, `@db.column`, document paths), `viewColumn`
424
+ * is the view's own physical name, an object field whose source is a
425
+ * flattened object expands to one mapping per leaf, and a primitive leaf
426
+ * inside a JSON column carries `json` (rendered by adapters that support
427
+ * JSON extraction).
428
+ *
429
+ * Computed once per view (the plan and the type are immutable).
430
+ *
431
+ * @throws for an object field over a JSON column without `@db.json` on the
432
+ * view field, a JSON leaf that is not a string / number / boolean, or an
433
+ * aggregate other than `count` over `'*'`.
318
434
  */
319
435
  getViewColumnMappings(): TViewColumnMapping[];
436
+ private _buildColumnMappings;
437
+ /** One view column over one physical source (a column or a JSON leaf). */
438
+ private _leafMapping;
320
439
  }
321
440
  /**
322
441
  * Structural type guard for views: `true` when the readable reports
@@ -436,4 +555,4 @@ declare class DbSpace {
436
555
  private _getFkLookupTarget;
437
556
  }
438
557
  //#endregion
439
- export { TViewColumnMapping as a, AtscriptQueryFieldRef$1 as c, TViewJoin as d, TViewPlan as f, NativeIntegrity as g, IntegrityStrategy as h, AtscriptDbView as i, AtscriptQueryNode$1 as l, AtscriptDbTable as m, TAdapterFactory as n, isAtscriptDbView as o, translateQueryTree as p, TDbSpaceOptions as r, AtscriptQueryComparison as s, DbSpace as t, AtscriptRef as u };
558
+ export { IntegrityStrategy as _, TViewColumnMapping as a, AtscriptQueryComparison as c, AtscriptRef as d, TViewJoin as f, AtscriptDbTable as g, translateQueryTree as h, AtscriptDbView as i, AtscriptQueryFieldRef$1 as l, isFieldRef as m, TAdapterFactory as n, TViewJsonType as o, TViewPlan as p, TDbSpaceOptions as r, isAtscriptDbView as s, DbSpace as t, AtscriptQueryNode$1 as u, NativeIntegrity as v };