@hypequery/datasets 0.21.0 → 0.23.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 (174) hide show
  1. package/README.md +6 -0
  2. package/dist/api.type-test.js +7 -0
  3. package/dist/cache/protocol-cache-keys.d.ts.map +1 -1
  4. package/dist/cache/protocol-cache-keys.js +5 -0
  5. package/dist/cache/query-signature.d.ts.map +1 -1
  6. package/dist/cache/query-signature.js +9 -0
  7. package/dist/catalog.d.ts +12 -0
  8. package/dist/catalog.d.ts.map +1 -1
  9. package/dist/catalog.js +14 -1
  10. package/dist/constants.d.ts +12 -1
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +24 -0
  13. package/dist/contract.d.ts +4 -1
  14. package/dist/contract.d.ts.map +1 -1
  15. package/dist/contract.js +4 -0
  16. package/dist/dataset-compilation.d.ts +50 -0
  17. package/dist/dataset-compilation.d.ts.map +1 -0
  18. package/dist/dataset-compilation.js +1 -0
  19. package/dist/dataset-query.d.ts +3 -3
  20. package/dist/dataset-query.d.ts.map +1 -1
  21. package/dist/dataset-query.js +7 -71
  22. package/dist/dataset-sql-dialect.d.ts +11 -0
  23. package/dist/dataset-sql-dialect.d.ts.map +1 -0
  24. package/dist/dataset-sql-dialect.js +1 -0
  25. package/dist/dataset.d.ts +3 -2
  26. package/dist/dataset.d.ts.map +1 -1
  27. package/dist/execution-capabilities.d.ts +28 -0
  28. package/dist/execution-capabilities.d.ts.map +1 -0
  29. package/dist/execution-capabilities.js +17 -0
  30. package/dist/execution-capabilities.json +13 -0
  31. package/dist/executor.d.ts +17 -38
  32. package/dist/executor.d.ts.map +1 -1
  33. package/dist/executor.js +40 -400
  34. package/dist/index.d.ts +10 -5
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4 -3
  37. package/dist/internal.d.ts +3 -0
  38. package/dist/internal.d.ts.map +1 -1
  39. package/dist/internal.js +2 -0
  40. package/dist/measure.d.ts +54 -17
  41. package/dist/measure.d.ts.map +1 -1
  42. package/dist/measure.js +3 -63
  43. package/dist/metric-query-engine.d.ts +29 -0
  44. package/dist/metric-query-engine.d.ts.map +1 -0
  45. package/dist/metric-query-engine.js +106 -0
  46. package/dist/portable-executor.d.ts +20 -6
  47. package/dist/portable-executor.d.ts.map +1 -1
  48. package/dist/portable-executor.js +29 -9
  49. package/dist/protocol-adapter.d.ts.map +1 -1
  50. package/dist/protocol-adapter.js +1 -0
  51. package/dist/protocol-rehydrate.d.ts.map +1 -1
  52. package/dist/protocol-rehydrate.js +9 -2
  53. package/dist/query-builder-protocol.d.ts +11 -0
  54. package/dist/query-builder-protocol.d.ts.map +1 -1
  55. package/dist/query-helpers.d.ts +10 -10
  56. package/dist/query-helpers.d.ts.map +1 -1
  57. package/dist/query-helpers.js +1 -3
  58. package/dist/query-planner.d.ts +7 -3
  59. package/dist/query-planner.d.ts.map +1 -1
  60. package/dist/query-planner.js +10 -12
  61. package/dist/relationship-check.d.ts +3 -2
  62. package/dist/relationship-check.d.ts.map +1 -1
  63. package/dist/relationship-check.js +8 -3
  64. package/dist/relationships.d.ts +6 -16
  65. package/dist/relationships.d.ts.map +1 -1
  66. package/dist/relationships.js +3 -12
  67. package/dist/semantic-planner.d.ts.map +1 -1
  68. package/dist/semantic-planner.js +4 -0
  69. package/dist/semantic-query-schema.d.ts +6 -0
  70. package/dist/semantic-query-schema.d.ts.map +1 -1
  71. package/dist/semantic-query-schema.js +31 -4
  72. package/dist/types.d.ts +67 -11
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/utils/agent-catalog-projection.d.ts +1 -0
  75. package/dist/utils/agent-catalog-projection.d.ts.map +1 -1
  76. package/dist/utils/agent-catalog-projection.js +2 -1
  77. package/dist/utils/base-measure-definition.d.ts +23 -0
  78. package/dist/utils/base-measure-definition.d.ts.map +1 -0
  79. package/dist/utils/base-measure-definition.js +65 -0
  80. package/dist/utils/build-dataset-query-builder.d.ts +5 -0
  81. package/dist/utils/build-dataset-query-builder.d.ts.map +1 -0
  82. package/dist/utils/build-dataset-query-builder.js +65 -0
  83. package/dist/utils/calendar-shift-sql.d.ts +18 -0
  84. package/dist/utils/calendar-shift-sql.d.ts.map +1 -0
  85. package/dist/utils/calendar-shift-sql.js +21 -0
  86. package/dist/utils/clickhouse-dataset-sql-dialect.d.ts +4 -0
  87. package/dist/utils/clickhouse-dataset-sql-dialect.d.ts.map +1 -0
  88. package/dist/utils/clickhouse-dataset-sql-dialect.js +6 -0
  89. package/dist/utils/compile-dataset-query.d.ts +10 -0
  90. package/dist/utils/compile-dataset-query.d.ts.map +1 -0
  91. package/dist/utils/compile-dataset-query.js +72 -0
  92. package/dist/utils/composite-time-measure-sql.d.ts.map +1 -1
  93. package/dist/utils/composite-time-measure-sql.js +2 -1
  94. package/dist/utils/dataset-definition-validation.d.ts.map +1 -1
  95. package/dist/utils/dataset-definition-validation.js +52 -2
  96. package/dist/utils/dataset-derived-query.d.ts +6 -2
  97. package/dist/utils/dataset-derived-query.d.ts.map +1 -1
  98. package/dist/utils/dataset-derived-query.js +28 -26
  99. package/dist/utils/dataset-filter-types.d.ts +28 -0
  100. package/dist/utils/dataset-filter-types.d.ts.map +1 -0
  101. package/dist/utils/dataset-filter-types.js +1 -0
  102. package/dist/utils/dataset-having.d.ts +21 -0
  103. package/dist/utils/dataset-having.d.ts.map +1 -0
  104. package/dist/utils/dataset-having.js +106 -0
  105. package/dist/utils/dataset-normalization.d.ts.map +1 -1
  106. package/dist/utils/dataset-normalization.js +5 -1
  107. package/dist/utils/dataset-query-validation.d.ts.map +1 -1
  108. package/dist/utils/dataset-query-validation.js +17 -3
  109. package/dist/utils/dataset-sql-dialect.d.ts +5 -0
  110. package/dist/utils/dataset-sql-dialect.d.ts.map +1 -0
  111. package/dist/utils/dataset-sql-dialect.js +5 -0
  112. package/dist/utils/dataset-target.d.ts +3 -0
  113. package/dist/utils/dataset-target.d.ts.map +1 -0
  114. package/dist/utils/dataset-target.js +3 -0
  115. package/dist/utils/filter-definition.d.ts +3 -0
  116. package/dist/utils/filter-definition.d.ts.map +1 -0
  117. package/dist/utils/filter-definition.js +3 -0
  118. package/dist/utils/metric-derived-query.d.ts +8 -0
  119. package/dist/utils/metric-derived-query.d.ts.map +1 -0
  120. package/dist/utils/metric-derived-query.js +106 -0
  121. package/dist/utils/metric-query-builder.d.ts +5 -0
  122. package/dist/utils/metric-query-builder.d.ts.map +1 -0
  123. package/dist/utils/metric-query-builder.js +50 -0
  124. package/dist/utils/metric-query-result.d.ts +10 -0
  125. package/dist/utils/metric-query-result.d.ts.map +1 -0
  126. package/dist/utils/metric-query-result.js +18 -0
  127. package/dist/utils/metric-query-validation.d.ts +6 -0
  128. package/dist/utils/metric-query-validation.d.ts.map +1 -0
  129. package/dist/utils/metric-query-validation.js +116 -0
  130. package/dist/utils/protocol-metric-expressions.d.ts +8 -0
  131. package/dist/utils/protocol-metric-expressions.d.ts.map +1 -1
  132. package/dist/utils/protocol-metric-expressions.js +23 -11
  133. package/dist/utils/relationship-builder-plan.d.ts +6 -2
  134. package/dist/utils/relationship-builder-plan.d.ts.map +1 -1
  135. package/dist/utils/relationship-builder-plan.js +24 -15
  136. package/dist/utils/relationship-definition.d.ts +6 -0
  137. package/dist/utils/relationship-definition.d.ts.map +1 -0
  138. package/dist/utils/relationship-definition.js +9 -0
  139. package/dist/utils/relationship-key-check.d.ts +4 -0
  140. package/dist/utils/relationship-key-check.d.ts.map +1 -1
  141. package/dist/utils/relationship-key-check.js +19 -7
  142. package/dist/utils/relationship-keys.d.ts +17 -0
  143. package/dist/utils/relationship-keys.d.ts.map +1 -0
  144. package/dist/utils/relationship-keys.js +63 -0
  145. package/dist/utils/relationship-measure-sql.d.ts +14 -0
  146. package/dist/utils/relationship-measure-sql.d.ts.map +1 -0
  147. package/dist/utils/relationship-measure-sql.js +44 -0
  148. package/dist/utils/relationship-measure-types.d.ts +36 -0
  149. package/dist/utils/relationship-measure-types.d.ts.map +1 -0
  150. package/dist/utils/relationship-measure-types.js +1 -0
  151. package/dist/utils/relationship-measures.d.ts +23 -0
  152. package/dist/utils/relationship-measures.d.ts.map +1 -0
  153. package/dist/utils/relationship-measures.js +62 -0
  154. package/dist/utils/relationship-validation.d.ts +1 -1
  155. package/dist/utils/relationship-validation.d.ts.map +1 -1
  156. package/dist/utils/relationship-validation.js +3 -5
  157. package/dist/utils/semantic-query-syntax.d.ts +6 -0
  158. package/dist/utils/semantic-query-syntax.d.ts.map +1 -0
  159. package/dist/utils/semantic-query-syntax.js +24 -0
  160. package/dist/utils/shift-measure-sql.d.ts.map +1 -1
  161. package/dist/utils/shift-measure-sql.js +10 -3
  162. package/dist/utils/snapshot-execution-context.d.ts +4 -0
  163. package/dist/utils/snapshot-execution-context.d.ts.map +1 -0
  164. package/dist/utils/snapshot-execution-context.js +16 -0
  165. package/dist/utils/time-measure-context-sql.d.ts.map +1 -1
  166. package/dist/utils/time-measure-context-sql.js +8 -2
  167. package/dist/utils/time-measure-dataset-sql.d.ts.map +1 -1
  168. package/dist/utils/time-measure-dataset-sql.js +3 -2
  169. package/dist/utils/time-measure-result-sql.d.ts.map +1 -1
  170. package/dist/utils/time-measure-result-sql.js +2 -1
  171. package/dist/utils/time-measure-source-sql.d.ts.map +1 -1
  172. package/dist/utils/time-measure-source-sql.js +8 -4
  173. package/dist/validation.js +1 -1
  174. package/package.json +10 -5
