@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
@@ -0,0 +1,53 @@
1
+ import { AggregateControls, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateFn as AggregateFn$1, AggregateQuery as AggregateQuery$1, AggregateResult, BucketExpr, BucketUnit as BucketUnit$1, CalendarBucketLabel, ComputedExpr, ResolvedBucket as ResolvedBucket$1, WeekStart, isAggregateExpr, isBucketExpr, resolveAlias } from "@uniqu/core";
2
+
3
+ //#region src/query/aggregate-fns.d.ts
4
+ /**
5
+ * The aggregate functions atscript-db knows — uniqu's full `AggregateFn` set.
6
+ * Which of them an adapter renders is its `aggregateFns()` capability.
7
+ */
8
+ type TDbAggregateFn = AggregateFn;
9
+ /**
10
+ * Every aggregate function — what an adapter that renders them all returns
11
+ * from `aggregateFns()`.
12
+ *
13
+ * @since 0.1.136
14
+ */
15
+ declare const ALL_AGGREGATE_FNS: ReadonlySet<TDbAggregateFn>;
16
+ /**
17
+ * Throws `DbError` `INVALID_QUERY` (uniqu's wording) unless `fn` is in
18
+ * `SUPPORTED_AGGREGATE_FNS` — for adapters to re-assert before rendering.
19
+ */
20
+ declare function assertAggregateFn(fn: unknown, path?: string): asserts fn is TDbAggregateFn;
21
+ //#endregion
22
+ //#region src/agg.d.ts
23
+ /** The text-search request a grouped query carries, once normalised. */
24
+ interface TAggregateSearch {
25
+ /** Non-empty, trimmed search term. */
26
+ text: string;
27
+ /** Named search index to target, when the caller picked one. */
28
+ indexName?: string;
29
+ }
30
+ /**
31
+ * Reads the `$search` / `$index` controls of an aggregate query.
32
+ *
33
+ * Search and grouping are orthogonal: `$search` narrows the ROWS, `$groupBy`
34
+ * shapes what is left. Every adapter must therefore apply the search predicate
35
+ * BEFORE grouping, so the groups — and `$count`, which counts them — only ever
36
+ * describe rows that matched. An adapter that silently ignored the term would
37
+ * report totals for rows the same search excludes from the leaf list.
38
+ *
39
+ * Two rules the leaf search path applies and the grouped path must NOT:
40
+ * - **No implicit relevance ordering.** Relevance is a property of a row, not
41
+ * of a group; after `$group` there is no per-row score left to sort on.
42
+ * Grouped results order by `$sort` or not at all.
43
+ * - **No implicit row cap.** The leaf runners cap an unbounded search at 1000
44
+ * rows; applying that before `$group` would silently truncate group counts.
45
+ *
46
+ * Returns `undefined` when there is nothing to search for, so callers fall
47
+ * straight through to the plain grouped path.
48
+ */
49
+ declare function resolveAggregateSearch(controls: {
50
+ [key: `$${string}`]: unknown;
51
+ } | undefined): TAggregateSearch | undefined;
52
+ //#endregion
53
+ export { TDbAggregateFn as _, AggregateResult as a, CalendarBucketLabel as c, WeekStart as d, isAggregateExpr as f, ALL_AGGREGATE_FNS as g, resolveAlias as h, AggregateQuery$1 as i, ComputedExpr as l, resolveAggregateSearch as m, AggregateExpr$1 as n, BucketExpr as o, isBucketExpr as p, AggregateFn$1 as r, BucketUnit$1 as s, AggregateControls as t, ResolvedBucket$1 as u, assertAggregateFn as v };
@@ -0,0 +1,53 @@
1
+ import { AggregateControls, AggregateExpr as AggregateExpr$1, AggregateFn, AggregateFn as AggregateFn$1, AggregateQuery as AggregateQuery$1, AggregateResult, BucketExpr, BucketUnit as BucketUnit$1, CalendarBucketLabel, ComputedExpr, ResolvedBucket as ResolvedBucket$1, WeekStart, isAggregateExpr as isAggregateExpr$1, isBucketExpr as isBucketExpr$1, resolveAlias } from "@uniqu/core";
2
+
3
+ //#region src/query/aggregate-fns.d.ts
4
+ /**
5
+ * The aggregate functions atscript-db knows — uniqu's full `AggregateFn` set.
6
+ * Which of them an adapter renders is its `aggregateFns()` capability.
7
+ */
8
+ type TDbAggregateFn = AggregateFn;
9
+ /**
10
+ * Every aggregate function — what an adapter that renders them all returns
11
+ * from `aggregateFns()`.
12
+ *
13
+ * @since 0.1.136
14
+ */
15
+ declare const ALL_AGGREGATE_FNS: ReadonlySet<TDbAggregateFn>;
16
+ /**
17
+ * Throws `DbError` `INVALID_QUERY` (uniqu's wording) unless `fn` is in
18
+ * `SUPPORTED_AGGREGATE_FNS` — for adapters to re-assert before rendering.
19
+ */
20
+ declare function assertAggregateFn(fn: unknown, path?: string): asserts fn is TDbAggregateFn;
21
+ //#endregion
22
+ //#region src/agg.d.ts
23
+ /** The text-search request a grouped query carries, once normalised. */
24
+ interface TAggregateSearch {
25
+ /** Non-empty, trimmed search term. */
26
+ text: string;
27
+ /** Named search index to target, when the caller picked one. */
28
+ indexName?: string;
29
+ }
30
+ /**
31
+ * Reads the `$search` / `$index` controls of an aggregate query.
32
+ *
33
+ * Search and grouping are orthogonal: `$search` narrows the ROWS, `$groupBy`
34
+ * shapes what is left. Every adapter must therefore apply the search predicate
35
+ * BEFORE grouping, so the groups — and `$count`, which counts them — only ever
36
+ * describe rows that matched. An adapter that silently ignored the term would
37
+ * report totals for rows the same search excludes from the leaf list.
38
+ *
39
+ * Two rules the leaf search path applies and the grouped path must NOT:
40
+ * - **No implicit relevance ordering.** Relevance is a property of a row, not
41
+ * of a group; after `$group` there is no per-row score left to sort on.
42
+ * Grouped results order by `$sort` or not at all.
43
+ * - **No implicit row cap.** The leaf runners cap an unbounded search at 1000
44
+ * rows; applying that before `$group` would silently truncate group counts.
45
+ *
46
+ * Returns `undefined` when there is nothing to search for, so callers fall
47
+ * straight through to the plain grouped path.
48
+ */
49
+ declare function resolveAggregateSearch(controls: {
50
+ [key: `$${string}`]: unknown;
51
+ } | undefined): TAggregateSearch | undefined;
52
+ //#endregion
53
+ export { TDbAggregateFn as _, AggregateResult as a, CalendarBucketLabel as c, WeekStart as d, isAggregateExpr$1 as f, ALL_AGGREGATE_FNS as g, resolveAlias as h, AggregateQuery$1 as i, ComputedExpr as l, resolveAggregateSearch as m, AggregateExpr$1 as n, BucketExpr as o, isBucketExpr$1 as p, AggregateFn$1 as r, BucketUnit$1 as s, AggregateControls as t, ResolvedBucket$1 as u, assertAggregateFn as v };
package/dist/agg.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_aggregate_fns = require("./aggregate-fns-CGBv3E8S.cjs");
2
3
  let _uniqu_core = require("@uniqu/core");
