@hypequery/datasets 0.1.0 → 0.2.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 (83) hide show
  1. package/README.md +498 -0
  2. package/dist/api.type-test.d.ts +2 -0
  3. package/dist/api.type-test.d.ts.map +1 -0
  4. package/dist/api.type-test.js +103 -0
  5. package/dist/constants.d.ts +9 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +11 -0
  8. package/dist/dataset-query.d.ts +16 -0
  9. package/dist/dataset-query.d.ts.map +1 -0
  10. package/dist/dataset-query.js +56 -0
  11. package/dist/dataset.d.ts +1 -1
  12. package/dist/dataset.d.ts.map +1 -1
  13. package/dist/dataset.js +22 -157
  14. package/dist/executor.d.ts +42 -14
  15. package/dist/executor.d.ts.map +1 -1
  16. package/dist/executor.js +188 -36
  17. package/dist/formulas.d.ts +1 -1
  18. package/dist/formulas.d.ts.map +1 -1
  19. package/dist/formulas.js +27 -12
  20. package/dist/in-memory-backend.d.ts +5 -0
  21. package/dist/in-memory-backend.d.ts.map +1 -0
  22. package/dist/in-memory-backend.js +221 -0
  23. package/dist/index.d.ts +6 -4
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +3 -4
  26. package/dist/internal.d.ts +23 -0
  27. package/dist/internal.d.ts.map +1 -0
  28. package/dist/internal.js +19 -0
  29. package/dist/measure.d.ts.map +1 -1
  30. package/dist/measure.js +1 -0
  31. package/dist/query-builder-protocol.d.ts +2 -2
  32. package/dist/query-builder-protocol.d.ts.map +1 -1
  33. package/dist/query-builder-protocol.js +1 -1
  34. package/dist/query-helpers.d.ts +12 -12
  35. package/dist/query-helpers.d.ts.map +1 -1
  36. package/dist/query-planner.d.ts +9 -7
  37. package/dist/query-planner.d.ts.map +1 -1
  38. package/dist/query-planner.js +26 -9
  39. package/dist/registry.d.ts +1 -1
  40. package/dist/registry.js +1 -1
  41. package/dist/relationships.d.ts +1 -1
  42. package/dist/relationships.js +1 -1
  43. package/dist/semantic-plan.d.ts +82 -0
  44. package/dist/semantic-plan.d.ts.map +1 -0
  45. package/dist/semantic-plan.js +1 -0
  46. package/dist/semantic-planner.d.ts +5 -0
  47. package/dist/semantic-planner.d.ts.map +1 -0
  48. package/dist/semantic-planner.js +155 -0
  49. package/dist/sql-utils.d.ts +1 -1
  50. package/dist/sql-utils.js +4 -4
  51. package/dist/types.d.ts +130 -52
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/utils/dataset-contract.d.ts +3 -0
  54. package/dist/utils/dataset-contract.d.ts.map +1 -0
  55. package/dist/utils/dataset-contract.js +30 -0
  56. package/dist/utils/dataset-metric-ref.d.ts +9 -0
  57. package/dist/utils/dataset-metric-ref.d.ts.map +1 -0
  58. package/dist/utils/dataset-metric-ref.js +39 -0
  59. package/dist/utils/dataset-normalization.d.ts +10 -0
  60. package/dist/utils/dataset-normalization.d.ts.map +1 -0
  61. package/dist/utils/dataset-normalization.js +35 -0
  62. package/dist/utils/dataset-query-validation.d.ts +4 -0
  63. package/dist/utils/dataset-query-validation.d.ts.map +1 -0
  64. package/dist/utils/dataset-query-validation.js +96 -0
  65. package/dist/utils/dataset-validation.d.ts +6 -0
  66. package/dist/utils/dataset-validation.d.ts.map +1 -0
  67. package/dist/utils/dataset-validation.js +42 -0
  68. package/dist/utils/derived-cte-validation.d.ts +3 -0
  69. package/dist/utils/derived-cte-validation.d.ts.map +1 -0
  70. package/dist/utils/derived-cte-validation.js +32 -0
  71. package/dist/utils/filtered-aggregation-sql.d.ts +5 -0
  72. package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -0
  73. package/dist/utils/filtered-aggregation-sql.js +73 -0
  74. package/dist/utils/metric-handle.d.ts +11 -0
  75. package/dist/utils/metric-handle.d.ts.map +1 -0
  76. package/dist/utils/metric-handle.js +36 -0
  77. package/dist/utils/pagination.d.ts +17 -0
  78. package/dist/utils/pagination.d.ts.map +1 -0
  79. package/dist/utils/pagination.js +23 -0
  80. package/dist/utils/tenant-runtime.d.ts +14 -0
  81. package/dist/utils/tenant-runtime.d.ts.map +1 -0
  82. package/dist/utils/tenant-runtime.js +36 -0
  83. package/package.json +14 -2