package/README.md CHANGED
@@ -102,6 +102,12 @@ Metric changes travel through the workflow your team already trusts: TypeScript,
102
102
  - [Relationships](https://hypequery.com/docs/datasets/relationships)
103
103
  - [MCP tool generation](https://hypequery.com/docs/datasets/tool-generation)
104
104
 
105
+ ## Contributing
106
+
107
+ For repository contributors, see the [implementation guide](./ARCHITECTURE.md)
108
+ for module boundaries and verification requirements, and the
109
+ [testing review](./TESTING_REVIEW.md) for coverage, CI gates, and remaining gaps.
110
+
105
111
  ## License
106
112
 
107
113
  Apache-2.0.
@@ -203,6 +203,13 @@ const builderFactory = {
203
203
  rawQuery: async () => [],
204
204
  };
205
205
  const analytics = createDatasetClient({ queryBuilder: builderFactory });
206
+ const _datasetCompilation = analytics.compileDataset(Orders, { measures: ['doubledRevenue'] });
207
+ // @ts-expect-error compilation accepts declared dataset measures only.
208
+ analytics.compileDataset(Orders, { measures: ['missing'] });
209
+ // @ts-expect-error compilation accepts declared dataset dimensions only.
210
+ analytics.compileDataset(Orders, { dimensions: ['missing'] });
211
+ // @ts-expect-error standalone metric handles are not dataset compilation targets.
212
+ analytics.compileDataset(Orders.metric('revenue', { measure: 'revenue' }));
206
213
  const explicitAnalytics = analytics;
207
214
  const datasetQuery = { dimensions: ['status'], measures: ['revenue'] };
208
215
  analytics.validate(revenueMetric, { dimensions: ['status'] }, runtimeContext);
@@ -1 +1 @@
1
- {"version":3,"file":"protocol-cache-keys.d.ts","sourceRoot":"","sources":["../../src/cache/protocol-cache-keys.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAIrB,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAInD,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAChC,WAAW,EAAE,OAAO,GACnB,wBAAwB,CAqC1B;AAkHD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,wBAAwB,EAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAcpB;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAgBpB"}
1
+ {"version":3,"file":"protocol-cache-keys.d.ts","sourceRoot":"","sources":["../../src/cache/protocol-cache-keys.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAIrB,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAInD,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAChC,WAAW,EAAE,OAAO,GACnB,wBAAwB,CAqC1B;AAkHD;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,wBAAwB,EAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAkBpB;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAgBpB"}
@@ -155,6 +155,11 @@ function definitionFor(settings, root, scope, query, metric) {
155
155
  * `query` must already carry its effective limit.
156
156
  */
157
157
  export function datasetCacheKey(settings, ds, query, context, scope) {
158
+ // RFC 0009's normalized query has no `having`, so no portable key can
159
+ // separate queries that differ only in their conditions. Run them uncached,
160
+ // as the Python SDK does, until the shared preimage covers `having`.
161
+ if (query.having !== undefined && query.having.length > 0)
162
+ return undefined;
158
163
  try {
159
164
  const wire = {
160
165
  kind: 'dataset',
@@ -1 +1 @@
1
- {"version":3,"file":"query-signature.d.ts","sourceRoot":"","sources":["../../src/cache/query-signature.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAGhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,CAAC;AAsF3B;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAoBR;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAoBR"}
1
+ {"version":3,"file":"query-signature.d.ts","sourceRoot":"","sources":["../../src/cache/query-signature.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAElB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAGhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,eAAe,EAAE,CAAC;AA8F3B;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAsBR;AAED,oDAAoD;AACpD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAoBR"}
@@ -21,6 +21,13 @@ function filterSignature(filters) {
21
21
  value: filter.value ?? null,
22
22
  }));
23
23
  }
24
+ function havingSignature(having) {
25
+ return having.map((condition) => ({
26
+ measure: condition.measure,
27
+ operator: condition.operator,
28
+ value: condition.value,
29
+ }));
30
+ }
24
31
  function orderBySignature(orderBy) {
25
32
  return (orderBy ?? []).map((order) => ({
26
33
  field: order.field,
@@ -88,6 +95,8 @@ export function buildDatasetQuerySignature(ds, query, context) {
88
95
  measures: query.measures ?? null,
89
96
  ...windowQuerySignature(ds, query),
90
97
  filters: filterSignature(query.filters),
98
+ // Omitted when absent so queries without conditions keep their existing keys.
99
+ ...(query.having?.length ? { having: havingSignature(query.having) } : {}),
91
100
  ...segmentSignature(ds, query.segments),
92
101
  orderBy: orderBySignature(query.orderBy),
93
102
  by: query.by ?? null,
package/dist/catalog.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { ProtocolExpression } from '@hypequery/protocol';
2
+ import type { RelationshipKey } from './types.js';
1
3
  import { type WindowCatalogMetadata } from './utils/window-catalog-metadata.js';
2
4
  import type { AnyDatasetInstance, DimensionDefinition, MeasureDefinition, MetricHandle, RelationshipDefinition, SemanticFilterDefinition, DatasetLimits, DatasetDefaults, DatasetFreshness, SemanticMetadata, TimeGrain } from './types.js';
3
5
  export interface DimensionCatalogEntry extends SemanticMetadata {
@@ -24,6 +26,11 @@ export interface MeasureCatalogEntry extends SemanticMetadata, WindowCatalogMeta
24
26
  approximate?: true;
25
27
  }
26
28
  export interface DerivedMeasureCatalogEntry extends SemanticMetadata, WindowCatalogMetadata {
29
+ uses?: {
30
+ alias: string;
31
+ measure: string;
32
+ }[];
33
+ expression?: ProtocolExpression;
27
34
  label?: string;
28
35
  description?: string;
29
36
  /** Present, as `true`, when any measure the formula uses is approximate. */
@@ -59,6 +66,7 @@ export interface RelationshipCatalogEntry {
59
66
  target: string;
60
67
  from: string;
61
68
  to: string;
69
+ keys?: readonly RelationshipKey[];
62
70
  queryable: boolean;
63
71
  fields: string[];
64
72
  /**
@@ -66,6 +74,8 @@ export interface RelationshipCatalogEntry {
66
74
  * supplied catalog that predates it still resolves, falling back to `fields`.
67
75
  */
68
76
  groupableFields?: string[];
77
+ /** Safe selectable base aggregates, keyed by qualified name. */
78
+ measures?: Record<string, MeasureCatalogEntry>;
69
79
  }
70
80
  export interface DatasetCatalog extends SemanticMetadata {
71
81
  name: string;
@@ -97,6 +107,8 @@ export type DatasetCatalogSource = AnyDatasetInstance & {
97
107
  };
98
108
  /** All queryable relationship field names (`<relationship>.<dimension>`) a catalog advertises. */
99
109
  export declare function getQueryableRelationshipFields(catalog: DatasetCatalog): string[];
110
+ /** Safe relationship aggregates advertised by a catalog. */
111
+ export declare function getQueryableRelationshipMeasures(catalog: DatasetCatalog): string[];
100
112
  /** The queryable relationship fields a catalog also allows as grouping keys. */
101
113
  export declare function getGroupableRelationshipFields(catalog: DatasetCatalog): string[];
102
114
  export declare function getDatasetCatalog(dataset: DatasetCatalogSource): DatasetCatalog;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
package/dist/catalog.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { derivedMeasureCatalogExpression } from './utils/protocol-metric-expressions.js';
2
+ import { listRelationshipMeasures } from './utils/relationship-measures.js';
1
3
  import { inheritedBaseMeasure } from './utils/measure-dependencies.js';
2
4
  import { windowCatalogMetadata } from './utils/window-catalog-metadata.js';
3
5
  import { splitDatasetMeasures } from './utils/dataset-measures.js';
@@ -62,14 +64,18 @@ function metricToCatalog(metric) {
62
64
  };
63
65
  }
64
66
  function relationshipToCatalog(name, relationship) {
67
+ const measures = Object.fromEntries(Object.entries(listRelationshipMeasures(name, relationship))
68
+ .map(([key, definition]) => [key, measureToCatalog(definition)]));
65
69
  return {
66
70
  kind: relationship.kind,
67
71
  target: relationship.target().name,
68
72
  from: relationship.from,
69
73
  to: relationship.to,
74
+ ...(relationship.keys ? { keys: relationship.keys.map(key => ({ ...key })) } : {}),
70
75
  queryable: relationship.kind !== 'hasMany',
71
76
  fields: listQueryableRelationshipFields(name, relationship),
72
77
  groupableFields: listGroupableRelationshipFields(name, relationship),
78
+ ...(Object.keys(measures).length ? { measures } : {}),
73
79
  };
74
80
  }
75
81
  /** All queryable relationship field names (`<relationship>.<dimension>`) a catalog advertises. */
@@ -78,6 +84,11 @@ export function getQueryableRelationshipFields(catalog) {
78
84
  .filter(relationship => relationship.queryable)
79
85
  .flatMap(relationship => relationship.fields);
80
86
  }
87
+ /** Safe relationship aggregates advertised by a catalog. */
88
+ export function getQueryableRelationshipMeasures(catalog) {
89
+ return Object.values(catalog.relationships).filter(relationship => relationship.queryable)
90
+ .flatMap(relationship => Object.keys(relationship.measures ?? {}));
91
+ }
81
92
  /** The queryable relationship fields a catalog also allows as grouping keys. */
82
93
  export function getGroupableRelationshipFields(catalog) {
83
94
  return Object.values(catalog.relationships)
@@ -129,6 +140,8 @@ export function getDatasetCatalog(dataset) {
129
140
  name,
130
141
  {
131
142
  ...snapshotSemanticMetadata(definition),
143
+ uses: Object.entries(definition.uses).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([alias, measure]) => ({ alias, measure })),
144
+ expression: derivedMeasureCatalogExpression(definition),
132
145
  ...(usesTimeMeasure(definition, dataset.measures) ? {
133
146
  requiresTimeRange: true,
134
147
  supportedGrains: measureSupportedGrains(dataset.measures, name, supportedGrains),
@@ -162,7 +175,7 @@ export function getDatasetCatalog(dataset) {
162
175
  ...measureNames,
163
176
  ...derivedMeasureNames,
164
177
  ...metricNames,
165
- ...Object.values(relationships).flatMap(relationship => relationship.fields),
178
+ ...Object.values(relationships).flatMap(relationship => [...relationship.fields, ...Object.keys(relationship.measures ?? {})]),
166
179
  ...(dataset.timeKey ? ['period'] : []),
167
180
  ],
168
181
  maxLimit,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared constants for semantic layer implementation.
3
3
  */
4
- import type { TimeGrain } from './types.js';
4
+ import type { MetricFilter, TimeGrain } from './types.js';
5
5
  /**
6
6
  * Maps time grain to ClickHouse date truncation functions.
7
7
  */
@@ -15,6 +15,17 @@ export declare const SUPPORTED_TIME_GRAINS: TimeGrain[];
15
15
  * The filter operators accepted by semantic dataset and metric inputs.
16
16
  */
17
17
  export declare const SEMANTIC_FILTER_OPERATORS: readonly ["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"];
18
+ /**
19
+ * Narrowing guard for a runtime-provided filter operator. Query builders accept
20
+ * operators that splice raw SQL (`inSubquery`, `inTable`), so anything outside
21
+ * the semantic set must never reach one.
22
+ */
23
+ export declare function isSemanticFilterOperator(operator: unknown): operator is MetricFilter['operator'];
24
+ /**
25
+ * Operators accepted by dataset `having` conditions. `like` is excluded:
26
+ * conditions compare aggregated numeric values.
27
+ */
28
+ export declare const SEMANTIC_HAVING_OPERATORS: readonly ["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between"];
18
29
  /**
19
30
  * Narrowing guard for a runtime-provided grain value.
20
31
  */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAmC,SAAS,EAAE,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAWkB,CAAC;AAEzD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAEvE"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAyB,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAmC,SAAS,EAAE,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAWkB,CAAC;AAIzD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,YAAY,CAAC,UAAU,CAAC,CAEhG;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,4EAUe,CAAC;AAEtD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAEvE"}
package/dist/constants.js CHANGED
@@ -33,6 +33,30 @@ export const SEMANTIC_FILTER_OPERATORS = [
33
33
  'between',
34
34
  'like',
35
35
  ];
36
+ const FILTER_OPERATORS = new Set(SEMANTIC_FILTER_OPERATORS);
37
+ /**
38
+ * Narrowing guard for a runtime-provided filter operator. Query builders accept
39
+ * operators that splice raw SQL (`inSubquery`, `inTable`), so anything outside
40
+ * the semantic set must never reach one.
41
+ */
42
+ export function isSemanticFilterOperator(operator) {
43
+ return typeof operator === 'string' && FILTER_OPERATORS.has(operator);
44
+ }
45
+ /**
46
+ * Operators accepted by dataset `having` conditions. `like` is excluded:
47
+ * conditions compare aggregated numeric values.
48
+ */
49
+ export const SEMANTIC_HAVING_OPERATORS = [
50
+ 'eq',
51
+ 'neq',
52
+ 'gt',
53
+ 'gte',
54
+ 'lt',
55
+ 'lte',
56
+ 'in',
57
+ 'notIn',
58
+ 'between',
59
+ ];
36
60
  /**
37
61
  * Narrowing guard for a runtime-provided grain value.
38
62
  */
@@ -1,5 +1,6 @@
1
+ import type { RelationshipKey } from './types.js';
1
2
  import { type WindowCatalogMetadata } from './utils/window-catalog-metadata.js';
2
- import { type DatasetCatalogSource, type DimensionCatalogEntry, type MeasureCatalogEntry, type SegmentCatalogEntry, type MetricCatalogEntry, type FilterCatalogEntry, type RelationshipCatalogEntry } from './catalog.js';
3
+ import { type DatasetCatalog, type DatasetCatalogSource, type DimensionCatalogEntry, type MeasureCatalogEntry, type SegmentCatalogEntry, type MetricCatalogEntry, type FilterCatalogEntry, type RelationshipCatalogEntry } from './catalog.js';
3
4
  import type { DatasetDefaults, DatasetFreshness, DatasetLimits, SemanticMetadata } from './types.js';
4
5
  /**
5
6
  * Version of the semantic contract format. Bump when the serialized shape
@@ -52,6 +53,7 @@ export interface ContractRelationship {
52
53
  target: string;
53
54
  from: string;
54
55
  to: string;
56
+ keys?: readonly RelationshipKey[];
55
57
  queryable: boolean;
56
58
  fields: string[];
57
59
  }
@@ -68,6 +70,7 @@ export interface ContractDataset extends SemanticMetadata {
68
70
  supportedGrains: string[];
69
71
  dimensions: Record<string, ContractDimension>;
70
72
  measures: Record<string, ContractMeasure>;
73
+ derivedMeasures?: DatasetCatalog['derivedMeasures'];
71
74
  metrics: Record<string, ContractMetric>;
72
75
  filters: Record<string, ContractFilter>;
73
76
  /** Named segments (label and description only); absent when none are declared. */
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
package/dist/contract.js CHANGED
@@ -56,6 +56,9 @@ function datasetToContract(catalog, includeSql) {
56
56
  supportedGrains: uniqueSorted(catalog.supportedGrains),
57
57
  dimensions: sortedRecord(Object.entries(catalog.dimensions).map(([name, entry]) => [name, dimensionToContract(entry, includeSql)])),
58
58
  measures: sortedRecord(Object.entries(catalog.measures).map(([name, entry]) => [name, measureToContract(entry, includeSql)])),
59
+ ...(catalog.derivedMeasures !== undefined ? {
60
+ derivedMeasures: sortedRecord(Object.entries(catalog.derivedMeasures)),
61
+ } : {}),
59
62
  metrics: sortedRecord(Object.entries(catalog.metrics).map(([name, entry]) => [name, metricToContract(entry)])),
60
63
  filters: sortedRecord(Object.entries(catalog.filters).map(([name, entry]) => [name, filterToContract(entry)])),
61
64
  ...(catalog.segments !== undefined ? {
@@ -138,6 +141,7 @@ function relationshipToContract(entry) {
138
141
  target: entry.target,
139
142
  from: entry.from,
140
143
  to: entry.to,
144
+ ...(entry.keys ? { keys: entry.keys.map(key => ({ ...key })) } : {}),
141
145
  queryable: entry.queryable,
142
146
  fields: uniqueSorted(entry.fields),
143
147
  };
@@ -0,0 +1,50 @@
1
+ import type { DatasetQuery } from './types.js';
2
+ /** Trusted compiler output. SQL may contain literals supplied by a custom builder. */
3
+ export interface DatasetCompiledStatement {
4
+ readonly sql: string;
5
+ readonly parameters: readonly unknown[];
6
+ }
7
+ /** Structural diagnostics: no SQL, physical columns, filter values or tenant IDs. */
8
+ export interface DatasetCompilationDescription {
9
+ readonly kind: 'dataset-compilation';
10
+ readonly version: 1;
11
+ readonly dataset: string;
12
+ readonly plan: 'aggregate' | 'derived' | 'time';
13
+ readonly dimensions: readonly string[];
14
+ readonly measures: readonly string[];
15
+ readonly measureDependencies: readonly string[];
16
+ readonly filters: readonly {
17
+ readonly field: string;
18
+ readonly operator: string;
19
+ }[];
20
+ /** Post-aggregation conditions, without their values. */
21
+ readonly having: readonly {
22
+ readonly measure: string;
23
+ readonly operator: string;
24
+ }[];
25
+ readonly segments: readonly string[];
26
+ readonly by?: string;
27
+ readonly timezone?: string;
28
+ readonly effectiveLimit?: number;
29
+ /** Includes the extra row used to determine pagination.hasMore. */
30
+ readonly executionLimit?: number;
31
+ readonly offset: number;
32
+ readonly parameterCount: number;
33
+ readonly preflightStatementCount: number;
34
+ }
35
+ /**
36
+ * Dataset-level envelope around the current query-builder output. This is not
37
+ * an RFC 0010 CompiledQuery: native named parameter binding remains an adapter
38
+ * responsibility. Use describe()/JSON serialization for structural diagnostics;
39
+ * inspect SQL and parameters only in an authorized, trusted debugger.
40
+ */
41
+ export interface DatasetCompilation extends DatasetCompiledStatement {
42
+ /** Normalized query, including its effective result limit and default measures. */
43
+ readonly query: Readonly<DatasetQuery>;
44
+ /** Statements executed before the result query, such as time-axis guards. */
45
+ readonly preflightStatements: readonly DatasetCompiledStatement[];
46
+ describe(): DatasetCompilationDescription;
47
+ /** JSON serialization deliberately omits trusted SQL, parameters and values. */
48
+ toJSON(): DatasetCompilationDescription;
49
+ }
50
+ //# sourceMappingURL=dataset-compilation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-compilation.d.ts","sourceRoot":"","sources":["../src/dataset-compilation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,sFAAsF;AACtF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;CACzC;AAED,qFAAqF;AACrF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;IAChD,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnF,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,mEAAmE;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAmB,SAAQ,wBAAwB;IAClE,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvC,6EAA6E;IAC7E,QAAQ,CAAC,mBAAmB,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAClE,QAAQ,IAAI,6BAA6B,CAAC;IAC1C,gFAAgF;IAChF,MAAM,IAAI,6BAA6B,CAAC;CACzC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import type { AnyDatasetInstance, DatasetQuery, DatasetQueryResult, ExecutionContext } from './types.js';
2
- import type { QueryBuilderFactoryLike, QueryBuilderLike } from './query-builder-protocol.js';
3
- import { type ValidationResult } from './validation.js';
2
+ import type { QueryBuilderFactoryLike } from './query-builder-protocol.js';
3
+ import type { ValidationResult } from './validation.js';
4
+ export { buildDatasetQueryBuilder } from './utils/build-dataset-query-builder.js';
4
5
  export interface DatasetQueryExecutionOptions {
5
6
  builderFactory: QueryBuilderFactoryLike;
6
7
  context?: ExecutionContext;
@@ -13,6 +14,5 @@ export interface DatasetQueryExecutionOptions {
13
14
  skipDefaultOrderBy?: boolean;
14
15
  }
15
16
  export declare function validateDatasetQuery(ds: AnyDatasetInstance, query: DatasetQuery, context?: ExecutionContext): ValidationResult;
16
- export declare function buildDatasetQueryBuilder(ds: AnyDatasetInstance, query: DatasetQuery, options: DatasetQueryExecutionOptions): QueryBuilderLike;
17
17
  export declare function runDatasetQuery(ds: AnyDatasetInstance, query: DatasetQuery, options: DatasetQueryExecutionOptions): Promise<DatasetQueryResult>;
18
18
  //# sourceMappingURL=dataset-query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-query.d.ts","sourceRoot":"","sources":["../src/dataset-query.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAS7F,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAgBxD,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,uBAAuB,CAAC;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,gBAAgB,CAElB;AAED,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,gBAAgB,CAyDlB;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CA0B7B"}
1
+ {"version":3,"file":"dataset-query.d.ts","sourceRoot":"","sources":["../src/dataset-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAElF,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,uBAAuB,CAAC;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,gBAAgB,CAElB;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAW7B"}
@@ -1,83 +1,19 @@
1
- import { queryTimeFilterSql } from './utils/query-timezone.js';
2
- import { selectedTimeMeasures } from './utils/time-query-measures.js';
3
- import { buildTimeMeasureDatasetSql } from './utils/time-measure-dataset-sql.js';
4
- import { baseMeasureNames, getBaseMeasure } from './utils/dataset-measures.js';
5
- import { appendOrderLimitOffset, applyMeasureDefinition, buildDimensionSelectionPlan, resolveDimensionExpression, resolveFilterField, resolveTenantFilterColumn, } from './query-planner.js';
6
1
  import { validateDatasetQueryInput } from './utils/dataset-query-validation.js';
7
- import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
8
- import { overfetchLimit } from './utils/pagination.js';
9
- import { applyRelationshipJoins, buildRelationshipBuilderContext, qualifyBaseColumn, } from './utils/relationship-builder-plan.js';
10
- import { hasSelectedDerivedMeasure, runDerivedDatasetQuery, } from './utils/dataset-derived-query.js';
2
+ import { prepareDatasetQuery } from './utils/compile-dataset-query.js';
11
3
  import { toDatasetQueryResult } from './utils/dataset-query-result.js';
12
- import { segmentFilters } from './utils/segments.js';
4
+ // Preserve the shipped builder helper while keeping compilation helpers focused.
5
+ export { buildDatasetQueryBuilder } from './utils/build-dataset-query-builder.js';
13
6
  export function validateDatasetQuery(ds, query, context) {
14
7
  return validateDatasetQueryInput(ds, query, context);
15
8
  }
16
- export function buildDatasetQueryBuilder(ds, query, options) {
17
- if (selectedTimeMeasures(ds, query).size) {
18
- throw new Error('A time-based dataset query needs the time-measure SQL planner; use createDatasetClient().toSQL().');
19
- }
20
- if (hasSelectedDerivedMeasure(ds, query)) {
21
- throw new Error('A derived dataset query needs the outer SQL projection; use createDatasetClient().toSQL().');
22
- }
23
- const validation = validateDatasetQuery(ds, query, options.context);
24
- if (!validation.valid) {
25
- throw new Error(`Invalid dataset query: ${validation.errors.join('; ')}`);
26
- }
27
- const joinCtx = buildRelationshipBuilderContext(ds, query, options.context);
28
- let qb = options.builderFactory.table(ds.source);
29
- qb = applyRelationshipJoins(qb, joinCtx);
30
- const { selectParts, groupByParts } = buildDimensionSelectionPlan(ds, query.dimensions ?? [], query.by, joinCtx, query.timezone);
31
- const measureNames = query.measures ?? baseMeasureNames(ds.measures);
32
- if (selectParts.length > 0) {
33
- qb = qb.select(selectParts);
34
- }
35
- for (const measureName of measureNames) {
36
- const definition = getBaseMeasure(ds.measures, measureName);
37
- if (!definition)
38
- throw new Error(`Measure "${measureName}" is not a base measure.`);
39
- qb = applyMeasureDefinition(qb, ds, measureName, definition, joinCtx);
40
- }
41
- if (groupByParts.length > 0) {
42
- qb = qb.groupBy(groupByParts);
43
- }
44
- const tenantColumn = resolveTenantFilterColumn(ds, options.context);
45
- const tenantPredicate = getRuntimeTenantPredicate(options.context);
46
- if (tenantPredicate && tenantColumn) {
47
- qb = qb.where(qualifyBaseColumn(joinCtx, tenantColumn), tenantPredicate.operator, tenantPredicate.value);
48
- }
49
- for (const filter of query.filters ?? []) {
50
- const resolvedField = resolveFilterField(ds, filter.field, joinCtx);
51
- qb = qb.where(queryTimeFilterSql(ds, filter.field, resolvedField, query.timezone), filter.operator, filter.value);
52
- }
53
- // Segments are author-defined, so they bypass the caller filter allow-list.
54
- for (const filter of segmentFilters(ds, query.segments)) {
55
- qb = qb.where(resolveDimensionExpression(ds, filter.field, joinCtx), filter.operator, filter.value);
56
- }
57
- return appendOrderLimitOffset(qb, query.orderBy, options.skipDefaultOrderBy ? undefined : query.by, options.executionLimit ?? query.limit, query.offset, joinCtx);
58
- }
59
9
  export async function runDatasetQuery(ds, query, options) {
60
- if (selectedTimeMeasures(ds, query).size) {
61
- const start = Date.now();
62
- const { sql, parameters, timeAxisSql } = buildTimeMeasureDatasetSql(ds, query, { ...options, executionLimit: overfetchLimit(query.limit) });
63
- await options.builderFactory.rawQuery(timeAxisSql, parameters, { abortSignal: options.context?.abortSignal });
64
- const rows = await options.builderFactory.rawQuery(sql, parameters, { abortSignal: options.context?.abortSignal });
65
- return toDatasetQueryResult(rows, { dataset: ds, query, sql, timingMs: Date.now() - start, context: options.context });
66
- }
67
- if (hasSelectedDerivedMeasure(ds, query)) {
68
- return runDerivedDatasetQuery(ds, query, options, buildDatasetQueryBuilder);
69
- }
70
10
  const start = Date.now();
71
- // Over-fetch one row so we can report `hasMore` without a count query.
72
- const qb = buildDatasetQueryBuilder(ds, query, {
73
- ...options,
74
- executionLimit: overfetchLimit(query.limit),
75
- });
76
- const rows = await qb.execute({ abortSignal: options.context?.abortSignal });
11
+ const prepared = prepareDatasetQuery(ds, query, options);
12
+ const rows = await prepared.execute();
77
13
  return toDatasetQueryResult(rows, {
78
14
  dataset: ds,
79
- query,
80
- sql: qb.toSQLWithParams().sql,
15
+ query: prepared.compilation.query,
16
+ sql: prepared.compilation.sql,
81
17
  timingMs: Date.now() - start,
82
18
  context: options.context,
83
19
  });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SQL rendering owned by the semantic datasets layer, separate from a query
3
+ * builder's compiler dialect. Extend this contract as emission sites migrate.
4
+ * Only the ClickHouse implementation is supported today.
5
+ */
6
+ export interface DatasetSqlDialect {
7
+ readonly name: string;
8
+ /** Quote one output identifier; dots in a qualified semantic alias are literal. */
9
+ quoteIdentifier(identifier: string): string;
10
+ }
11
+ //# sourceMappingURL=dataset-sql-dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataset-sql-dialect.d.ts","sourceRoot":"","sources":["../src/dataset-sql-dialect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7C"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/dataset.d.ts CHANGED
@@ -29,6 +29,7 @@
29
29
  * });
30
30
  * ```
31
31
  */
32
- import type { DatasetConfig, DatasetInstance, DatasetMeasureDefinition, DerivedMeasures, DimensionDefinition, RelationshipDefinition, SegmentDefinition } from './types.js';
33
- export declare function dataset<TDatasetName extends string, TDimensions extends Record<string, DimensionDefinition>, TDefinitions extends Record<string, DatasetMeasureDefinition> = {}, TRelationships extends Record<string, RelationshipDefinition> = Record<string, never>, const TSegments extends Record<string, SegmentDefinition> = {}>(name: TDatasetName, config: DatasetConfig<TDimensions, TDefinitions, TRelationships, TSegments>): DatasetInstance<TDimensions, TDefinitions, TRelationships, TDatasetName, DerivedMeasures<TDefinitions>, TSegments>;
32
+ import type { NormalizedDatasetFilters } from './utils/dataset-filter-types.js';
33
+ import type { DatasetConfig, DatasetInstance, DatasetMeasureDefinition, DerivedMeasures, DimensionDefinition, RelationshipDefinition, SegmentDefinition, SemanticFiltersDefinition } from './types.js';
34
+ export declare function dataset<TDatasetName extends string, TDimensions extends Record<string, DimensionDefinition>, TDefinitions extends Record<string, DatasetMeasureDefinition> = {}, TRelationships extends Record<string, RelationshipDefinition> = Record<string, never>, const TSegments extends Record<string, SegmentDefinition> = {}, const TFilters extends SemanticFiltersDefinition | undefined = SemanticFiltersDefinition | undefined>(name: TDatasetName, config: DatasetConfig<TDimensions, TDefinitions, TRelationships, TSegments, TFilters>): DatasetInstance<TDimensions, TDefinitions, TRelationships, TDatasetName, DerivedMeasures<TDefinitions>, TSegments, NormalizedDatasetFilters<TDimensions, TFilters>>;
34
35
  //# sourceMappingURL=dataset.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,wBAAwB,EAExB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EAKtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAsBpB,wBAAgB,OAAO,CACrB,YAAY,SAAS,MAAM,EAC3B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvD,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAAG,EAAE,EAClE,cAAc,SAAS,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACrF,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,EAE9D,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,CAAC,GAC1E,eAAe,CAAC,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC,CAoFpH"}
1
+ {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,wBAAwB,EAExB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EAKtB,iBAAiB,EACjB,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAsBpB,wBAAgB,OAAO,CACrB,YAAY,SAAS,MAAM,EAC3B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvD,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,GAAG,EAAE,EAClE,cAAc,SAAS,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACrF,KAAK,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,EAC9D,KAAK,CAAC,QAAQ,SAAS,yBAAyB,GAAG,SAAS,GAAG,yBAAyB,GAAG,SAAS,EAEpG,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,GACpF,eAAe,CAAC,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,wBAAwB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAoFrK"}
@@ -0,0 +1,28 @@
1
+ export type DatasetFeature = 'baseMeasures' | 'derivedMeasures' | 'segments' | 'windowMeasures' | 'shiftMeasures' | 'approxCountDistinct' | 'subDayGrains';
2
+ export interface DatasetFeatureSupport {
3
+ readonly feature: DatasetFeature;
4
+ /** Versions capable of representing the feature, independently of runtime support. */
5
+ readonly protocolVersions: readonly number[];
6
+ readonly typescript: {
7
+ readonly local: boolean;
8
+ readonly publish: boolean;
9
+ };
10
+ readonly python: {
11
+ readonly local: boolean;
12
+ readonly publish: boolean;
13
+ };
14
+ /** Repository portable runtime support, not qualification of a hosted service. */
15
+ readonly cloud: boolean;
16
+ }
17
+ export interface DatasetExecutionCapabilities {
18
+ readonly version: 1;
19
+ readonly cloudDeploymentVersion: 2;
20
+ readonly features: readonly DatasetFeatureSupport[];
21
+ }
22
+ /**
23
+ * Conservative feature matrix tested against TS, Python and portable execution.
24
+ * Support assumes a compatible builder and a valid definition/query. This is a
25
+ * discovery aid, not a replacement for contract validation or authorization.
26
+ */
27
+ export declare const DATASET_EXECUTION_CAPABILITIES: DatasetExecutionCapabilities;
28
+ //# sourceMappingURL=execution-capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-capabilities.d.ts","sourceRoot":"","sources":["../src/execution-capabilities.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,iBAAiB,GAAG,UAAU,GACxE,gBAAgB,GAAG,eAAe,GAAG,qBAAqB,GAAG,cAAc,CAAC;AAEhF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,sFAAsF;IACtF,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5E,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACxE,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;CACrD;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,4BAU3C,CAAC"}
@@ -0,0 +1,17 @@
1
+ import matrix from './execution-capabilities.json' with { type: 'json' };
2
+ /**
3
+ * Conservative feature matrix tested against TS, Python and portable execution.
4
+ * Support assumes a compatible builder and a valid definition/query. This is a
5
+ * discovery aid, not a replacement for contract validation or authorization.
6
+ */
7
+ export const DATASET_EXECUTION_CAPABILITIES = Object.freeze({
8
+ version: 1,
9
+ cloudDeploymentVersion: 2,
10
+ features: Object.freeze(matrix.features.map(entry => Object.freeze({
11
+ feature: entry.feature,
12
+ protocolVersions: Object.freeze([...entry.protocolVersions]),
13
+ typescript: Object.freeze({ ...entry.typescript }),
14
+ python: Object.freeze({ ...entry.python }),
15
+ cloud: entry.cloud,
16
+ }))),
17
+ });
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 1,
3
+ "cloudDeploymentVersion": 2,
4
+ "features": [
5
+ { "feature": "baseMeasures", "protocolVersions": [2, 3], "typescript": { "local": true, "publish": true }, "python": { "local": true, "publish": true }, "cloud": true },
6
+ { "feature": "derivedMeasures", "protocolVersions": [2, 3], "typescript": { "local": true, "publish": true }, "python": { "local": true, "publish": true }, "cloud": true },
7
+ { "feature": "segments", "protocolVersions": [3], "typescript": { "local": true, "publish": false }, "python": { "local": false, "publish": false }, "cloud": false },
8
+ { "feature": "windowMeasures", "protocolVersions": [3], "typescript": { "local": true, "publish": false }, "python": { "local": false, "publish": false }, "cloud": false },
9
+ { "feature": "shiftMeasures", "protocolVersions": [3], "typescript": { "local": true, "publish": false }, "python": { "local": false, "publish": false }, "cloud": false },
10
+ { "feature": "approxCountDistinct", "protocolVersions": [3], "typescript": { "local": true, "publish": false }, "python": { "local": false, "publish": false }, "cloud": false },
11
+ { "feature": "subDayGrains", "protocolVersions": [3], "typescript": { "local": true, "publish": false }, "python": { "local": true, "publish": false }, "cloud": false }
12
+ ]
13
+ }