@taylordb/query-builder 0.9.15 → 0.10.0

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 (33) hide show
  1. package/README.md +5 -2
  2. package/dist/cjs/@types/aggregate.d.ts +16 -1
  3. package/dist/cjs/__tests__/query-builder.spec.js +93 -3
  4. package/dist/cjs/__tests__/query-builder.spec.js.map +1 -1
  5. package/dist/cjs/__tests__/taylorclient.types.d.ts +3 -3
  6. package/dist/cjs/aggregation-helpers.d.ts +77 -0
  7. package/dist/cjs/aggregation-helpers.js +103 -0
  8. package/dist/cjs/aggregation-helpers.js.map +1 -0
  9. package/dist/cjs/aggregation-query-builder.d.ts +30 -22
  10. package/dist/cjs/aggregation-query-builder.js +124 -20
  11. package/dist/cjs/aggregation-query-builder.js.map +1 -1
  12. package/dist/cjs/batch-query-builder.d.ts +1 -1
  13. package/dist/cjs/batch-query-builder.js +1 -1
  14. package/dist/cjs/index.d.ts +2 -0
  15. package/dist/cjs/index.js +11 -1
  16. package/dist/cjs/index.js.map +1 -1
  17. package/dist/esm/@types/aggregate.d.ts +16 -1
  18. package/dist/esm/__tests__/query-builder.spec.js +94 -4
  19. package/dist/esm/__tests__/query-builder.spec.js.map +1 -1
  20. package/dist/esm/__tests__/taylorclient.types.d.ts +3 -3
  21. package/dist/esm/aggregation-helpers.d.ts +77 -0
  22. package/dist/esm/aggregation-helpers.js +92 -0
  23. package/dist/esm/aggregation-helpers.js.map +1 -0
  24. package/dist/esm/aggregation-query-builder.d.ts +30 -22
  25. package/dist/esm/aggregation-query-builder.js +124 -20
  26. package/dist/esm/aggregation-query-builder.js.map +1 -1
  27. package/dist/esm/batch-query-builder.d.ts +1 -1
  28. package/dist/esm/batch-query-builder.js +1 -1
  29. package/dist/esm/index.d.ts +2 -0
  30. package/dist/esm/index.js +1 -0
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  33. package/package.json +2 -2
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Helper functions for creating aggregation metrics.
3
+ * These functions return objects that describe the aggregation to perform.
4
+ */
5
+ /**
6
+ * Creates a count aggregation for the specified field.
7
+ * @param field - The field name to count.
8
+ * @returns An aggregation helper object.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * count('id')
13
+ * ```
14
+ */
15
+ export function count(field) {
16
+ return { field, aggregation: 'count' };
17
+ }
18
+ /**
19
+ * Creates an average aggregation for the specified field.
20
+ * @param field - The field name to average.
21
+ * @returns An aggregation helper object.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * avg('age')
26
+ * ```
27
+ */
28
+ export function avg(field) {
29
+ return { field, aggregation: 'average' };
30
+ }
31
+ /**
32
+ * Creates a sum aggregation for the specified field.
33
+ * @param field - The field name to sum.
34
+ * @returns An aggregation helper object.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * sum('age')
39
+ * ```
40
+ */
41
+ export function sum(field) {
42
+ return { field, aggregation: 'sum' };
43
+ }
44
+ /**
45
+ * Creates a median aggregation for the specified field.
46
+ * @param field - The field name to calculate median for.
47
+ * @returns An aggregation helper object.
48
+ */
49
+ export function median(field) {
50
+ return { field, aggregation: 'median' };
51
+ }
52
+ /**
53
+ * Creates a min aggregation for the specified field.
54
+ * @param field - The field name to find minimum for.
55
+ * @returns An aggregation helper object.
56
+ */
57
+ export function min(field) {
58
+ return { field, aggregation: 'min' };
59
+ }
60
+ /**
61
+ * Creates a max aggregation for the specified field.
62
+ * @param field - The field name to find maximum for.
63
+ * @returns An aggregation helper object.
64
+ */
65
+ export function max(field) {
66
+ return { field, aggregation: 'max' };
67
+ }
68
+ /**
69
+ * Creates a range aggregation for the specified field.
70
+ * @param field - The field name to calculate range for.
71
+ * @returns An aggregation helper object.
72
+ */
73
+ export function range(field) {
74
+ return { field, aggregation: 'range' };
75
+ }
76
+ /**
77
+ * Creates a standard deviation aggregation for the specified field.
78
+ * @param field - The field name to calculate standard deviation for.
79
+ * @returns An aggregation helper object.
80
+ */
81
+ export function stdDev(field) {
82
+ return { field, aggregation: 'standardDeviation' };
83
+ }
84
+ /**
85
+ * Creates a unique count aggregation for the specified field.
86
+ * @param field - The field name to count unique values for.
87
+ * @returns An aggregation helper object.
88
+ */
89
+ export function unique(field) {
90
+ return { field, aggregation: 'unique' };
91
+ }
92
+ //# sourceMappingURL=aggregation-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregation-helpers.js","sourceRoot":"","sources":["../../src/aggregation-helpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH;;;;;;;;;GASG;AACH,MAAM,UAAU,KAAK,CACnB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAgB,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CACjB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,SAAkB,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CACjB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAc,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAiB,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG,CACjB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAc,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,GAAG,CACjB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAc,EAAE,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CACnB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAgB,EAAE,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,mBAA4B,EAAE,CAAC;AAC9D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,KAAa;IAEb,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAiB,EAAE,CAAC;AACnD,CAAC"}
@@ -1,5 +1,6 @@
1
- import type { AggregateNode, AggregateRecord } from './@types/aggregate.js';
1
+ import type { AggregateNode, AggregateRecord, MetricsRecord } from './@types/aggregate.js';
2
2
  import type { AnyDB } from './@types/internal-types.js';
