@webda/ql 4.0.0-beta.5 → 4.0.0-beta.7

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 (63) hide show
  1. package/README.md +72 -31
  2. package/lib/WebdaQLLexer.d.ts +44 -30
  3. package/lib/WebdaQLLexer.d.ts.map +1 -1
  4. package/lib/WebdaQLLexer.js +257 -152
  5. package/lib/WebdaQLLexer.js.map +1 -1
  6. package/lib/WebdaQLParserLexer.d.ts +44 -30
  7. package/lib/WebdaQLParserLexer.d.ts.map +1 -1
  8. package/lib/WebdaQLParserLexer.js +257 -152
  9. package/lib/WebdaQLParserLexer.js.map +1 -1
  10. package/lib/WebdaQLParserListener.d.ts +203 -30
  11. package/lib/WebdaQLParserListener.d.ts.map +1 -1
  12. package/lib/WebdaQLParserParser.d.ts +242 -44
  13. package/lib/WebdaQLParserParser.d.ts.map +1 -1
  14. package/lib/WebdaQLParserParser.js +2054 -715
  15. package/lib/WebdaQLParserParser.js.map +1 -1
  16. package/lib/WebdaQLParserVisitor.d.ts +126 -17
  17. package/lib/WebdaQLParserVisitor.d.ts.map +1 -1
  18. package/lib/aggregation-query.d.ts +95 -0
  19. package/lib/aggregation-query.d.ts.map +1 -0
  20. package/lib/aggregation-query.js +104 -0
  21. package/lib/aggregation-query.js.map +1 -0
  22. package/lib/aggregation-select.spec.d.ts +2 -0
  23. package/lib/aggregation-select.spec.d.ts.map +1 -0
  24. package/lib/aggregation-select.spec.js +165 -0
  25. package/lib/aggregation-select.spec.js.map +1 -0
  26. package/lib/aggregation.d.ts +97 -0
  27. package/lib/aggregation.d.ts.map +1 -0
  28. package/lib/aggregation.js +241 -0
  29. package/lib/aggregation.js.map +1 -0
  30. package/lib/aggregation.spec.d.ts +2 -0
  31. package/lib/aggregation.spec.d.ts.map +1 -0
  32. package/lib/aggregation.spec.js +360 -0
  33. package/lib/aggregation.spec.js.map +1 -0
  34. package/lib/bind.d.ts.map +1 -1
  35. package/lib/bind.js +29 -0
  36. package/lib/bind.js.map +1 -1
  37. package/lib/filter.d.ts +54 -0
  38. package/lib/filter.d.ts.map +1 -0
  39. package/lib/filter.js +135 -0
  40. package/lib/filter.js.map +1 -0
  41. package/lib/filter.spec.d.ts +2 -0
  42. package/lib/filter.spec.d.ts.map +1 -0
  43. package/lib/filter.spec.js +124 -0
  44. package/lib/filter.spec.js.map +1 -0
  45. package/lib/index.d.ts +2 -0
  46. package/lib/index.d.ts.map +1 -1
  47. package/lib/index.js +2 -0
  48. package/lib/index.js.map +1 -1
  49. package/lib/query.d.ts +173 -12
  50. package/lib/query.d.ts.map +1 -1
  51. package/lib/query.js +529 -64
  52. package/lib/query.js.map +1 -1
  53. package/lib/query.spec.js +7 -4
  54. package/lib/query.spec.js.map +1 -1
  55. package/lib/statements.spec.d.ts +2 -0
  56. package/lib/statements.spec.d.ts.map +1 -0
  57. package/lib/statements.spec.js +423 -0
  58. package/lib/statements.spec.js.map +1 -0
  59. package/lib/webdaql-string.d.ts +9 -0
  60. package/lib/webdaql-string.d.ts.map +1 -1
  61. package/lib/webdaql-string.js +9 -8
  62. package/lib/webdaql-string.js.map +1 -1
  63. package/package.json +2 -2