@@ -0,0 +1,221 @@
1
+ function valueForField(row, field) {
2
+ return row[field];
3
+ }
4
+ function compareFilter(actual, filter) {
5
+ switch (filter.operator) {
6
+ case 'eq':
7
+ return actual === filter.value;
8
+ case 'neq':
9
+ return actual !== filter.value;
10
+ case 'gt':
11
+ return Number(actual) > Number(filter.value);
12
+ case 'gte':
13
+ return Number(actual) >= Number(filter.value);
14
+ case 'lt':
15
+ return Number(actual) < Number(filter.value);
16
+ case 'lte':
17
+ return Number(actual) <= Number(filter.value);
18
+ case 'in':
19
+ return Array.isArray(filter.value) && filter.value.includes(actual);
20
+ case 'notIn':
21
+ return Array.isArray(filter.value) && !filter.value.includes(actual);
22
+ case 'between':
23
+ return Array.isArray(filter.value)
24
+ && filter.value.length === 2
25
+ && Number(actual) >= Number(filter.value[0])
26
+ && Number(actual) <= Number(filter.value[1]);
27
+ case 'like':
28
+ return typeof actual === 'string'
29
+ && typeof filter.value === 'string'
30
+ && actual.includes(filter.value.replaceAll('%', ''));
31
+ default:
32
+ return false;
33
+ }
34
+ }
35
+ function applyFilters(rows, filters) {
36
+ return rows.filter((row) => filters.every((filter) => compareFilter(valueForField(row, filter.field), filter)));
37
+ }
38
+ function applyTenant(rows, tenant) {
39
+ if (!tenant) {
40
+ return rows;
41
+ }
42
+ if (tenant.operator === 'in') {
43
+ return rows.filter((row) => tenant.value.includes(String(row[tenant.field])));
44
+ }
45
+ return rows.filter((row) => row[tenant.field] === tenant.value);
46
+ }
47
+ function periodForValue(value, grain) {
48
+ const date = new Date(String(value));
49
+ if (Number.isNaN(date.getTime())) {
50
+ return String(value);
51
+ }
52
+ if (grain.unit === 'year') {
53
+ return `${date.getUTCFullYear()}-01-01`;
54
+ }
55
+ if (grain.unit === 'quarter') {
56
+ const quarterStartMonth = Math.floor(date.getUTCMonth() / 3) * 3;
57
+ return new Date(Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1)).toISOString().slice(0, 10);
58
+ }
59
+ if (grain.unit === 'month') {
60
+ return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1)).toISOString().slice(0, 10);
61
+ }
62
+ if (grain.unit === 'week') {
63
+ const day = date.getUTCDay();
64
+ const weekStart = grain.weekStart ?? 1;
65
+ const diff = (day - weekStart + 7) % 7;
66
+ const start = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() - diff));
67
+ return start.toISOString().slice(0, 10);
68
+ }
69
+ return date.toISOString().slice(0, 10);
70
+ }
71
+ function groupKey(row, plan) {
72
+ const parts = plan.dimensions.map((dimension) => row[dimension.field]);
73
+ if (plan.grain) {
74
+ parts.unshift(periodForValue(row[plan.grain.field], plan.grain));
75
+ }
76
+ return JSON.stringify(parts);
77
+ }
78
+ function aggregateRows(rows, aggregation) {
79
+ const filteredRows = applyFilters(rows, aggregation.filters ?? []);
80
+ const values = filteredRows.map((row) => row[aggregation.field]);
81
+ switch (aggregation.aggregation) {
82
+ case 'sum':
83
+ return values.reduce((total, value) => total + Number(value ?? 0), 0);
84
+ case 'count':
85
+ return filteredRows.length;
86
+ case 'countDistinct':
87
+ return new Set(values).size;
88
+ case 'avg':
89
+ return values.length === 0
90
+ ? 0
91
+ : values.reduce((total, value) => total + Number(value ?? 0), 0) / values.length;
92
+ case 'min':
93
+ return Math.min(...values.map((value) => Number(value)));
94
+ case 'max':
95
+ return Math.max(...values.map((value) => Number(value)));
96
+ default:
97
+ return 0;
98
+ }
99
+ }
100
+ function evaluateExpression(expression, row) {
101
+ switch (expression.kind) {
102
+ case 'ref':
103
+ return row[expression.name];
104
+ case 'literal':
105
+ return expression.value;
106
+ case 'binary': {
107
+ const left = Number(evaluateExpression(expression.left, row));
108
+ const right = Number(evaluateExpression(expression.right, row));
109
+ if (expression.operator === 'add')
110
+ return left + right;
111
+ if (expression.operator === 'subtract')
112
+ return left - right;
113
+ if (expression.operator === 'multiply')
114
+ return left * right;
115
+ return right === 0 ? null : left / right;
116
+ }
117
+ case 'function': {
118
+ const [first, second] = expression.args.map((arg) => evaluateExpression(arg, row));
119
+ if (expression.name === 'nullIfZero')
120
+ return Number(first) === 0 ? null : first;
121
+ if (expression.name === 'coalesce')
122
+ return first == null ? second : first;
123
+ if (expression.name === 'round') {
124
+ const decimals = Number(second ?? 0);
125
+ const factor = 10 ** decimals;
126
+ return Math.round(Number(first) * factor) / factor;
127
+ }
128
+ if (expression.name === 'floor')
129
+ return Math.floor(Number(first));
130
+ return Math.ceil(Number(first));
131
+ }
132
+ default:
133
+ return undefined;
134
+ }
135
+ }
136
+ function compareRows(orderBy) {
137
+ return (a, b) => {
138
+ for (const order of orderBy) {
139
+ const av = a[order.field];
140
+ const bv = b[order.field];
141
+ if (av === bv)
142
+ continue;
143
+ const result = av > bv ? 1 : -1;
144
+ return order.direction === 'desc' ? -result : result;
145
+ }
146
+ return 0;
147
+ };
148
+ }
149
+ function applyOrderLimitOffset(rows, plan) {
150
+ let result = [...rows];
151
+ if (plan.orderBy?.length) {
152
+ result = result.sort(compareRows(plan.orderBy));
153
+ }
154
+ if (plan.offset != null) {
155
+ result = result.slice(plan.offset);
156
+ }
157
+ if (plan.limit != null) {
158
+ result = result.slice(0, plan.limit);
159
+ }
160
+ return result;
161
+ }
162
+ export function createInMemoryBackend(tables) {
163
+ function executeAggregate(plan) {
164
+ const table = tables[plan.source] ?? [];
165
+ const filteredRows = applyFilters(applyTenant(table, plan.tenant), plan.filters);
166
+ const groups = new Map();
167
+ for (const row of filteredRows) {
168
+ const key = groupKey(row, plan);
169
+ groups.set(key, [...(groups.get(key) ?? []), row]);
170
+ }
171
+ if (groups.size === 0 && plan.dimensions.length === 0 && !plan.grain) {
172
+ groups.set('[]', []);
173
+ }
174
+ const output = Array.from(groups.values()).map((rows) => {
175
+ const first = rows[0] ?? {};
176
+ const record = {};
177
+ if (plan.grain) {
178
+ record[plan.grain.output] = periodForValue(first[plan.grain.field], plan.grain);
179
+ }
180
+ for (const dimension of plan.dimensions) {
181
+ record[dimension.name] = first[dimension.field];
182
+ }
183
+ for (const aggregation of plan.aggregations) {
184
+ record[aggregation.name] = aggregateRows(rows, aggregation);
185
+ }
186
+ return record;
187
+ });
188
+ return applyOrderLimitOffset(output, plan);
189
+ }
190
+ async function execute(plan) {
191
+ const start = Date.now();
192
+ let data;
193
+ if (plan.kind === 'aggregate') {
194
+ data = executeAggregate(plan);
195
+ }
196
+ else {
197
+ const input = (await execute(plan.input)).data;
198
+ data = input.map((row) => {
199
+ const next = {};
200
+ if (plan.input.kind === 'aggregate') {
201
+ if (plan.input.grain) {
202
+ next[plan.input.grain.output] = row[plan.input.grain.output];
203
+ }
204
+ for (const dimension of plan.input.dimensions) {
205
+ next[dimension.name] = row[dimension.name];
206
+ }
207
+ }
208
+ for (const metric of plan.metrics) {
209
+ next[metric.name] = evaluateExpression(metric.expression, row);
210
+ }
211
+ return next;
212
+ });
213
+ data = applyOrderLimitOffset(data, plan);
214
+ }
215
+ return {
216
+ data: data,
217
+ meta: { timingMs: Date.now() - start },
218
+ };
219
+ }
220
+ return { execute };
221
+ }
package/dist/index.d.ts CHANGED
@@ -6,13 +6,15 @@ export { sum, count, countDistinct, avg, min, max } from './aggregations.js';
6
6
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
7
7
  export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