3
4
  //#region src/agg.ts
4
5
  /**
@@ -32,6 +33,7 @@ function resolveAggregateSearch(controls) {
32
33
  };
33
34
  }
34
35
  //#endregion
36
+ exports.assertAggregateFn = require_aggregate_fns.assertAggregateFn;
35
37
  Object.defineProperty(exports, "isAggregateExpr", {
36
38
  enumerable: true,
37
39
  get: function() {
package/dist/agg.d.cts CHANGED
@@ -1,35 +1,3 @@
1
- import { n as TResolvedBucket } from "./buckets-Bo2IcPZ_.cjs";
2
- import { AggregateControls, AggregateExpr, AggregateFn, AggregateQuery, AggregateResult, BucketExpr, BucketUnit, CalendarBucketLabel, ComputedExpr, ResolvedBucket, WeekStart, isAggregateExpr, isBucketExpr, resolveAlias } from "@uniqu/core";
3
-
4
- //#region src/agg.d.ts
5
- /** The text-search request a grouped query carries, once normalised. */
6
- interface TAggregateSearch {
7
- /** Non-empty, trimmed search term. */
8
- text: string;
9
- /** Named search index to target, when the caller picked one. */
10
- indexName?: string;
11
- }
12
- /**
13
- * Reads the `$search` / `$index` controls of an aggregate query.
14
- *
15
- * Search and grouping are orthogonal: `$search` narrows the ROWS, `$groupBy`
16
- * shapes what is left. Every adapter must therefore apply the search predicate
17
- * BEFORE grouping, so the groups — and `$count`, which counts them — only ever
18
- * describe rows that matched. An adapter that silently ignored the term would
19
- * report totals for rows the same search excludes from the leaf list.
20
- *
21
- * Two rules the leaf search path applies and the grouped path must NOT:
22
- * - **No implicit relevance ordering.** Relevance is a property of a row, not
23
- * of a group; after `$group` there is no per-row score left to sort on.
24
- * Grouped results order by `$sort` or not at all.
25
- * - **No implicit row cap.** The leaf runners cap an unbounded search at 1000
26
- * rows; applying that before `$group` would silently truncate group counts.
27
- *
28
- * Returns `undefined` when there is nothing to search for, so callers fall
29
- * straight through to the plain grouped path.
30
- */
31
- declare function resolveAggregateSearch(controls: {
32
- [key: `$${string}`]: unknown;
33
- } | undefined): TAggregateSearch | undefined;
34
- //#endregion
35
- export { type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, type BucketExpr, type BucketUnit, type CalendarBucketLabel, type ComputedExpr, type ResolvedBucket, type TResolvedBucket, type WeekStart, isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
1
+ import { n as TResolvedBucket } from "./buckets-kKY0RKYN.cjs";
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
+ 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,35 +1,3 @@
1
- import { n as TResolvedBucket } from "./buckets-Bys2QXyk.mjs";
2
- import { AggregateControls, AggregateExpr, AggregateFn, AggregateQuery, AggregateResult, BucketExpr, BucketUnit, CalendarBucketLabel, ComputedExpr, ResolvedBucket, WeekStart, isAggregateExpr, isBucketExpr, resolveAlias } from "@uniqu/core";
3
-
4
- //#region src/agg.d.ts
5
- /** The text-search request a grouped query carries, once normalised. */
6
- interface TAggregateSearch {
7
- /** Non-empty, trimmed search term. */
8
- text: string;
9
- /** Named search index to target, when the caller picked one. */
10
- indexName?: string;
11
- }
12
- /**
13
- * Reads the `$search` / `$index` controls of an aggregate query.
14
- *
15
- * Search and grouping are orthogonal: `$search` narrows the ROWS, `$groupBy`
16
- * shapes what is left. Every adapter must therefore apply the search predicate
17
- * BEFORE grouping, so the groups — and `$count`, which counts them — only ever
18
- * describe rows that matched. An adapter that silently ignored the term would
19
- * report totals for rows the same search excludes from the leaf list.
20
- *
21
- * Two rules the leaf search path applies and the grouped path must NOT:
22
- * - **No implicit relevance ordering.** Relevance is a property of a row, not
23
- * of a group; after `$group` there is no per-row score left to sort on.
24
- * Grouped results order by `$sort` or not at all.
25
- * - **No implicit row cap.** The leaf runners cap an unbounded search at 1000
26
- * rows; applying that before `$group` would silently truncate group counts.
27
- *
28
- * Returns `undefined` when there is nothing to search for, so callers fall
29
- * straight through to the plain grouped path.
30
- */
31
- declare function resolveAggregateSearch(controls: {
32
- [key: `$${string}`]: unknown;
33
- } | undefined): TAggregateSearch | undefined;
34
- //#endregion
35
- export { type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, type BucketExpr, type BucketUnit, type CalendarBucketLabel, type ComputedExpr, type ResolvedBucket, type TResolvedBucket, type WeekStart, isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
1
+ import { n as TResolvedBucket } from "./buckets-y4EzoX7D.mjs";
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
+ 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.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { a as assertAggregateFn } from "./aggregate-fns-CfsveE1w.mjs";
1
2
  import { isAggregateExpr, isBucketExpr, resolveAlias } from "@uniqu/core";
2
3
  //#region src/agg.ts
3
4
  /**
@@ -31,4 +32,4 @@ function resolveAggregateSearch(controls) {
31
32
  };
32
33
  }
33
34
  //#endregion
34
- export { isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
35
+ export { assertAggregateFn, isAggregateExpr, isBucketExpr, resolveAggregateSearch, resolveAlias };
@@ -0,0 +1,87 @@
1
+ const require_db_error = require("./db-error-DTkkeu5b.cjs");
2
+ //#region src/query/aggregate-fns.ts
3
+ /**
4
+ * The only `$fn` names a `$select` aggregate may use. Any other name is rejected with
5
+ * `INVALID_QUERY` (HTTP 400 through moost-db) before a query reaches an
6
+ * adapter, so no adapter ever renders an unchecked function name into SQL or
7
+ * a pipeline. A known name missing from the adapter's `aggregateFns()` is
8
+ * `AGG_FN_NOT_SUPPORTED`.
9
+ */
10
+ const SUPPORTED_AGGREGATE_FNS = [
11
+ "sum",
12
+ "count",
13
+ "avg",
14
+ "min",
15
+ "max",
16
+ "countDistinct"
17
+ ];
18
+ /**
19
+ * The aggregates that are NULL over no (non-null) value — every function but
20
+ * the counts, which are 0. So a view field reading a left-joined table must be
21
+ * optional unless it counts, and a CONDITIONAL one must be optional when no
22
+ * row may match — except `sum`, whose conditional form is rendered as
23
+ * `COALESCE(…, 0)`.
24
+ */
25
+ const NULL_WHEN_EMPTY_AGGREGATE_FNS = new Set([
26
+ "sum",
27
+ "avg",
28
+ "min",
29
+ "max"
30
+ ]);
31
+ /** `BaseDbAdapter.aggregateFns()` by default: every function except `countDistinct`. */
32
+ const BASE_AGGREGATE_FNS = new Set([
33
+ "sum",
34
+ "count",
35
+ "avg",
36
+ "min",
37
+ "max"
38
+ ]);
39
+ /**
40
+ * Every aggregate function — what an adapter that renders them all returns
41
+ * from `aggregateFns()`.
42
+ *
43
+ * @since 0.1.136
44
+ */
45
+ const ALL_AGGREGATE_FNS = new Set(SUPPORTED_AGGREGATE_FNS);
46
+ const SUPPORTED_LIST = `${SUPPORTED_AGGREGATE_FNS.slice(0, -1).join(", ")} or ${SUPPORTED_AGGREGATE_FNS.at(-1)}`;
47
+ /**
48
+ * Throws `DbError` `INVALID_QUERY` (uniqu's wording) unless `fn` is in
49
+ * `SUPPORTED_AGGREGATE_FNS` — for adapters to re-assert before rendering.
50
+ */
51
+ function assertAggregateFn(fn, path = "$select") {
52
+ if (!SUPPORTED_AGGREGATE_FNS.includes(fn)) throw new require_db_error.DbError("INVALID_QUERY", [{
53
+ path,
54
+ message: `Unknown aggregate function "${String(fn)}" — use ${SUPPORTED_LIST}`
55
+ }]);
56
+ }
57
+ //#endregion
58
+ Object.defineProperty(exports, "ALL_AGGREGATE_FNS", {
59
+ enumerable: true,
60
+ get: function() {
61
+ return ALL_AGGREGATE_FNS;
62
+ }
63
+ });
64
+ Object.defineProperty(exports, "BASE_AGGREGATE_FNS", {
65
+ enumerable: true,
66
+ get: function() {
67
+ return BASE_AGGREGATE_FNS;
68
+ }
69
+ });
70
+ Object.defineProperty(exports, "NULL_WHEN_EMPTY_AGGREGATE_FNS", {
71
+ enumerable: true,
72
+ get: function() {
73
+ return NULL_WHEN_EMPTY_AGGREGATE_FNS;
74
+ }
75
+ });
76
+ Object.defineProperty(exports, "SUPPORTED_AGGREGATE_FNS", {
77
+ enumerable: true,
78
+ get: function() {
79
+ return SUPPORTED_AGGREGATE_FNS;
80
+ }
81
+ });
82
+ Object.defineProperty(exports, "assertAggregateFn", {
83
+ enumerable: true,
84
+ get: function() {
85
+ return assertAggregateFn;
86
+ }
87
+ });
@@ -0,0 +1,58 @@
1
+ import { r as DbError } from "./db-error-D5uilS_A.mjs";
2
+ //#region src/query/aggregate-fns.ts
3
+ /**
4
+ * The only `$fn` names a `$select` aggregate may use. Any other name is rejected with
5
+ * `INVALID_QUERY` (HTTP 400 through moost-db) before a query reaches an
6
+ * adapter, so no adapter ever renders an unchecked function name into SQL or
7
+ * a pipeline. A known name missing from the adapter's `aggregateFns()` is
8
+ * `AGG_FN_NOT_SUPPORTED`.
9
+ */
10
+ const SUPPORTED_AGGREGATE_FNS = [
11
+ "sum",
12
+ "count",
13
+ "avg",
14
+ "min",
15
+ "max",
16
+ "countDistinct"
17
+ ];
18
+ /**
19
+ * The aggregates that are NULL over no (non-null) value — every function but
20
+ * the counts, which are 0. So a view field reading a left-joined table must be
21
+ * optional unless it counts, and a CONDITIONAL one must be optional when no
22
+ * row may match — except `sum`, whose conditional form is rendered as
23
+ * `COALESCE(…, 0)`.
24
+ */
25
+ const NULL_WHEN_EMPTY_AGGREGATE_FNS = new Set([
26
+ "sum",
27
+ "avg",
28
+ "min",
29
+ "max"
30
+ ]);
31
+ /** `BaseDbAdapter.aggregateFns()` by default: every function except `countDistinct`. */
32
+ const BASE_AGGREGATE_FNS = new Set([
33
+ "sum",
34
+ "count",
35
+ "avg",
36
+ "min",
37
+ "max"
38
+ ]);
39
+ /**
40
+ * Every aggregate function — what an adapter that renders them all returns
41
+ * from `aggregateFns()`.
42
+ *
43
+ * @since 0.1.136
44
+ */
45
+ const ALL_AGGREGATE_FNS = new Set(SUPPORTED_AGGREGATE_FNS);
46
+ const SUPPORTED_LIST = `${SUPPORTED_AGGREGATE_FNS.slice(0, -1).join(", ")} or ${SUPPORTED_AGGREGATE_FNS.at(-1)}`;
47
+ /**
48
+ * Throws `DbError` `INVALID_QUERY` (uniqu's wording) unless `fn` is in
49
+ * `SUPPORTED_AGGREGATE_FNS` — for adapters to re-assert before rendering.
50
+ */
51
+ function assertAggregateFn(fn, path = "$select") {
52
+ if (!SUPPORTED_AGGREGATE_FNS.includes(fn)) throw new DbError("INVALID_QUERY", [{
53
+ path,
54
+ message: `Unknown aggregate function "${String(fn)}" — use ${SUPPORTED_LIST}`
55
+ }]);
56
+ }
57
+ //#endregion
58
+ export { assertAggregateFn as a, SUPPORTED_AGGREGATE_FNS as i, BASE_AGGREGATE_FNS as n, NULL_WHEN_EMPTY_AGGREGATE_FNS as r, ALL_AGGREGATE_FNS as t };
@@ -1,5 +1,5 @@
1
1
  import { f as TFieldOps } from "./ops-AqhV7s9o.cjs";
2
- 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";
2
+ 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";
3
3
  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";
4
4
 
5
5
  //#region src/query/uniqu-select.d.ts
@@ -15,7 +15,7 @@ import { FlatOf, FlatOf as FlatOf$1, NavPropsOf, NavPropsOf as NavPropsOf$1, Own
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 };