3
+ import type { AggregationHelper } from './aggregation-helpers.js';
3
4
  import { Executor } from './executor.js';
4
5
  import { FilterableQueryBuilder } from './where-query-builder.js';
5
6
  /**
@@ -11,9 +12,9 @@ import { FilterableQueryBuilder } from './where-query-builder.js';
11
12
  */
12
13
  export declare class AggregationQueryBuilder<DB extends AnyDB, TableName extends keyof DB, TGroupBy extends readonly (keyof DB[TableName] & string)[] = [], TAggregations extends {
13
14
  [K in keyof DB[TableName] & string]?: readonly (keyof DB[TableName][K]['aggregations'])[];
14
- } = object> extends FilterableQueryBuilder<DB, TableName> {
15
+ } = object, TMetrics extends Record<string, AggregationHelper> | undefined = undefined> extends FilterableQueryBuilder<DB, TableName> {
15
16
  #private;
16
- constructor(node: AggregateNode, executor: Executor);
17
+ constructor(node: AggregateNode, executor: Executor, metrics?: TMetrics);
17
18
  /**
18
19
  * Groups the results by a specified field.
19
20
  * @param field - The field to group by.
@@ -25,73 +26,80 @@ export declare class AggregationQueryBuilder<DB extends AnyDB, TableName extends
25
26
  * const userCounts = await qb
26
27
  * .aggregateFrom('users')
27
28
  * .groupBy('role')
28
- * .withAggregates({ id: ['count'] })
29
+ * .metrics({ count: count('id') })
29
30
  * .execute();
30
31
  * ```
31
32
  */
32
33
  groupBy<const TField extends keyof DB[TableName] & string>(field: TField, direction?: 'asc' | 'desc'): AggregationQueryBuilder<DB, TableName, [
33
34
  ...TGroupBy,
34
35
  TField
35
- ], TAggregations>;
36
+ ], TAggregations, TMetrics>;
36
37
  /**
37
- * Specifies the aggregations to perform.
38
- * @param aggregates - An object where the keys are field names and the values are arrays of aggregation functions.
39
- * @returns A new `AggregationQueryBuilder` instance with the aggregations applied.
38
+ * Specifies the metrics to compute using helper functions.
39
+ * Returns a flat array of records with groupBy fields and metrics at the top level.
40
+ * @param metrics - An object where keys are metric names and values are aggregation helper functions.
41
+ * @returns A new `AggregationQueryBuilder` instance with the metrics applied.
40
42
  *
41
43
  * @example
42
44
  * ```typescript
43
45
  * const userStats = await qb
44
46
  * .aggregateFrom('users')
45
- * .withAggregates({
46
- * id: ['count'],
47
- * age: ['avg', 'sum'],
47
+ * .groupBy('role', 'asc')
48
+ * .groupBy('permission', 'desc')
49
+ * .metrics({
50
+ * idCount: count('id'),
51
+ * ageAvg: avg('age'),
52
+ * ageSum: sum('age')
48
53
  * })
49
54
  * .execute();
50
55
  * ```
51
56
  */