8
8
  export { createDatasetRegistry } from './registry.js';
9
- export { MetricExecutor } from './executor.js';
10
- export type { MetricExecutorOptions } from './executor.js';
9
+ export { createDatasetClient } from './executor.js';
10
+ export type { DatasetClient, CreateDatasetClientOptions } from './executor.js';
11
+ export { createInMemoryBackend } from './in-memory-backend.js';
12
+ export type { InMemoryTable, InMemoryTables } from './in-memory-backend.js';
13
+ export type { PlanNode, SemanticBackend, SemanticBackendResult, SemanticExpression, SemanticAggregationPlan, SemanticDimensionPlan, SemanticGrainPlan, } from './semantic-plan.js';
11
14
  export type { ValidationResult } from './validation.js';
12
15
  export { validateFilterValue, matchesFieldType } from './validation.js';
13
16
  export type { QueryBuilderLike, QueryBuilderFactoryLike } from './query-builder-protocol.js';
14
17
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
15
18
  export { GRAIN_FUNCTIONS } from './constants.js';
16
- export { resolveDimensionExpression, resolveFilterField, buildDimensionSelectionPlan, applyAggregationSpec, applyMeasureDefinition, appendOrderLimitOffset, resolveTenantFilterColumn, } from './query-planner.js';
17
- export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, MetricResultMeta, MetricResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetQueryConfig, DatasetQueryContract, DatasetQueryRef, DatasetLimits, DatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, } from './types.js';
19
+ export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetLimits, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetMeasureNames, DatasetOrderableNames, DatasetQueryFor, DatasetRow, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricResultFor, } from './types.js';
18
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,EACL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAC/B,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,KAAK,EAAE,IAAI,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAChC,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,KAAK,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAG7F,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,EACL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAC/B,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,KAAK,EAAE,IAAI,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAChC,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,KAAK,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAG7F,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -14,12 +14,11 @@ export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ce
14
14
  export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