@@ -0,0 +1,241 @@
1
+ import { assertFilterQuery, ComparisonExpression, parse } from "./query.js";
2
+ import { bind } from "./bind.js";
3
+ import { WebdaQLError } from "./webdaql-string.js";
4
+ import { AggregationError, checkAlias, validateAggregation } from "./aggregation-query.js";
5
+ // Validation lives apart so query.ts can use it without importing this module back
6
+ export * from "./aggregation-query.js";
7
+ const TYPE_RANK = { number: 1, bigint: 1, string: 2, boolean: 3 };
8
+ /**
9
+ * Compare two values the way every backend orders aggregated rows
10
+ *
11
+ * null / undefined first, then numbers, strings (code unit order), booleans, then anything
12
+ * else by its JSON representation.
13
+ * @param a - first value
14
+ * @param b - second value
15
+ * @returns negative, zero or positive
16
+ */
17
+ export function compareValues(a, b) {
18
+ const aNull = a === null || a === undefined;
19
+ const bNull = b === null || b === undefined;
20
+ if (aNull || bNull) {
21
+ return aNull === bNull ? 0 : aNull ? -1 : 1;
22
+ }
23
+ const rankA = TYPE_RANK[typeof a] ?? 4;
24
+ const rankB = TYPE_RANK[typeof b] ?? 4;
25
+ if (rankA !== rankB) {
26
+ return rankA - rankB;
27
+ }
28
+ const left = rankA === 4 ? JSON.stringify(a) : a;
29
+ const right = rankB === 4 ? JSON.stringify(b) : b;
30
+ return left < right ? -1 : left > right ? 1 : 0;
31
+ }
32
+ /**
33
+ * Read a dotted path, undefined when any segment is missing
34
+ *
35
+ * A Date is returned as its ISO string, the form JSON backends store: group keys, MIN / MAX and
36
+ * COUNT_DISTINCT then match on every backend.
37
+ * @param item - the object
38
+ * @param path - dotted path
39
+ * @returns the value
40
+ */
41
+ function readPath(item, path) {
42
+ const value = ComparisonExpression.getAttributeValue(item, path.split("."));
43
+ if (value instanceof Date) {
44
+ return Number.isNaN(value.getTime()) ? null : value.toISOString();
45
+ }
46
+ return value;
47
+ }
48
+ /**
49
+ * Create the accumulator of a metric
50
+ * @param metric - the metric
51
+ * @returns the accumulator
52
+ */
53
+ function createAccumulator(metric) {
54
+ const value = (item) => (metric.field === undefined ? item : readPath(item, metric.field));
55
+ const present = (v) => v !== null && v !== undefined;
56
+ const numeric = (v) => typeof v === "number" && Number.isFinite(v);
57
+ switch (metric.fn) {
58
+ case "COUNT": {
59
+ let count = 0;
60
+ return { add: item => void (present(value(item)) && count++), result: () => count };
61
+ }
62
+ case "COUNT_DISTINCT": {
63
+ const seen = new Set();
64
+ return {
65
+ add: item => {
66
+ const v = value(item);
67
+ if (present(v))
68
+ seen.add(JSON.stringify(v));
69
+ },
70
+ result: () => seen.size
71
+ };
72
+ }
73
+ case "SUM": {
74
+ let sum = 0;
75
+ return {
76
+ add: item => {
77
+ const v = value(item);
78
+ if (numeric(v))
79
+ sum += v;
80
+ },
81
+ result: () => sum
82
+ };
83
+ }
84
+ case "AVG": {
85
+ let sum = 0;
86
+ let count = 0;
87
+ return {
88
+ add: item => {
89
+ const v = value(item);
90
+ if (numeric(v)) {
91
+ sum += v;
92
+ count++;
93
+ }
94
+ },
95
+ result: () => (count ? sum / count : null)
96
+ };
97
+ }
98
+ case "MIN":
99
+ case "MAX": {
100
+ const sign = metric.fn === "MIN" ? 1 : -1;
101
+ let current = undefined;
102
+ return {
103
+ add: item => {
104
+ const v = value(item);
105
+ if (present(v) && (current === undefined || sign * compareValues(v, current) < 0))
106
+ current = v;
107
+ },
108
+ result: () => current ?? null
109
+ };
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * Streaming reference implementation of an aggregation
115
+ *
116
+ * Items must already match the query filter. Memory is O(groups), plus one Set per group per
117
+ * COUNT_DISTINCT. It is the fallback engine of repositories and the oracle of the
118
+ * conformance tests.
119
+ */
120
+ export class Aggregator {
121
+ query;
122
+ maxGroups;
123
+ groups = new Map();
124
+ /**
125
+ * @param query - the aggregation; validated here
126
+ * @param maxGroups - throw AGGREGATION_TOO_MANY_GROUPS beyond this number of groups
127
+ */
128
+ constructor(query, maxGroups = Number.POSITIVE_INFINITY) {
129
+ this.query = query;
130
+ this.maxGroups = maxGroups;
131
+ validateAggregation(query);
132
+ }
133
+ /**
134
+ * Create an empty group
135
+ * @param keys - group key values
136
+ * @returns the group
137
+ */
138
+ createGroup(keys) {
139
+ return {
140
+ keys,
141
+ accumulators: Object.entries(this.query.metrics).map(([alias, metric]) => [alias, createAccumulator(metric)])
142
+ };
143
+ }
144
+ /**
145
+ * Add a matching item
146
+ * @param item - the item
147
+ */
148
+ add(item) {
149
+ const keys = this.query.groupBy.map(path => readPath(item, path) ?? null);
150
+ const id = JSON.stringify(keys);
151
+ let group = this.groups.get(id);
152
+ if (!group) {
153
+ if (this.groups.size >= this.maxGroups) {
154
+ throw new AggregationError("AGGREGATION_TOO_MANY_GROUPS", `Aggregation exceeds ${this.maxGroups} groups`);
155
+ }
156
+ group = this.createGroup(keys);
157
+ this.groups.set(id, group);
158
+ }
159
+ for (const [, accumulator] of group.accumulators) {
160
+ accumulator.add(item);
161
+ }
162
+ }
163
+ /**
164
+ * Compute the rows, ordered and limited
165
+ * @returns flat rows keyed by group path and metric alias
166
+ */
167
+ rows() {
168
+ const groups = [...this.groups.values()];
169
+ if (!groups.length && !this.query.groupBy.length) {
170
+ groups.push(this.createGroup([]));
171
+ }
172
+ let rows = groups.map(group => {
173
+ const row = {};
174
+ this.query.groupBy.forEach((path, i) => (row[path] = group.keys[i]));
175
+ group.accumulators.forEach(([alias, accumulator]) => (row[alias] = accumulator.result()));
176
+ return row;
177
+ });
178
+ const orderBy = this.query.orderBy ?? [];
179
+ if (orderBy.length) {
180
+ rows.sort((a, b) => {
181
+ for (const order of orderBy) {
182
+ const c = compareValues(a[order.key], b[order.key]);
183
+ if (c)
184
+ return order.direction === "ASC" ? c : -c;
185
+ }
186
+ return 0;
187
+ });
188
+ }
189
+ if (this.query.limit) {
190
+ rows = rows.slice(0, this.query.limit);
191
+ }
192
+ return rows;
193
+ }
194
+ }
195
+ const METRIC_KEYS = {
196
+ count: "COUNT",
197
+ countDistinct: "COUNT_DISTINCT",
198
+ sum: "SUM",
199
+ avg: "AVG",
200
+ min: "MIN",
201
+ max: "MAX"
202
+ };
203
+ /**
204
+ * Convert the object form of an aggregation to the canonical AST
205
+ * @param input - the object form
206
+ * @param params - values for the `?` / `:name` placeholders of the filter
207
+ * @returns the validated AST
208
+ * @throws WebdaQLError when the input is invalid
209
+ */
210
+ export function toAggregationQuery(input, params) {
211
+ let filter = input.filter ?? "";
212
+ if (params !== undefined) {
213
+ filter = bind(filter, params);
214
+ }
215
+ const parsed = parse(filter);
216
+ // DELETE / UPDATE / SELECT statements are not filters
217
+ assertFilterQuery(parsed);
218
+ if (parsed.limit !== undefined || parsed.orderBy?.length || parsed.continuationToken !== undefined) {
219
+ throw new WebdaQLError("An aggregation filter cannot contain ORDER BY, LIMIT or OFFSET");
220
+ }
221
+ const metrics = {};
222
+ for (const [alias, spec] of Object.entries(input.metrics ?? {})) {
223
+ // Before assigning: an own `__proto__` key would otherwise change the prototype of `metrics`
224
+ checkAlias(alias);
225
+ const entries = Object.entries(spec ?? {});
226
+ if (entries.length !== 1 || !Object.prototype.hasOwnProperty.call(METRIC_KEYS, entries[0][0])) {
227
+ throw new WebdaQLError(`Metric '${alias}' must define exactly one of ${Object.keys(METRIC_KEYS).join(", ")}`);
228
+ }
229
+ const [kind, field] = entries[0];
230
+ const fn = METRIC_KEYS[kind];
231
+ metrics[alias] = fn === "COUNT" && field === "*" ? { fn } : { fn, field: field };
232
+ }
233
+ return validateAggregation({
234
+ filter: parsed.filter,
235
+ groupBy: [...(input.groupBy ?? [])],
236
+ metrics,
237
+ orderBy: input.orderBy?.map(order => ({ key: order.key, direction: order.direction })),
238
+ limit: input.limit
239
+ });
240
+ }
241
+ //# sourceMappingURL=aggregation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregation.js","sourceRoot":"","sources":["../src/aggregation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=aggregation.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregation.spec.d.ts","sourceRoot":"","sources":["../src/aggregation.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,360 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { suite, test } from "@webda/test";
36
+ import * as assert from "assert";
37
+ import { Aggregator, AggregationError, compareValues, toAggregationQuery, validateAggregation } from "./aggregation.js";
38
+ import { AndExpression } from "./query.js";
39
+ import { WebdaQLError } from "./webdaql-string.js";
40
+ /**
41
+ * Build a valid aggregation query, overridden by the given fields
42
+ * @param over - fields to override
43
+ * @returns the query
44
+ */
45
+ function q(over = {}) {
46
+ return {
47
+ filter: new AndExpression([]),
48
+ groupBy: ["status"],
49
+ metrics: { n: { fn: "COUNT" } },
50
+ ...over
51
+ };
52
+ }
53
+ let ValidateAggregationTest = (() => {
54
+ let _classDecorators = [suite];
55
+ let _classDescriptor;
56
+ let _classExtraInitializers = [];
57
+ let _classThis;
58
+ let _instanceExtraInitializers = [];
59
+ let _valid_decorators;
60
+ let _rejects_decorators;
61
+ let _digitsInsideSegments_decorators;
62
+ let _missingGroupBy_decorators;
63
+ let _errorCode_decorators;
64
+ var ValidateAggregationTest = class {
65
+ static { _classThis = this; }
66
+ static {
67
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
68
+ _valid_decorators = [test];
69
+ _rejects_decorators = [test];
70
+ _digitsInsideSegments_decorators = [test];
71
+ _missingGroupBy_decorators = [test];
72
+ _errorCode_decorators = [test];
73
+ __esDecorate(this, null, _valid_decorators, { kind: "method", name: "valid", static: false, private: false, access: { has: obj => "valid" in obj, get: obj => obj.valid }, metadata: _metadata }, null, _instanceExtraInitializers);
74
+ __esDecorate(this, null, _rejects_decorators, { kind: "method", name: "rejects", static: false, private: false, access: { has: obj => "rejects" in obj, get: obj => obj.rejects }, metadata: _metadata }, null, _instanceExtraInitializers);
75
+ __esDecorate(this, null, _digitsInsideSegments_decorators, { kind: "method", name: "digitsInsideSegments", static: false, private: false, access: { has: obj => "digitsInsideSegments" in obj, get: obj => obj.digitsInsideSegments }, metadata: _metadata }, null, _instanceExtraInitializers);
76
+ __esDecorate(this, null, _missingGroupBy_decorators, { kind: "method", name: "missingGroupBy", static: false, private: false, access: { has: obj => "missingGroupBy" in obj, get: obj => obj.missingGroupBy }, metadata: _metadata }, null, _instanceExtraInitializers);
77
+ __esDecorate(this, null, _errorCode_decorators, { kind: "method", name: "errorCode", static: false, private: false, access: { has: obj => "errorCode" in obj, get: obj => obj.errorCode }, metadata: _metadata }, null, _instanceExtraInitializers);
78
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
79
+ ValidateAggregationTest = _classThis = _classDescriptor.value;
80
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
81
+ __runInitializers(_classThis, _classExtraInitializers);
82
+ }
83
+ valid() {
84
+ const query = q({
85
+ groupBy: ["status", "owner.uuid"],
86
+ metrics: { n: { fn: "COUNT" }, total: { fn: "SUM", field: "points" }, d: { fn: "COUNT_DISTINCT", field: "tag" } },
87
+ orderBy: [
88
+ { key: "n", direction: "DESC" },
89
+ { key: "owner.uuid", direction: "ASC" }
90
+ ],
91
+ limit: 10
92
+ });
93
+ assert.strictEqual(validateAggregation(query), query);
94
+ }
95
+ rejects() {
96
+ const bad = [
97
+ ["no metric", { metrics: {} }],
98
+ ["bad path", { groupBy: ["a b"] }],
99
+ ["proto path", { groupBy: ["__proto__.x"] }],
100
+ ["constructor path", { groupBy: ["a.constructor"] }],
101
+ ["duplicate group", { groupBy: ["a", "a"] }],
102
+ ["bad alias", { metrics: { "1n": { fn: "COUNT" } } }],
103
+ ["underscore alias", { metrics: { _id: { fn: "COUNT" } } }],
104
+ ["reserved alias", { metrics: { constructor: { fn: "COUNT" } } }],
105
+ ["alias clash", { metrics: { status: { fn: "COUNT" } } }],
106
+ ["unknown fn", { metrics: { n: { fn: "MEDIAN", field: "a" } } }],
107
+ ["missing field", { metrics: { n: { fn: "SUM" } } }],
108
+ ["bad field", { metrics: { n: { fn: "SUM", field: "a;drop" } } }],
109
+ ["unknown order key", { orderBy: [{ key: "nope", direction: "ASC" }] }],
110
+ ["bad direction", { orderBy: [{ key: "n", direction: "UP" }] }],
111
+ ["zero limit", { limit: 0 }],
112
+ ["float limit", { limit: 1.5 }],
113
+ ["digit group segment", { groupBy: ["tags.0"] }],
114
+ ["digit field segment", { metrics: { n: { fn: "MAX", field: "items.12.price" } } }]
115
+ ];
116
+ for (const [name, over] of bad) {
117
+ assert.throws(() => validateAggregation(q(over)), WebdaQLError, name);
118
+ }
119
+ }
120
+ digitsInsideSegments() {
121
+ // Only all-digit segments are rejected: MongoDB `$a.0` does not index arrays
122
+ validateAggregation(q({ groupBy: ["a1", "b.c2d"] }));
123
+ }
124
+ missingGroupBy() {
125
+ const query = { filter: new AndExpression([]), metrics: { n: { fn: "COUNT" } } };
126
+ validateAggregation(query);
127
+ assert.deepStrictEqual(query.groupBy, [], "a missing groupBy is normalized to []");
128
+ const agg = new Aggregator({ filter: new AndExpression([]), metrics: { n: { fn: "COUNT" } } });
129
+ agg.add({});
130
+ assert.deepStrictEqual(agg.rows(), [{ n: 1 }]);
131
+ }
132
+ errorCode() {
133
+ const err = new AggregationError("AGGREGATION_NOT_NATIVE", "nope");
134
+ assert.ok(err instanceof WebdaQLError);
135
+ assert.strictEqual(err.code, "AGGREGATION_NOT_NATIVE");
136
+ assert.strictEqual(err.name, "AggregationError");
137
+ }
138
+ constructor() {
139
+ __runInitializers(this, _instanceExtraInitializers);
140
+ }
141
+ };
142
+ return ValidateAggregationTest = _classThis;
143
+ })();
144
+ /**
145
+ * Run an aggregation over items
146
+ * @param over - query overrides
147
+ * @param items - items, already filtered
148
+ * @returns the rows
149
+ */
150
+ function run(over, items) {
151
+ const agg = new Aggregator(q(over));
152
+ items.forEach(item => agg.add(item));
153
+ return agg.rows();
154
+ }
155
+ const ITEMS = [
156
+ { status: "open", points: 3, tag: "a", owner: { uuid: "u1" }, label: "delta" },
157
+ { status: "open", points: "8", tag: "a", owner: { uuid: "u2" }, label: "alpha" },
158
+ { status: "done", points: null, tag: "b", label: "charlie" },
159
+ { status: null, points: 5, tag: null, owner: { uuid: "u1" } },
160
+ { points: 2, tag: "c" }
161
+ ];
162
+ let AggregatorTest = (() => {
163
+ let _classDecorators = [suite];
164
+ let _classDescriptor;
165
+ let _classExtraInitializers = [];
166
+ let _classThis;
167
+ let _instanceExtraInitializers = [];
168
+ let _compare_decorators;
169
+ let _groupedCounts_decorators;
170
+ let _metricSemantics_decorators;
171
+ let _emptyGroups_decorators;
172
+ let _nestedGroupAndOrderLimit_decorators;
173
+ let _dates_decorators;
174
+ let _maxGroups_decorators;
175
+ var AggregatorTest = class {
176
+ static { _classThis = this; }
177
+ static {
178
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
179
+ _compare_decorators = [test];
180
+ _groupedCounts_decorators = [test];
181
+ _metricSemantics_decorators = [test];
182
+ _emptyGroups_decorators = [test];
183
+ _nestedGroupAndOrderLimit_decorators = [test];
184
+ _dates_decorators = [test];
185
+ _maxGroups_decorators = [test];
186
+ __esDecorate(this, null, _compare_decorators, { kind: "method", name: "compare", static: false, private: false, access: { has: obj => "compare" in obj, get: obj => obj.compare }, metadata: _metadata }, null, _instanceExtraInitializers);
187
+ __esDecorate(this, null, _groupedCounts_decorators, { kind: "method", name: "groupedCounts", static: false, private: false, access: { has: obj => "groupedCounts" in obj, get: obj => obj.groupedCounts }, metadata: _metadata }, null, _instanceExtraInitializers);
188
+ __esDecorate(this, null, _metricSemantics_decorators, { kind: "method", name: "metricSemantics", static: false, private: false, access: { has: obj => "metricSemantics" in obj, get: obj => obj.metricSemantics }, metadata: _metadata }, null, _instanceExtraInitializers);
189
+ __esDecorate(this, null, _emptyGroups_decorators, { kind: "method", name: "emptyGroups", static: false, private: false, access: { has: obj => "emptyGroups" in obj, get: obj => obj.emptyGroups }, metadata: _metadata }, null, _instanceExtraInitializers);
190
+ __esDecorate(this, null, _nestedGroupAndOrderLimit_decorators, { kind: "method", name: "nestedGroupAndOrderLimit", static: false, private: false, access: { has: obj => "nestedGroupAndOrderLimit" in obj, get: obj => obj.nestedGroupAndOrderLimit }, metadata: _metadata }, null, _instanceExtraInitializers);
191
+ __esDecorate(this, null, _dates_decorators, { kind: "method", name: "dates", static: false, private: false, access: { has: obj => "dates" in obj, get: obj => obj.dates }, metadata: _metadata }, null, _instanceExtraInitializers);
192
+ __esDecorate(this, null, _maxGroups_decorators, { kind: "method", name: "maxGroups", static: false, private: false, access: { has: obj => "maxGroups" in obj, get: obj => obj.maxGroups }, metadata: _metadata }, null, _instanceExtraInitializers);
193
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
194
+ AggregatorTest = _classThis = _classDescriptor.value;
195
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
196
+ __runInitializers(_classThis, _classExtraInitializers);
197
+ }
198
+ compare() {
199
+ assert.ok(compareValues(null, 0) < 0, "null first");
200
+ assert.ok(compareValues(undefined, "a") < 0, "undefined is null");
201
+ assert.strictEqual(compareValues(null, undefined), 0);
202
+ assert.ok(compareValues(2, 10) < 0, "numeric, not lexical");
203
+ assert.ok(compareValues("B", "a") < 0, "code unit order");
204
+ assert.ok(compareValues(false, true) < 0);
205
+ assert.ok(compareValues(1, "1") < 0, "numbers before strings");
206
+ assert.ok(compareValues("2026-01-02", "2026-01-10") < 0, "ISO dates as strings");
207
+ }
208
+ groupedCounts() {
209
+ assert.deepStrictEqual(run({ metrics: { n: { fn: "COUNT" } }, orderBy: [{ key: "status", direction: "ASC" }] }, ITEMS), [
210
+ { status: null, n: 2 },
211
+ { status: "done", n: 1 },
212
+ { status: "open", n: 2 }
213
+ ], "missing and null keys share one group, sorted first");
214
+ }
215
+ metricSemantics() {
216
+ assert.deepStrictEqual(run({
217
+ groupBy: [],
218
+ metrics: {
219
+ all: { fn: "COUNT" },
220
+ withTag: { fn: "COUNT", field: "tag" },
221
+ tags: { fn: "COUNT_DISTINCT", field: "tag" },
222
+ total: { fn: "SUM", field: "points" },
223
+ mean: { fn: "AVG", field: "points" },
224
+ lo: { fn: "MIN", field: "label" },
225
+ hi: { fn: "MAX", field: "points" }
226
+ }
227
+ }, ITEMS), [{ all: 5, withTag: 4, tags: 3, total: 10, mean: 10 / 3, lo: "alpha", hi: "8" }]);
228
+ }
229
+ emptyGroups() {
230
+ assert.deepStrictEqual(run({
231
+ groupBy: [],
232
+ metrics: {
233
+ n: { fn: "COUNT" },
234
+ total: { fn: "SUM", field: "points" },
235
+ mean: { fn: "AVG", field: "points" },
236
+ lo: { fn: "MIN", field: "points" },
237
+ d: { fn: "COUNT_DISTINCT", field: "tag" }
238
+ }
239
+ }, []), [{ n: 0, total: 0, mean: null, lo: null, d: 0 }], "a global aggregation always returns one row");
240
+ assert.deepStrictEqual(run({}, []), [], "a grouped aggregation over nothing has no row");
241
+ assert.deepStrictEqual(run({ groupBy: ["status"], metrics: { total: { fn: "SUM", field: "points" } } }, [{ status: "x", points: "1" }]), [{ status: "x", total: 0 }], "non-numeric values are ignored by SUM");
242
+ }
243
+ nestedGroupAndOrderLimit() {
244
+ assert.deepStrictEqual(run({
245
+ groupBy: ["owner.uuid"],
246
+ metrics: { n: { fn: "COUNT" } },
247
+ orderBy: [
248
+ { key: "n", direction: "DESC" },
249
+ { key: "owner.uuid", direction: "DESC" }
250
+ ],
251
+ limit: 2
252
+ }, ITEMS), [
253
+ { "owner.uuid": "u1", n: 2 },
254
+ { "owner.uuid": null, n: 2 }
255
+ ], "null sorts last in DESC");
256
+ }
257
+ dates() {
258
+ const items = [
259
+ { day: new Date("2026-01-05T10:00:00.000Z"), at: new Date("2026-01-05T10:00:00.000Z") },
260
+ { day: "2026-01-05T10:00:00.000Z", at: new Date("2025-12-31T23:59:59.000Z") },
261
+ { day: new Date("2026-03-01T00:00:00.000Z"), at: "2026-03-01T00:00:00.000Z" }
262
+ ];
263
+ // Group keys: a Date and its ISO string are one group, returned as the ISO string
264
+ assert.deepStrictEqual(run({
265
+ groupBy: ["day"],
266
+ metrics: { n: { fn: "COUNT" } },
267
+ orderBy: [{ key: "day", direction: "ASC" }]
268
+ }, items), [
269
+ { day: "2026-01-05T10:00:00.000Z", n: 2 },
270
+ { day: "2026-03-01T00:00:00.000Z", n: 1 }
271
+ ]);
272
+ // MIN / MAX return ISO strings; COUNT_DISTINCT treats a Date and its ISO string alike
273
+ assert.deepStrictEqual(run({
274
+ groupBy: [],
275
+ metrics: {
276
+ lo: { fn: "MIN", field: "at" },
277
+ hi: { fn: "MAX", field: "at" },
278
+ days: { fn: "COUNT_DISTINCT", field: "day" }
279
+ }
280
+ }, items), [{ lo: "2025-12-31T23:59:59.000Z", hi: "2026-03-01T00:00:00.000Z", days: 2 }]);
281
+ }
282
+ maxGroups() {
283
+ const agg = new Aggregator(q({ groupBy: ["tag"] }), 2);
284
+ agg.add({ tag: "a" });
285
+ agg.add({ tag: "b" });
286
+ agg.add({ tag: "a" });
287
+ assert.throws(() => agg.add({ tag: "c" }), (err) => err.code === "AGGREGATION_TOO_MANY_GROUPS");
288
+ }
289
+ constructor() {
290
+ __runInitializers(this, _instanceExtraInitializers);
291
+ }
292
+ };
293
+ return AggregatorTest = _classThis;
294
+ })();
295
+ let ToAggregationQueryTest = (() => {
296
+ let _classDecorators = [suite];
297
+ let _classDescriptor;
298
+ let _classExtraInitializers = [];
299
+ let _classThis;
300
+ let _instanceExtraInitializers = [];
301
+ let _converts_decorators;
302
+ let _defaults_decorators;
303
+ let _rejects_decorators;
304
+ var ToAggregationQueryTest = class {
305
+ static { _classThis = this; }
306
+ static {
307
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
308
+ _converts_decorators = [test];
309
+ _defaults_decorators = [test];
310
+ _rejects_decorators = [test];
311
+ __esDecorate(this, null, _converts_decorators, { kind: "method", name: "converts", static: false, private: false, access: { has: obj => "converts" in obj, get: obj => obj.converts }, metadata: _metadata }, null, _instanceExtraInitializers);
312
+ __esDecorate(this, null, _defaults_decorators, { kind: "method", name: "defaults", static: false, private: false, access: { has: obj => "defaults" in obj, get: obj => obj.defaults }, metadata: _metadata }, null, _instanceExtraInitializers);
313
+ __esDecorate(this, null, _rejects_decorators, { kind: "method", name: "rejects", static: false, private: false, access: { has: obj => "rejects" in obj, get: obj => obj.rejects }, metadata: _metadata }, null, _instanceExtraInitializers);
314
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
315
+ ToAggregationQueryTest = _classThis = _classDescriptor.value;
316
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
317
+ __runInitializers(_classThis, _classExtraInitializers);
318
+ }
319
+ converts() {
320
+ const query = toAggregationQuery({
321
+ filter: "status = :status AND points > :min",
322
+ groupBy: ["owner.uuid"],
323
+ metrics: { n: { count: "*" }, withTag: { count: "tag" }, d: { countDistinct: "tag" }, s: { sum: "points" } },
324
+ orderBy: [{ key: "n", direction: "DESC" }],
325
+ limit: 5
326
+ }, { status: "open", min: 1 });
327
+ assert.strictEqual(query.filter.toString(), 'status = "open" AND points > 1');
328
+ assert.deepStrictEqual(query.groupBy, ["owner.uuid"]);
329
+ assert.deepStrictEqual(query.metrics, {
330
+ n: { fn: "COUNT" },
331
+ withTag: { fn: "COUNT", field: "tag" },
332
+ d: { fn: "COUNT_DISTINCT", field: "tag" },
333
+ s: { fn: "SUM", field: "points" }
334
+ });
335
+ assert.deepStrictEqual(query.orderBy, [{ key: "n", direction: "DESC" }]);
336
+ assert.strictEqual(query.limit, 5);
337
+ }
338
+ defaults() {
339
+ const query = toAggregationQuery({ metrics: { n: { count: "*" } } });
340
+ assert.strictEqual(query.filter.toString(), "");
341
+ assert.deepStrictEqual(query.groupBy, []);
342
+ }
343
+ rejects() {
344
+ assert.throws(() => toAggregationQuery({ filter: "a = 1 LIMIT 3", metrics: { n: { count: "*" } } }), WebdaQLError);
345
+ assert.throws(() => toAggregationQuery({ filter: "a = 1 ORDER BY a", metrics: { n: { count: "*" } } }), WebdaQLError);
346
+ assert.throws(() => toAggregationQuery({ filter: "a = 1 OFFSET 'x'", metrics: { n: { count: "*" } } }), WebdaQLError);
347
+ assert.throws(() => toAggregationQuery({ filter: "DELETE WHERE a = 1", metrics: { n: { count: "*" } } }), WebdaQLError);
348
+ assert.throws(() => toAggregationQuery({ filter: "SELECT a WHERE a = 1", metrics: { n: { count: "*" } } }), WebdaQLError);
349
+ assert.throws(() => toAggregationQuery({ metrics: { n: { count: "*", sum: "a" } } }), WebdaQLError);
350
+ assert.throws(() => toAggregationQuery({ metrics: { n: { toString: "a" } } }), WebdaQLError);
351
+ assert.throws(() => toAggregationQuery({ metrics: { n: { sum: "*" } } }), WebdaQLError, "* only for count");
352
+ assert.throws(() => toAggregationQuery({ metrics: JSON.parse('{"__proto__": {"count": "*"}}') }), /Invalid metric alias/, "reserved alias is rejected, not dropped");
353
+ }
354
+ constructor() {
355
+ __runInitializers(this, _instanceExtraInitializers);
356
+ }
357
+ };
358
+ return ToAggregationQueryTest = _classThis;
359
+ })();
360
+ //# sourceMappingURL=aggregation.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregation.spec.js","sourceRoot":"","sources":["../src/aggregation.spec.ts"],"names":[],"mappings":"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"}