52
- withAggregates<const T extends {
53
- [K in keyof DB[TableName] & string]?: readonly (keyof DB[TableName][K]['aggregations'])[];
54
- }>(aggregates: T): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations & T>;
57
+ metrics<const T extends Record<string, AggregationHelper>>(metrics: T): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations, T>;
55
58
  /**
56
59
  * Sets the maximum number of records to return.
57
60
  * @param count - The maximum number of records.
58
61
  * @returns A new `AggregationQueryBuilder` instance with the limit applied.
59
62
  */
60
- limit(count: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations>;
63
+ limit(count: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations, TMetrics>;
61
64
  /**
62
65
  * Sets the number of records to skip.
63
66
  * @param count - The number of records to skip.
64
67
  * @returns A new `AggregationQueryBuilder` instance with the offset applied.
65
68
  */
66
- offset(count: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations>;
69
+ offset(count: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations, TMetrics>;
67
70
  /**
68
71
  * Paginates the results.
69
72
  * @param page - The page number to retrieve.
70
73
  * @param limit - The number of records per page.
71
74
  * @returns A new `AggregationQueryBuilder` instance with pagination applied.
72
75
  */
73
- paginate(page: number, limit: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations>;
76
+ paginate(page: number, limit: number): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations, TMetrics>;
74
77
  /**
75
78
  * Sorts the results by a specified field.
76
79
  * @param field - The field to sort by.
77
80
  * @param direction - The sort direction ('asc' or 'desc').
78
81
  * @returns A new `AggregationQueryBuilder` instance with the sorting applied.
79
82
  */
80
- orderBy(field: keyof DB[TableName], direction?: 'asc' | 'desc'): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations>;
83
+ orderBy(field: keyof DB[TableName], direction?: 'asc' | 'desc'): AggregationQueryBuilder<DB, TableName, TGroupBy, TAggregations, TMetrics>;
81
84
  /**
82
85
  * Executes the aggregation query.
83
86
  * @returns A promise that resolves with an array of the aggregation results.
87
+ * If metrics were specified, returns a flat array. Otherwise, returns the nested structure.
84
88
  *
85
89
  * @example
86
90
  * ```typescript
87
91
  * const userCounts = await qb
88
92
  * .aggregateFrom('users')
89
93
  * .groupBy('role')
90
- * .withAggregates({ id: ['count'] })
94
+ * .metrics({ count: count('id') })
91
95
  * .execute();
92
96
  * ```
93
97
  */
94
- execute(): Promise<AggregateRecord<DB, TableName, TGroupBy, TAggregations>[]>;
98
+ execute(): Promise<TMetrics extends Record<string, AggregationHelper> ? MetricsRecord<DB, TableName, TGroupBy, TMetrics>[] : AggregateRecord<DB, TableName, TGroupBy, TAggregations>[]>;
99
+ /**
100
+ * Flattens the nested AggregateRecord structure into a flat array of metrics records.
101
+ */
102
+ private _flattenMetrics;
95
103
  /**
96
104
  * Subscribes to the results of the aggregation query.
97
105
  * @param callback - A callback function that will be called with the results of the aggregation query.
@@ -102,7 +110,7 @@ export declare class AggregationQueryBuilder<DB extends AnyDB, TableName extends
102
110
  * const unsubscribe = qb
103
111
  * .aggregateFrom('users')
104
112
  * .groupBy('role')
105
- * .withAggregates({ id: ['count'] })
113
+ * .metrics({ count: count('id') })
106
114
  * .subscribe((userCounts) => {
107
115
  * console.log('User counts by role:', userCounts);
108
116
  * });
@@ -111,7 +119,7 @@ export declare class AggregationQueryBuilder<DB extends AnyDB, TableName extends
111
119
  * unsubscribe();
112
120
  * ```
113
121
  */
114
- subscribe(callback: (result: AggregateRecord<DB, TableName, TGroupBy, TAggregations>[]) => void): Promise<{
122
+ subscribe(callback: (result: TMetrics extends Record<string, AggregationHelper> ? MetricsRecord<DB, TableName, TGroupBy, TMetrics>[] : AggregateRecord<DB, TableName, TGroupBy, TAggregations>[]) => void): Promise<{
115
123
  unsubscribe: () => Promise<void>;
116
124
  }>;
117
125
  compile(): {
@@ -1,3 +1,4 @@
1
+ import { isEmpty } from 'lodash';
1
2
  import { FilterableQueryBuilder } from './where-query-builder.js';
2
3
  /**
3
4
  * A query builder for performing aggregation queries.
@@ -8,9 +9,11 @@ import { FilterableQueryBuilder } from './where-query-builder.js';
8
9
  */
9
10
  export class AggregationQueryBuilder extends FilterableQueryBuilder {
10
11
  #node;
11
- constructor(node, executor) {
12
+ #metrics;
13
+ constructor(node, executor, metrics) {
12
14
  super(node, executor);
13
15
  this.#node = node;
16
+ this.#metrics = metrics;
14
17
  }
15
18
  /**
16
19
  * Groups the results by a specified field.
@@ -23,7 +26,7 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
23
26
  * const userCounts = await qb
24
27
  * .aggregateFrom('users')
25
28
  * .groupBy('role')
26
- * .withAggregates({ id: ['count'] })
29
+ * .metrics({ count: count('id') })
27
30
  * .execute();
28
31
  * ```
29
32
  */
@@ -35,33 +38,48 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
35
38
  return new AggregationQueryBuilder({
36
39
  ...this.#node,
37
40
  groupings: [...(this.#node.groupings || []), newGrouping],
38
- }, this._executor);
41
+ }, this._executor, this.#metrics);
39
42
  }
40
43
  /**
41
- * Specifies the aggregations to perform.
42
- * @param aggregates - An object where the keys are field names and the values are arrays of aggregation functions.
43
- * @returns A new `AggregationQueryBuilder` instance with the aggregations applied.
44
+ * Specifies the metrics to compute using helper functions.
45
+ * Returns a flat array of records with groupBy fields and metrics at the top level.
46
+ * @param metrics - An object where keys are metric names and values are aggregation helper functions.
47
+ * @returns A new `AggregationQueryBuilder` instance with the metrics applied.
44
48
  *
45
49
  * @example
46
50
  * ```typescript
47
51
  * const userStats = await qb
48
52
  * .aggregateFrom('users')
49
- * .withAggregates({
50
- * id: ['count'],
51
- * age: ['avg', 'sum'],
53
+ * .groupBy('role', 'asc')
54
+ * .groupBy('permission', 'desc')
55
+ * .metrics({
56
+ * idCount: count('id'),
57
+ * ageAvg: avg('age'),
58
+ * ageSum: sum('age')
52
59
  * })
53
60
  * .execute();
54
61
  * ```
55
62
  */
56
- withAggregates(aggregates) {
57
- const newAggregates = { ...this.#node.aggregations };
58
- for (const key in aggregates) {
59
- newAggregates[key] = aggregates[key].map(aggregate => aggregate);
63
+ metrics(metrics) {
64
+ // Convert metrics format to aggregations format for the backend
65
+ const newAggregates = {
66
+ ...this.#node.aggregations,
67
+ };
68
+ for (const metricName in metrics) {
69
+ const helper = metrics[metricName];
70
+ const field = helper.field;
71
+ const aggregation = helper.aggregation;
72
+ if (!newAggregates[field]) {
73
+ newAggregates[field] = [];
74
+ }
75
+ if (!newAggregates[field].includes(aggregation)) {
76
+ newAggregates[field].push(aggregation);
77
+ }
60
78
  }
61
79
  return new AggregationQueryBuilder({
62
80
  ...this.#node,
63
81
  aggregations: newAggregates,
64
- }, this._executor);
82
+ }, this._executor, metrics);
65
83
  }
66
84
  /**
67
85
  * Sets the maximum number of records to return.
@@ -72,7 +90,7 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
72
90
  return new AggregationQueryBuilder({
73
91
  ...this.#node,
74
92
  pagination: { ...this.#node.pagination, limit: count },
75
- }, this._executor);
93
+ }, this._executor, this.#metrics);
76
94
  }
77
95
  /**
78
96
  * Sets the number of records to skip.
@@ -83,7 +101,7 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
83
101
  return new AggregationQueryBuilder({
84
102
  ...this.#node,
85
103
  pagination: { ...this.#node.pagination, offset: count },
86
- }, this._executor);
104
+ }, this._executor, this.#metrics);
87
105
  }
88
106
  /**
89
107
  * Paginates the results.
@@ -108,25 +126,101 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
108
126
  return new AggregationQueryBuilder({
109
127
  ...this.#node,
110
128
  sorting: [...(this.#node.sorting || []), newSorting],
111
- }, this._executor);
129
+ }, this._executor, this.#metrics);
112
130
  }
113
131
  /**
114
132
  * Executes the aggregation query.
115
133
  * @returns A promise that resolves with an array of the aggregation results.
134
+ * If metrics were specified, returns a flat array. Otherwise, returns the nested structure.
116
135
  *
117
136
  * @example
118
137
  * ```typescript
119
138
  * const userCounts = await qb
120
139
  * .aggregateFrom('users')
121
140
  * .groupBy('role')
122
- * .withAggregates({ id: ['count'] })
141
+ * .metrics({ count: count('id') })
123
142
  * .execute();
124
143
  * ```
125
144
  */
126
145
  async execute() {
127
146
  const response = await this._executor.execute(this);
147
+ // If metrics are used, flatten the nested structure
148
+ if (this.#metrics) {
149
+ return this._flattenMetrics(response[0], this.#node.groupings
150
+ ?.filter((g) => 'field' in g && !('formula' in g))
151
+ .map(g => g.field) || [], this.#metrics);
152
+ }
128
153
  return response;
129
154
  }
155
+ /**
156
+ * Flattens the nested AggregateRecord structure into a flat array of metrics records.
157
+ */
158
+ _flattenMetrics(records, groupByFields, metrics) {
159
+ const result = [];
160
+ const flatten = (record, path) => {
161
+ if ('slug' in record && 'value' in record) {
162
+ const currentPath = {
163
+ ...path,
164
+ [record.slug]: record.value,
165
+ };
166
+ if ('children' in record &&
167
+ Array.isArray(record.children) &&
168
+ !isEmpty(record.children)) {
169
+ // Has children, recurse
170
+ for (const child of record.children) {
171
+ flatten(child, currentPath);
172
+ }
173
+ }
174
+ else {
175
+ // Leaf node, create flat record
176
+ const flatRecord = { ...currentPath };
177
+ // Add metrics
178
+ for (const metricName in metrics) {
179
+ const helper = metrics[metricName];
180
+ const field = helper.field;
181
+ const aggregation = helper.aggregation;
182
+ // Extract the metric value from aggregates
183
+ if (record.aggregates &&
184
+ field in record.aggregates &&
185
+ record.aggregates[field] &&
186
+ typeof record.aggregates[field] === 'object' &&
187
+ aggregation in record.aggregates[field]) {
188
+ flatRecord[metricName] = record.aggregates[field][aggregation];
189
+ }
190
+ else {
191
+ flatRecord[metricName] = null;
192
+ }
193
+ }
194
+ result.push(flatRecord);
195
+ }
196
+ }
197
+ else {
198
+ // No groupBy, just metrics
199
+ const flatRecord = {};
200
+ // Add metrics
201
+ for (const metricName in metrics) {
202
+ const helper = metrics[metricName];
203
+ const field = helper.field;
204
+ const aggregation = helper.aggregation;
205
+ if (record.aggregates &&
206
+ field in record.aggregates &&
207
+ record.aggregates[field] &&
208
+ typeof record.aggregates[field] === 'object' &&
209
+ aggregation in record.aggregates[field]) {
210
+ flatRecord[metricName] = record.aggregates[field][aggregation];
211
+ }
212
+ else {
213
+ flatRecord[metricName] = null;
214
+ }
215
+ }
216
+ result.push(flatRecord);
217
+ }
218
+ };
219
+ for (const record of records) {
220
+ flatten(record, {});
221
+ }
222
+ return result;
223
+ }
130
224
  /**
131
225
  * Subscribes to the results of the aggregation query.
132
226
  * @param callback - A callback function that will be called with the results of the aggregation query.
@@ -137,7 +231,7 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
137
231
  * const unsubscribe = qb
138
232
  * .aggregateFrom('users')
139
233
  * .groupBy('role')
140
- * .withAggregates({ id: ['count'] })
234
+ * .metrics({ count: count('id') })
141
235
  * .subscribe((userCounts) => {
142
236
  * console.log('User counts by role:', userCounts);
143
237
  * });
@@ -147,7 +241,17 @@ export class AggregationQueryBuilder extends FilterableQueryBuilder {
147
241
  * ```
148
242
  */
149
243
  subscribe(callback) {
150
- return this._executor.subscribe([this], callback);
244
+ return this._executor.subscribe([this], (rawResult) => {
245
+ if (this.#metrics) {
246
+ const flattened = this._flattenMetrics(rawResult, this.#node.groupings
247
+ ?.filter((g) => 'field' in g && !('formula' in g))
248
+ .map(g => g.field) || [], this.#metrics);
249
+ callback(flattened);
250
+ }
251
+ else {
252
+ callback(rawResult);
253
+ }
254
+ });
151
255
  }
152
256
  compile() {
153
257
  const query = 'mutation ($metadata: JSON) { execute(metadata: $metadata) }';
@@ -1 +1 @@
1
- {"version":3,"file":"aggregation-query-builder.js","sourceRoot":"","sources":["../../src/aggregation-query-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aggregation-query-builder.js","sourceRoot":"","sources":["../../src/aggregation-query-builder.ts"],"names":[],"mappings":"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"}
@@ -42,7 +42,7 @@ export declare class BatchQueryBuilder<const TBuilders extends readonly AnyQuery
42
42
  * ```typescript
43
43
  * const unsubscribe = qb.batch([
44
44
  * qb.selectFrom('users').select(['id', 'name']),
45
- * qb.aggregateFrom('users').groupBy('role').withAggregates({ id: ['count'] }),
45
+ * qb.aggregateFrom('users').groupBy('role').metrics({ count: count('id') }),
46
46
  * ]).subscribe(([users, userAggregates]) => {
47
47
  * console.log('Users:', users);
48
48
  * console.log('User Aggregates:', userAggregates);
@@ -36,7 +36,7 @@ export class BatchQueryBuilder {
36
36
  * ```typescript
37
37
  * const unsubscribe = qb.batch([
38
38
  * qb.selectFrom('users').select(['id', 'name']),
39
- * qb.aggregateFrom('users').groupBy('role').withAggregates({ id: ['count'] }),
39
+ * qb.aggregateFrom('users').groupBy('role').metrics({ count: count('id') }),
40
40
  * ]).subscribe(([users, userAggregates]) => {
41
41
  * console.log('Users:', users);
42
42
  * console.log('User Aggregates:', userAggregates);
@@ -1 +1,3 @@
1
+ export { avg, count, max, median, min, range, stdDev, sum, unique, } from './aggregation-helpers.js';
2
+ export type { AggregationHelper } from './aggregation-helpers.js';
1
3
  export { createQueryBuilder } from './query-builder.js';
package/dist/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ export { avg, count, max, median, min, range, stdDev, sum, unique, } from './aggregation-helpers.js';
1
2
  export { createQueryBuilder } from './query-builder.js';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,KAAK,EACL,GAAG,EACH,MAAM,EACN,GAAG,EACH,KAAK,EACL,MAAM,EACN,GAAG,EACH,MAAM,GACP,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}