15
15
  // Registry
16
16
  export { createDatasetRegistry } from './registry.js';
17
- // Executor
18
- export { MetricExecutor } from './executor.js';
17
+ // Dataset client
18
+ export { createDatasetClient } from './executor.js';
19
+ export { createInMemoryBackend } from './in-memory-backend.js';
19
20
  export { validateFilterValue, matchesFieldType } from './validation.js';
20
21
  // SQL utilities
21
22
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
22
23
  // Constants
23
24
  export { GRAIN_FUNCTIONS } from './constants.js';
24
- // Query planning helpers
25
- export { resolveDimensionExpression, resolveFilterField, buildDimensionSelectionPlan, applyAggregationSpec, applyMeasureDefinition, appendOrderLimitOffset, resolveTenantFilterColumn, } from './query-planner.js';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal APIs for @hypequery/serve package only.
3
+ *
4
+ * These exports are NOT part of the public API and should not be used
5
+ * by end users. They are implementation details that the serve package
6
+ * needs to create endpoints.
7
+ *
8
+ * DO NOT import from this file in user code!
9
+ */
10
+ export { createDatasetClient, DatasetClientImpl, MetricQueryEngine } from './executor.js';
11
+ export type { DatasetClient, CreateDatasetClientOptions, MetricQueryEngineOptions } from './executor.js';
12
+ export { createInMemoryBackend } from './in-memory-backend.js';
13
+ export type { InMemoryTable, InMemoryTables } from './in-memory-backend.js';
14
+ export type { PlanNode, SemanticBackend, SemanticBackendResult, SemanticExpression, SemanticAggregationPlan, SemanticDimensionPlan, SemanticGrainPlan, } from './semantic-plan.js';
15
+ export type { QueryBuilderLike, QueryBuilderFactoryLike } from './query-builder-protocol.js';
16
+ export type { ValidationResult } from './validation.js';
17
+ export { validateFilterValue, matchesFieldType } from './validation.js';
18
+ export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
19
+ export { runDatasetQuery, buildDatasetQueryBuilder, validateDatasetQuery } from './dataset-query.js';
20
+ export type { DatasetQueryExecutionOptions } from './dataset-query.js';
21
+ export { GRAIN_FUNCTIONS } from './constants.js';
22
+ export type { AnyDatasetInstance, DatasetQuery, DatasetQueryResult, } from './types.js';
23
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC1F,YAAY,EAAE,aAAa,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AAGrC,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAGvE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Internal APIs for @hypequery/serve package only.
3
+ *
4
+ * These exports are NOT part of the public API and should not be used
5
+ * by end users. They are implementation details that the serve package
6
+ * needs to create endpoints.
7
+ *
8
+ * DO NOT import from this file in user code!
9
+ */
10
+ // Dataset client internals - used by serve to create metric/dataset endpoints
11
+ export { createDatasetClient, DatasetClientImpl, MetricQueryEngine } from './executor.js';
12
+ export { createInMemoryBackend } from './in-memory-backend.js';
13
+ export { validateFilterValue, matchesFieldType } from './validation.js';
14
+ // SQL utilities - used by serve for SQL generation
15
+ export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
16
+ // Dataset query execution - used by serve for dataset endpoints
17
+ export { runDatasetQuery, buildDatasetQueryBuilder, validateDatasetQuery } from './dataset-query.js';
18
+ // Constants - used by serve
19
+ export { GRAIN_FUNCTIONS } from './constants.js';
@@ -1 +1 @@
1
- {"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAsB,MAAM,YAAY,CAAC;AAaxF,eAAO,MAAM,OAAO;0BAVH,MAAM,SAAS,cAAc,KAAG,iBAAiB;4BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;oCAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;CAiBxD,CAAC"}
1
+ {"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAsB,MAAM,YAAY,CAAC;AAcxF,eAAO,MAAM,OAAO;0BAXH,MAAM,SAAS,cAAc,KAAG,iBAAiB;4BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;oCAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;CAkBxD,CAAC"}
package/dist/measure.js CHANGED
@@ -6,6 +6,7 @@ function createMeasureHelper(aggregation) {
6
6
  sql: opts?.sql,
7
7
  label: opts?.label,
8
8
  description: opts?.description,
9
+ filters: opts?.filters,
9
10
  });
10
11
  }
11
12
  export const measure = {
@@ -2,7 +2,7 @@
2
2
  * Duck-typed protocol interfaces for query builders.
3
3
  *
4
4
  * These interfaces define the minimal contract that a query builder must satisfy
5
- * to work with the MetricExecutor. The @hypequery/clickhouse `createQueryBuilder`
5
+ * to work with the semantic dataset client. The @hypequery/clickhouse `createQueryBuilder`
6
6
  * return value satisfies `QueryBuilderFactoryLike` structurally — no explicit
7
7
  * `implements` is needed.
8
8
  *
@@ -26,7 +26,7 @@ export interface QueryBuilderLike {
26
26
  sql: string;
27
27
  parameters: unknown[];
28
28
  };
29
- execute(): Promise<Record<string, unknown>[]>;
29
+ execute<T = Record<string, unknown>>(): Promise<T[]>;
30
30
  }
31
31
  /** A query builder factory (what `createQueryBuilder(config)` returns). */
32
32
  export interface QueryBuilderFactoryLike {
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder-protocol.d.ts","sourceRoot":"","sources":["../src/query-builder-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAGrD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAChE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAG1E,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAGtD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,gBAAgB,CAAC;IACtE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGxC,eAAe,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAC1D,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CAC/C;AAED,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACtF"}
1
+ {"version":3,"file":"query-builder-protocol.d.ts","sourceRoot":"","sources":["../src/query-builder-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAGrD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAChE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAG1E,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAGtD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,gBAAgB,CAAC;IACtE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGxC,eAAe,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAC1D,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACtD;AAED,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACtF"}
@@ -2,7 +2,7 @@
2
2
  * Duck-typed protocol interfaces for query builders.
3
3
  *
4
4
  * These interfaces define the minimal contract that a query builder must satisfy
5
- * to work with the MetricExecutor. The @hypequery/clickhouse `createQueryBuilder`
5
+ * to work with the semantic dataset client. The @hypequery/clickhouse `createQueryBuilder`
6
6
  * return value satisfies `QueryBuilderFactoryLike` structurally — no explicit
7
7
  * `implements` is needed.
8
8
  *
@@ -1,16 +1,16 @@
1
1
  import type { MetricFilter, MetricOrderBy } from './types.js';
2
- export declare function eq<TField extends string>(field: TField, value: unknown): MetricFilter;
3
- export declare function neq<TField extends string>(field: TField, value: unknown): MetricFilter;
4
- export declare function gt<TField extends string>(field: TField, value: unknown): MetricFilter;
5
- export declare function gte<TField extends string>(field: TField, value: unknown): MetricFilter;
6
- export declare function lt<TField extends string>(field: TField, value: unknown): MetricFilter;
7
- export declare function lte<TField extends string>(field: TField, value: unknown): MetricFilter;
8
- export declare function inList<TField extends string>(field: TField, value: unknown[]): MetricFilter;
9
- export declare function notInList<TField extends string>(field: TField, value: unknown[]): MetricFilter;
10
- export declare function between<TField extends string>(field: TField, lower: unknown, upper: unknown): MetricFilter;
11
- export declare function like<TField extends string>(field: TField, value: string): MetricFilter;
12
- export declare function asc<TField extends string>(field: TField): MetricOrderBy;
13
- export declare function desc<TField extends string>(field: TField): MetricOrderBy;
2
+ export declare function eq<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
3
+ export declare function neq<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
4
+ export declare function gt<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
5
+ export declare function gte<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
6
+ export declare function lt<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
7
+ export declare function lte<const TField extends string, const TValue>(field: TField, value: TValue): MetricFilter<TField, TValue>;
8
+ export declare function inList<const TField extends string, const TValue>(field: TField, value: TValue[]): MetricFilter<TField, TValue[]>;
9
+ export declare function notInList<const TField extends string, const TValue>(field: TField, value: TValue[]): MetricFilter<TField, TValue[]>;
10
+ export declare function between<const TField extends string, const TLower, const TUpper>(field: TField, lower: TLower, upper: TUpper): MetricFilter<TField, [TLower, TUpper]>;
11
+ export declare function like<const TField extends string>(field: TField, value: string): MetricFilter<TField, string>;
12
+ export declare function asc<const TField extends string>(field: TField): MetricOrderBy<TField>;
13
+ export declare function desc<const TField extends string>(field: TField): MetricOrderBy<TField>;
14
14
  export declare const filter: {
15
15
  readonly eq: typeof eq;
16
16
  readonly neq: typeof neq;
@@ -1 +1 @@
1
- {"version":3,"file":"query-helpers.d.ts","sourceRoot":"","sources":["../src/query-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAU9D,wBAAgB,EAAE,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAErF;AAED,wBAAgB,GAAG,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAEtF;AAED,wBAAgB,EAAE,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAErF;AAED,wBAAgB,GAAG,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAEtF;AAED,wBAAgB,EAAE,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAErF;AAED,wBAAgB,GAAG,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAEtF;AAED,wBAAgB,MAAM,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,YAAY,CAE3F;AAED,wBAAgB,SAAS,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,YAAY,CAE9F;AAED,wBAAgB,OAAO,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,CAE1G;AAED,wBAAgB,IAAI,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAEtF;AAED,wBAAgB,GAAG,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAEvE;AAED,wBAAgB,IAAI,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAExE;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;CAWT,CAAC;AAEX,eAAO,MAAM,KAAK;;;CAGR,CAAC"}
1
+ {"version":3,"file":"query-helpers.d.ts","sourceRoot":"","sources":["../src/query-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAU9D,wBAAgB,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAExH;AAED,wBAAgB,GAAG,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzH;AAED,wBAAgB,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAExH;AAED,wBAAgB,GAAG,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzH;AAED,wBAAgB,EAAE,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAExH;AAED,wBAAgB,GAAG,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzH;AAED,wBAAgB,MAAM,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAEhI;AAED,wBAAgB,SAAS,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAEnI;AAED,wBAAgB,OAAO,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAEpK;AAED,wBAAgB,IAAI,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAE5G;AAED,wBAAgB,GAAG,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAErF;AAED,wBAAgB,IAAI,CAAC,KAAK,CAAC,MAAM,SAAS,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAEtF;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;CAWT,CAAC;AAEX,eAAO,MAAM,KAAK;;;CAGR,CAAC"}
@@ -1,13 +1,15 @@
1
- import type { AggregationSpec, DatasetInstance, ExecutionContext, MeasureDefinition, MetricOrderBy, TimeGrain } from "./types.js";
1
+ import type { AggregationSpec, AnyDatasetInstance, ExecutionContext, MeasureDefinition, MetricOrderBy, TimeGrain } from "./types.js";
2
2
  import type { QueryBuilderLike } from "./query-builder-protocol.js";
3
- export declare function resolveDimensionExpression(ds: DatasetInstance, dimensionName: string): string;
4
- export declare function resolveFilterField(ds: DatasetInstance, filterField: string): string;
5
- export declare function buildDimensionSelectionPlan(ds: DatasetInstance, dimensions: string[], grain: TimeGrain | undefined): {
3
+ type DatasetShape = AnyDatasetInstance;
4
+ export declare function resolveDimensionExpression(ds: DatasetShape, dimensionName: string): string;
5
+ export declare function resolveFilterField(ds: DatasetShape, filterField: string): string;
6
+ export declare function buildDimensionSelectionPlan(ds: DatasetShape, dimensions: string[], grain: TimeGrain | undefined): {
6
7
  selectParts: string[];
7
8
  groupByParts: string[];
8
9
  };
9
- export declare function applyAggregationSpec(qb: QueryBuilderLike, ds: DatasetInstance, spec: AggregationSpec, alias: string): QueryBuilderLike;
10
- export declare function applyMeasureDefinition(qb: QueryBuilderLike, ds: DatasetInstance, name: string, definition: MeasureDefinition): QueryBuilderLike;
10
+ export declare function applyAggregationSpec(qb: QueryBuilderLike, ds: DatasetShape, spec: AggregationSpec, alias: string): QueryBuilderLike;
11
+ export declare function applyMeasureDefinition(qb: QueryBuilderLike, ds: DatasetShape, name: string, definition: MeasureDefinition): QueryBuilderLike;
11
12
  export declare function appendOrderLimitOffset(qb: QueryBuilderLike, orderBy: MetricOrderBy[] | undefined, grain: TimeGrain | undefined, limit?: number, offset?: number): QueryBuilderLike;
12
- export declare function resolveTenantFilterColumn(_ds: DatasetInstance, context?: ExecutionContext): string | undefined;
13
+ export declare function resolveTenantFilterColumn(ds: DatasetShape, context?: ExecutionContext): string | undefined;
14
+ export {};
13
15
  //# sourceMappingURL=query-planner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-planner.d.ts","sourceRoot":"","sources":["../src/query-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,eAAe,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,CAGR;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,eAAe,EACnB,WAAW,EAAE,MAAM,GAClB,MAAM,CAGR;AAED,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,SAAS,GAAG,SAAS,GAC3B;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAqBnD;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,MAAM,GACZ,gBAAgB,CAmBlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,iBAAiB,GAC5B,gBAAgB,CAmBlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,aAAa,EAAE,GAAG,SAAS,EACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,gBAAgB,CAiBlB;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,eAAe,EACpB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,GAAG,SAAS,CAEpB"}
1
+ {"version":3,"file":"query-planner.d.ts","sourceRoot":"","sources":["../src/query-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAKpE,KAAK,YAAY,GAAG,kBAAkB,CAAC;AAMvC,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,YAAY,EAChB,aAAa,EAAE,MAAM,GACpB,MAAM,CAGR;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,YAAY,EAChB,WAAW,EAAE,MAAM,GAClB,MAAM,CAGR;AAED,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,YAAY,EAChB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,SAAS,GAAG,SAAS,GAC3B;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAwBnD;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,MAAM,GACZ,gBAAgB,CAuBlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,iBAAiB,GAC5B,gBAAgB,CA6BlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,aAAa,EAAE,GAAG,SAAS,EACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,gBAAgB,CAiBlB;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,YAAY,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,GAAG,SAAS,CAMpB"}
@@ -1,4 +1,9 @@
1
1
  import { GRAIN_FUNCTIONS } from "./constants.js";
2
+ import { applyFilteredAggregationExpression } from './utils/filtered-aggregation-sql.js';
3
+ import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
4
+ function toOrderDirection(direction) {
5
+ return direction === 'asc' ? 'ASC' : 'DESC';
6
+ }
2
7
  export function resolveDimensionExpression(ds, dimensionName) {
3
8
  const definition = ds.dimensions[dimensionName];
4
9
  return definition?.sql ?? definition?.column ?? dimensionName;
@@ -9,11 +14,14 @@ export function resolveFilterField(ds, filterField) {
9
14
  }
10
15
  export function buildDimensionSelectionPlan(ds, dimensions, grain) {
11
16
  const selectParts = [];
12
- const groupByParts = [];
17
+ const groupByParts = new Set();
13
18
  if (grain) {
14
19
  const fn = GRAIN_FUNCTIONS[grain];
20
+ if (!fn) {
21
+ throw new Error(`Unsupported time grain "${grain}".`);
22
+ }
15
23
  selectParts.push(`${fn}(${ds.timeKey}) AS period`);
16
- groupByParts.push("period");
24
+ groupByParts.add("period");
17
25
  }
18
26
  for (const dimensionName of dimensions) {
19
27
  const expression = resolveDimensionExpression(ds, dimensionName);
@@ -23,12 +31,12 @@ export function buildDimensionSelectionPlan(ds, dimensions, grain) {
23
31
  else {
24
32
  selectParts.push(`${expression} AS ${dimensionName}`);
25
33
  }
26
- groupByParts.push(dimensionName);
34
+ groupByParts.add(dimensionName);
27
35
  }
28
- return { selectParts, groupByParts };
36
+ return { selectParts, groupByParts: Array.from(groupByParts) };
29
37
  }
30
38
  export function applyAggregationSpec(qb, ds, spec, alias) {
31
- const fieldOrExpr = resolveDimensionExpression(ds, spec.field);
39
+ const fieldOrExpr = applyFilteredAggregationExpression(ds, spec, spec.sql ?? resolveDimensionExpression(ds, spec.field));
32
40
  switch (spec.aggregation) {
33
41
  case "sum":
34
42
  return qb.sum(fieldOrExpr, alias);
@@ -47,7 +55,13 @@ export function applyAggregationSpec(qb, ds, spec, alias) {
47
55
  }
48
56
  }
49
57
  export function applyMeasureDefinition(qb, ds, name, definition) {
50
- const fieldOrExpr = definition.sql ?? resolveDimensionExpression(ds, definition.field);
58
+ const baseFieldOrExpr = definition.sql ?? resolveDimensionExpression(ds, definition.field);
59
+ const fieldOrExpr = applyFilteredAggregationExpression(ds, {
60
+ __type: 'aggregation_spec',
61
+ aggregation: definition.aggregation,
62
+ field: definition.field,
63
+ filters: definition.filters,
64
+ }, baseFieldOrExpr);
51
65
  switch (definition.aggregation) {
52
66
  case "sum":
53
67
  return qb.sum(fieldOrExpr, name);
@@ -68,7 +82,7 @@ export function applyMeasureDefinition(qb, ds, name, definition) {
68
82
  export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset) {
69
83
  if (orderBy && orderBy.length > 0) {
70
84
  for (const order of orderBy) {
71
- qb = qb.orderBy(order.field, order.direction.toUpperCase());
85
+ qb = qb.orderBy(order.field, toOrderDirection(order.direction));
72
86
  }
73
87
  }
74
88
  else if (grain) {
@@ -82,6 +96,9 @@ export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset) {
82
96
  }
83
97
  return qb;
84
98
  }
85
- export function resolveTenantFilterColumn(_ds, context) {
86
- return context?.runtime?.tenant?.column;
99
+ export function resolveTenantFilterColumn(ds, context) {
100
+ if (!getRuntimeTenantPredicate(context)) {
101
+ return undefined;
102
+ }
103
+ return ds.tenantKey;
87
104
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * DatasetRegistry — runtime registry of defined datasets.
3
3
  *
4
- * Used by MetricExecutor and serve() to discover datasets at startup.
4
+ * Used by serve() and semantic clients to discover datasets at startup.
5
5
  */
6
6
  import type { DatasetRegistryInstance } from './types.js';
7
7
  export declare function createDatasetRegistry(): DatasetRegistryInstance;
package/dist/registry.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * DatasetRegistry — runtime registry of defined datasets.
3
3
  *
4
- * Used by MetricExecutor and serve() to discover datasets at startup.
4
+ * Used by serve() and semantic clients to discover datasets at startup.
5
5
  */
6
6
  export function createDatasetRegistry() {
7
7
  const datasets = new Map();
@@ -2,7 +2,7 @@
2
2
  * Relationship helpers for dataset definitions.
3
3
  *
4
4
  * These helpers currently define semantic model metadata only. The shipped
5
- * executor does not yet resolve relationship paths into joined dataset queries
5
+ * semantic client does not yet resolve relationship paths into joined dataset queries
6
6
  * or cross-dataset metrics.
7
7
  *
8
8
  * @example
@@ -2,7 +2,7 @@
2
2
  * Relationship helpers for dataset definitions.
3
3
  *
4
4
  * These helpers currently define semantic model metadata only. The shipped
5
- * executor does not yet resolve relationship paths into joined dataset queries
5
+ * semantic client does not yet resolve relationship paths into joined dataset queries
6
6
  * or cross-dataset metrics.
7
7
  *
8
8
  * @example