@hypequery/datasets 0.23.1 → 0.25.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 (255) hide show
  1. package/README.md +14 -0
  2. package/dist/aggregations.d.ts +3 -0
  3. package/dist/aggregations.d.ts.map +1 -1
  4. package/dist/aggregations.js +6 -0
  5. package/dist/cache/definition-identity.d.ts +9 -6
  6. package/dist/cache/definition-identity.d.ts.map +1 -1
  7. package/dist/cache/definition-identity.js +14 -8
  8. package/dist/cache/protocol-cache-keys.d.ts.map +1 -1
  9. package/dist/cache/protocol-cache-keys.js +29 -6
  10. package/dist/cache/query-signature.d.ts.map +1 -1
  11. package/dist/cache/query-signature.js +12 -1
  12. package/dist/catalog.d.ts +7 -0
  13. package/dist/catalog.d.ts.map +1 -1
  14. package/dist/catalog.js +5 -2
  15. package/dist/client-contract/query-schema.d.ts +19 -0
  16. package/dist/client-contract/query-schema.d.ts.map +1 -0
  17. package/dist/client-contract/query-schema.js +85 -0
  18. package/dist/constants.d.ts +5 -4
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +7 -6
  21. package/dist/contract.d.ts +5 -0
  22. package/dist/contract.d.ts.map +1 -1
  23. package/dist/contract.js +6 -3
  24. package/dist/dataset-compilation.d.ts +2 -0
  25. package/dist/dataset-compilation.d.ts.map +1 -1
  26. package/dist/dataset-sql-dialect.d.ts +119 -0
  27. package/dist/dataset-sql-dialect.d.ts.map +1 -1
  28. package/dist/dataset.d.ts +4 -2
  29. package/dist/dataset.d.ts.map +1 -1
  30. package/dist/dataset.js +23 -31
  31. package/dist/in-memory-backend.d.ts.map +1 -1
  32. package/dist/in-memory-backend.js +2 -0
  33. package/dist/index.d.ts +49 -6
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +34 -6
  36. package/dist/internal.d.ts +5 -1
  37. package/dist/internal.d.ts.map +1 -1
  38. package/dist/internal.js +5 -1
  39. package/dist/measure.d.ts +9 -1
  40. package/dist/measure.d.ts.map +1 -1
  41. package/dist/measure.js +9 -1
  42. package/dist/metric-query-engine.d.ts +0 -1
  43. package/dist/metric-query-engine.d.ts.map +1 -1
  44. package/dist/metric-query-engine.js +11 -3
  45. package/dist/protocol-adapter.d.ts.map +1 -1
  46. package/dist/protocol-adapter.js +2 -3
  47. package/dist/protocol-deployment-adapter.d.ts.map +1 -1
  48. package/dist/protocol-deployment-adapter.js +7 -1
  49. package/dist/protocol-rehydrate.d.ts.map +1 -1
  50. package/dist/protocol-rehydrate.js +1 -0
  51. package/dist/protocol-schema-adapter.d.ts +7 -7
  52. package/dist/protocol-schema-adapter.d.ts.map +1 -1
  53. package/dist/protocol-schema-adapter.js +12 -245
  54. package/dist/query-builder-protocol.d.ts +34 -1
  55. package/dist/query-builder-protocol.d.ts.map +1 -1
  56. package/dist/query-planner.d.ts +14 -5
  57. package/dist/query-planner.d.ts.map +1 -1
  58. package/dist/query-planner.js +53 -34
  59. package/dist/relationship-check.d.ts.map +1 -1
  60. package/dist/relationship-check.js +8 -8
  61. package/dist/schemas.d.ts +17 -0
  62. package/dist/schemas.d.ts.map +1 -0
  63. package/dist/schemas.js +16 -0
  64. package/dist/semantic-planner.d.ts.map +1 -1
  65. package/dist/semantic-planner.js +49 -13
  66. package/dist/semantic-query-schema.d.ts +8 -1
  67. package/dist/semantic-query-schema.d.ts.map +1 -1
  68. package/dist/semantic-query-schema.js +18 -12
  69. package/dist/tools.d.ts.map +1 -1
  70. package/dist/tools.js +4 -3
  71. package/dist/types.d.ts +105 -7
  72. package/dist/types.d.ts.map +1 -1
  73. package/dist/utils/aggregate-state-functions.d.ts +24 -0
  74. package/dist/utils/aggregate-state-functions.d.ts.map +1 -0
  75. package/dist/utils/aggregate-state-functions.js +60 -0
  76. package/dist/utils/approximate-measures.d.ts +3 -1
  77. package/dist/utils/approximate-measures.d.ts.map +1 -1
  78. package/dist/utils/approximate-measures.js +8 -2
  79. package/dist/utils/base-measure-definition.d.ts +16 -0
  80. package/dist/utils/base-measure-definition.d.ts.map +1 -1
  81. package/dist/utils/base-measure-definition.js +31 -0
  82. package/dist/utils/build-dataset-query-builder.d.ts +1 -1
  83. package/dist/utils/build-dataset-query-builder.d.ts.map +1 -1
  84. package/dist/utils/build-dataset-query-builder.js +26 -21
  85. package/dist/utils/by-name.d.ts +8 -0
  86. package/dist/utils/by-name.d.ts.map +1 -0
  87. package/dist/utils/by-name.js +44 -0
  88. package/dist/utils/calendar-shift-sql.d.ts +5 -4
  89. package/dist/utils/calendar-shift-sql.d.ts.map +1 -1
  90. package/dist/utils/calendar-shift-sql.js +8 -8
  91. package/dist/utils/clickhouse-dataset-sql-dialect.d.ts +2 -2
  92. package/dist/utils/clickhouse-dataset-sql-dialect.d.ts.map +1 -1
  93. package/dist/utils/clickhouse-dataset-sql-dialect.js +143 -1
  94. package/dist/utils/compile-dataset-query.d.ts +1 -1
  95. package/dist/utils/compile-dataset-query.d.ts.map +1 -1
  96. package/dist/utils/compile-dataset-query.js +22 -8
  97. package/dist/utils/composite-time-measure-sql.d.ts +3 -5
  98. package/dist/utils/composite-time-measure-sql.d.ts.map +1 -1
  99. package/dist/utils/composite-time-measure-sql.js +15 -16
  100. package/dist/utils/count-aggregations.d.ts +4 -0
  101. package/dist/utils/count-aggregations.d.ts.map +1 -0
  102. package/dist/utils/count-aggregations.js +6 -0
  103. package/dist/utils/dataset-definition-validation.d.ts +1 -1
  104. package/dist/utils/dataset-definition-validation.d.ts.map +1 -1
  105. package/dist/utils/dataset-definition-validation.js +55 -26
  106. package/dist/utils/dataset-derived-query.d.ts +2 -4
  107. package/dist/utils/dataset-derived-query.d.ts.map +1 -1
  108. package/dist/utils/dataset-derived-query.js +11 -14
  109. package/dist/utils/dataset-having.d.ts +5 -7
  110. package/dist/utils/dataset-having.d.ts.map +1 -1
  111. package/dist/utils/dataset-having.js +9 -12
  112. package/dist/utils/dataset-normalization.d.ts.map +1 -1
  113. package/dist/utils/dataset-normalization.js +1 -0
  114. package/dist/utils/dataset-query-validation.d.ts +1 -1
  115. package/dist/utils/dataset-query-validation.d.ts.map +1 -1
  116. package/dist/utils/dataset-query-validation.js +19 -2
  117. package/dist/utils/dataset-source.d.ts +42 -0
  118. package/dist/utils/dataset-source.d.ts.map +1 -0
  119. package/dist/utils/dataset-source.js +59 -0
  120. package/dist/utils/dataset-sql-dialect.d.ts +13 -2
  121. package/dist/utils/dataset-sql-dialect.d.ts.map +1 -1
  122. package/dist/utils/dataset-sql-dialect.js +74 -1
  123. package/dist/utils/dataset-time-keys.d.ts +32 -0
  124. package/dist/utils/dataset-time-keys.d.ts.map +1 -0
  125. package/dist/utils/dataset-time-keys.js +55 -0
  126. package/dist/utils/dataset-validation.d.ts.map +1 -1
  127. package/dist/utils/dataset-validation.js +7 -0
  128. package/dist/utils/deployable-formulas.d.ts +33 -0
  129. package/dist/utils/deployable-formulas.d.ts.map +1 -0
  130. package/dist/utils/deployable-formulas.js +102 -0
  131. package/dist/utils/derived-cte-validation.d.ts +5 -0
  132. package/dist/utils/derived-cte-validation.d.ts.map +1 -1
  133. package/dist/utils/derived-cte-validation.js +77 -8
  134. package/dist/utils/derived-measure-sql.d.ts +10 -2
  135. package/dist/utils/derived-measure-sql.d.ts.map +1 -1
  136. package/dist/utils/derived-measure-sql.js +23 -43
  137. package/dist/utils/enforced-constraints.d.ts +14 -0
  138. package/dist/utils/enforced-constraints.d.ts.map +1 -0
  139. package/dist/utils/enforced-constraints.js +57 -0
  140. package/dist/utils/filter-field-type.d.ts +14 -0
  141. package/dist/utils/filter-field-type.d.ts.map +1 -0
  142. package/dist/utils/filter-field-type.js +21 -0
  143. package/dist/utils/filtered-aggregation-sql.d.ts +2 -1
  144. package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -1
  145. package/dist/utils/filtered-aggregation-sql.js +18 -35
  146. package/dist/utils/groupable.d.ts +7 -0
  147. package/dist/utils/groupable.d.ts.map +1 -0
  148. package/dist/utils/groupable.js +8 -0
  149. package/dist/utils/metric-derived-query.d.ts +2 -4
  150. package/dist/utils/metric-derived-query.d.ts.map +1 -1
  151. package/dist/utils/metric-derived-query.js +58 -51
  152. package/dist/utils/metric-query-builder.d.ts +1 -1
  153. package/dist/utils/metric-query-builder.d.ts.map +1 -1
  154. package/dist/utils/metric-query-builder.js +22 -20
  155. package/dist/utils/metric-query-validation.d.ts.map +1 -1
  156. package/dist/utils/metric-query-validation.js +14 -1
  157. package/dist/utils/portable-aggregations.d.ts +1 -0
  158. package/dist/utils/portable-aggregations.d.ts.map +1 -1
  159. package/dist/utils/portable-aggregations.js +5 -0
  160. package/dist/utils/protocol-schema-conversion.d.ts +12 -0
  161. package/dist/utils/protocol-schema-conversion.d.ts.map +1 -0
  162. package/dist/utils/protocol-schema-conversion.js +61 -0
  163. package/dist/utils/query-field-references.d.ts +10 -0
  164. package/dist/utils/query-field-references.d.ts.map +1 -0
  165. package/dist/utils/query-field-references.js +38 -0
  166. package/dist/utils/query-timezone.d.ts +41 -3
  167. package/dist/utils/query-timezone.d.ts.map +1 -1
  168. package/dist/utils/query-timezone.js +76 -9
  169. package/dist/utils/raw-sql-dialect-check.d.ts +12 -0
  170. package/dist/utils/raw-sql-dialect-check.d.ts.map +1 -0
  171. package/dist/utils/raw-sql-dialect-check.js +37 -0
  172. package/dist/utils/relationship-builder-plan.d.ts +37 -18
  173. package/dist/utils/relationship-builder-plan.d.ts.map +1 -1
  174. package/dist/utils/relationship-builder-plan.js +43 -28
  175. package/dist/utils/relationship-measure-sql.d.ts +14 -4
  176. package/dist/utils/relationship-measure-sql.d.ts.map +1 -1
  177. package/dist/utils/relationship-measure-sql.js +36 -10
  178. package/dist/utils/relationship-measures.d.ts.map +1 -1
  179. package/dist/utils/relationship-measures.js +3 -0
  180. package/dist/utils/relationship-validation.d.ts.map +1 -1
  181. package/dist/utils/relationship-validation.js +2 -0
  182. package/dist/utils/row-scope.d.ts +23 -0
  183. package/dist/utils/row-scope.d.ts.map +1 -0
  184. package/dist/utils/row-scope.js +26 -0
  185. package/dist/utils/scoped-dataset-source.d.ts +23 -0
  186. package/dist/utils/scoped-dataset-source.d.ts.map +1 -0
  187. package/dist/utils/scoped-dataset-source.js +34 -0
  188. package/dist/utils/semantic-tool.d.ts +2 -2
  189. package/dist/utils/semantic-tool.d.ts.map +1 -1
  190. package/dist/utils/semantic-tool.js +1 -1
  191. package/dist/utils/shift-measure-sql.d.ts +5 -4
  192. package/dist/utils/shift-measure-sql.d.ts.map +1 -1
  193. package/dist/utils/shift-measure-sql.js +25 -26
  194. package/dist/utils/shift-wall-time-sql.d.ts +2 -1
  195. package/dist/utils/shift-wall-time-sql.d.ts.map +1 -1
  196. package/dist/utils/shift-wall-time-sql.js +7 -7
  197. package/dist/utils/snapshot-execution-context.d.ts.map +1 -1
  198. package/dist/utils/snapshot-execution-context.js +3 -0
  199. package/dist/utils/statement-parameters.d.ts +58 -0
  200. package/dist/utils/statement-parameters.d.ts.map +1 -0
  201. package/dist/utils/statement-parameters.js +101 -0
  202. package/dist/utils/time-axis-calendar-guard.d.ts +2 -1
  203. package/dist/utils/time-axis-calendar-guard.d.ts.map +1 -1
  204. package/dist/utils/time-axis-calendar-guard.js +5 -7
  205. package/dist/utils/time-measure-axis-sql.d.ts +3 -2
  206. package/dist/utils/time-measure-axis-sql.d.ts.map +1 -1
  207. package/dist/utils/time-measure-axis-sql.js +20 -22
  208. package/dist/utils/time-measure-context-sql.d.ts +3 -2
  209. package/dist/utils/time-measure-context-sql.d.ts.map +1 -1
  210. package/dist/utils/time-measure-context-sql.js +11 -11
  211. package/dist/utils/time-measure-dataset-sql.d.ts +7 -5
  212. package/dist/utils/time-measure-dataset-sql.d.ts.map +1 -1
  213. package/dist/utils/time-measure-dataset-sql.js +17 -12
  214. package/dist/utils/time-measure-leaf-sql.d.ts +3 -2
  215. package/dist/utils/time-measure-leaf-sql.d.ts.map +1 -1
  216. package/dist/utils/time-measure-leaf-sql.js +19 -18
  217. package/dist/utils/time-measure-result-sql.d.ts.map +1 -1
  218. package/dist/utils/time-measure-result-sql.js +10 -11
  219. package/dist/utils/time-measure-source-sql.d.ts +5 -2
  220. package/dist/utils/time-measure-source-sql.d.ts.map +1 -1
  221. package/dist/utils/time-measure-source-sql.js +33 -23
  222. package/dist/utils/time-measure-values-sql.d.ts +4 -3
  223. package/dist/utils/time-measure-values-sql.d.ts.map +1 -1
  224. package/dist/utils/time-measure-values-sql.js +26 -29
  225. package/dist/utils/timestamp-instants.d.ts +17 -0
  226. package/dist/utils/timestamp-instants.d.ts.map +1 -0
  227. package/dist/utils/timestamp-instants.js +34 -0
  228. package/dist/utils/timestamp-text.d.ts +12 -0
  229. package/dist/utils/timestamp-text.d.ts.map +1 -0
  230. package/dist/utils/timestamp-text.js +18 -0
  231. package/dist/utils/zod-json-schema.d.ts +8 -0
  232. package/dist/utils/zod-json-schema.d.ts.map +1 -0
  233. package/dist/utils/zod-json-schema.js +18 -0
  234. package/dist/utils/zod-schema-version.d.ts +19 -0
  235. package/dist/utils/zod-schema-version.d.ts.map +1 -0
  236. package/dist/utils/zod-schema-version.js +6 -0
  237. package/dist/utils/zod-v3-protocol-schema.d.ts +10 -0
  238. package/dist/utils/zod-v3-protocol-schema.d.ts.map +1 -0
  239. package/dist/utils/zod-v3-protocol-schema.js +164 -0
  240. package/dist/utils/zod-v4-protocol-schema.d.ts +12 -0
  241. package/dist/utils/zod-v4-protocol-schema.d.ts.map +1 -0
  242. package/dist/utils/zod-v4-protocol-schema.js +171 -0
  243. package/dist/validation.d.ts +7 -0
  244. package/dist/validation.d.ts.map +1 -1
  245. package/dist/validation.js +42 -8
  246. package/package.json +21 -12
  247. package/dist/api.type-test.d.ts +0 -2
  248. package/dist/api.type-test.d.ts.map +0 -1
  249. package/dist/api.type-test.js +0 -251
  250. package/dist/utils/time-arithmetic-sql.d.ts +0 -4
  251. package/dist/utils/time-arithmetic-sql.d.ts.map +0 -1
  252. package/dist/utils/time-arithmetic-sql.js +0 -9
  253. package/dist/utils/window-aggregation-sql.d.ts +0 -5
  254. package/dist/utils/window-aggregation-sql.d.ts.map +0 -1
  255. package/dist/utils/window-aggregation-sql.js +0 -17
@@ -1,17 +1,17 @@
1
1
  import { semanticOrderDirection } from './utils/semantic-query-syntax.js';
2
2
  import { queryTimeSql } from './utils/query-timezone.js';
3
3
  import { assertNoRawSqlUnderJoins } from './utils/sql-under-joins.js';
4
- import { GRAIN_FUNCTIONS } from "./constants.js";
4
+ import { isSupportedTimeGrain } from "./constants.js";
5
5
  import { applyFilteredAggregationExpression } from './utils/filtered-aggregation-sql.js';
6
6
  import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
7
- import { clickhouseDatasetSqlDialect } from './utils/clickhouse-dataset-sql-dialect.js';
8
7
  import { isQualifiedField } from './utils/relationship-fields.js';
9
- import { qualifyBaseColumn, resolveQualifiedColumn, } from './utils/relationship-builder-plan.js';
8
+ import { qualifyBaseColumn, resolveQualifiedExpression, } from './utils/relationship-builder-plan.js';
10
9
  import { measureToAggregationSpec } from './utils/dataset-normalization.js';
11
10
  import { validatePercentileLevel } from './measure.js';
11
+ import { assertAggregateStateFunction } from './utils/aggregate-state-functions.js';
12
12
  export function resolveDimensionExpression(ds, dimensionName, joinCtx) {
13
13
  if (joinCtx && isQualifiedField(dimensionName)) {
14
- return resolveQualifiedColumn(ds, dimensionName);
14
+ return resolveQualifiedExpression(ds, dimensionName, joinCtx);
15
15
  }
16
16
  const definition = ds.dimensions[dimensionName];
17
17
  if (definition?.sql) {
@@ -22,50 +22,51 @@ export function resolveDimensionExpression(ds, dimensionName, joinCtx) {
22
22
  }
23
23
  export function resolveFilterField(ds, filterField, joinCtx) {
24
24
  if (joinCtx && isQualifiedField(filterField)) {
25
- return resolveQualifiedColumn(ds, filterField);
25
+ return resolveQualifiedExpression(ds, filterField, joinCtx);
26
26
  }
27
27
  const resolvedField = ds.filters[filterField]?.field ?? filterField;
28
28
  return resolveDimensionExpression(ds, resolvedField, joinCtx);
29
29
  }
30
- export function buildDimensionSelectionPlan(ds, dimensions, grain, joinCtx, timezone, dialect = clickhouseDatasetSqlDialect) {
30
+ export function buildDimensionSelectionPlan(ds, dimensions, grain, joinCtx, timezone, dialect) {
31
31
  const selectParts = [];
32
32
  const groupByParts = new Set();
33
33
  if (grain) {
34
- const fn = GRAIN_FUNCTIONS[grain];
35
- if (!fn) {
34
+ if (!isSupportedTimeGrain(grain)) {
36
35
  throw new Error(`Unsupported time grain "${grain}".`);
37
36
  }
38
37
  const time = resolveDimensionExpression(ds, String(ds.timeKey), joinCtx);
39
- selectParts.push(`${fn}(${queryTimeSql(time, timezone)}) AS period`);
40
- groupByParts.add("period");
38
+ const period = dialect.quoteIdentifier('period');
39
+ selectParts.push(`${dialect.truncateTime(queryTimeSql(dialect, time, timezone), grain)} AS ${period}`);
40
+ groupByParts.add(period);
41
41
  }
42
42
  for (const dimensionName of dimensions) {
43
43
  const expression = resolveDimensionExpression(ds, dimensionName, joinCtx);
44
- if (joinCtx) {
45
- // With joins in scope, every selection is table-qualified and aliased so
46
- // grouping/ordering can reference the alias unambiguously.
47
- const alias = isQualifiedField(dimensionName)
48
- ? dialect.quoteIdentifier(dimensionName)
49
- : dimensionName;
50
- selectParts.push(`${expression} AS ${alias}`);
51
- groupByParts.add(alias);
52
- }
53
- else if (expression === dimensionName) {
44
+ // Every generated alias is quoted: reserved words and engines that fold
45
+ // unquoted case (Postgres) must keep the semantic name. With joins in
46
+ // scope every selection is table-qualified, so it is always aliased.
47
+ if (!joinCtx && expression === dimensionName) {
54
48
  selectParts.push(dimensionName);
55
49
  groupByParts.add(dimensionName);
56
50
  }
57
51
  else {
58
- selectParts.push(`${expression} AS ${dimensionName}`);
59
- groupByParts.add(dimensionName);
52
+ const alias = dialect.quoteIdentifier(dimensionName);
53
+ selectParts.push(`${expression} AS ${alias}`);
54
+ // A qualified alias (`customer.tier`) can resolve to the physical joined
55
+ // column, so group on its guarded expression: the match marker stays
56
+ // part of the key whatever the engine's alias-resolution rules.
57
+ groupByParts.add(joinCtx && isQualifiedField(dimensionName) ? expression : alias);
60
58
  }
61
59
  }
62
60
  return { selectParts, groupByParts: Array.from(groupByParts) };
63
61
  }
64
- export function applyAggregationSpec(qb, ds, spec, alias, joinCtx, expressions) {
62
+ export function applyAggregationSpec(qb, ds, spec, name, joinCtx, dialect, expressions) {
63
+ // The semantic name is the output alias, quoted so it survives reserved
64
+ // words and case folding; messages keep the unquoted name.
65
+ const alias = dialect.quoteIdentifier(name);
65
66
  if (spec.sql) {
66
- assertNoRawSqlUnderJoins('measure', alias, spec.sql, joinCtx);
67
+ assertNoRawSqlUnderJoins('measure', name, spec.sql, joinCtx);
67
68
  }
68
- const fieldOrExpr = expressions?.field ?? applyFilteredAggregationExpression(ds, spec, spec.sql ?? resolveDimensionExpression(ds, spec.field, joinCtx), joinCtx);
69
+ const fieldOrExpr = expressions?.field ?? applyFilteredAggregationExpression(ds, spec, spec.sql ?? resolveDimensionExpression(ds, spec.field, joinCtx), joinCtx, dialect);
69
70
  switch (spec.aggregation) {
70
71
  case "sum":
71
72
  return qb.sum(fieldOrExpr, alias);
@@ -82,7 +83,7 @@ export function applyAggregationSpec(qb, ds, spec, alias, joinCtx, expressions)
82
83
  case "argMax":
83
84
  case "argMin": {
84
85
  if (!spec.argField) {
85
- throw new Error(`Aggregation "${spec.aggregation}" for "${alias}" requires an argField ("by" column).`);
86
+ throw new Error(`Aggregation "${spec.aggregation}" for "${name}" requires an argField ("by" column).`);
86
87
  }
87
88
  const argExpr = expressions?.arg ?? resolveDimensionExpression(ds, spec.argField, joinCtx);
88
89
  if (spec.aggregation === "argMax") {
@@ -98,7 +99,7 @@ export function applyAggregationSpec(qb, ds, spec, alias, joinCtx, expressions)
98
99
  }
99
100
  case "percentile": {
100
101
  if (spec.level == null) {
101
- throw new Error(`Aggregation "percentile" for "${alias}" requires a level.`);
102
+ throw new Error(`Aggregation "percentile" for "${name}" requires a level.`);
102
103
  }
103
104
  validatePercentileLevel(spec.level);
104
105
  if (!qb.quantile) {
@@ -111,6 +112,16 @@ export function applyAggregationSpec(qb, ds, spec, alias, joinCtx, expressions)
111
112
  throw new Error('Query builder does not support approxCountDistinct aggregations.');
112
113
  }
113
114
  return qb.approxCountDistinct(fieldOrExpr, alias);
115
+ case "merge": {
116
+ assertAggregateStateFunction(spec.stateFunction, `Measure "${name}"`);
117
+ if (spec.filters?.length) {
118
+ throw new Error(`Measure filters are not supported on merge aggregations ("${name}").`);
119
+ }
120
+ if (!qb.mergeState) {
121
+ throw new Error('Query builder does not support merge aggregations (mergeState).');
122
+ }
123
+ return qb.mergeState(spec.stateFunction, fieldOrExpr, alias);
124
+ }
114
125
  case "stddev":
115
126
  if (!qb.stddev) {
116
127
  throw new Error('Query builder does not support stddev aggregations.');
@@ -125,20 +136,28 @@ export function applyAggregationSpec(qb, ds, spec, alias, joinCtx, expressions)
125
136
  throw new Error(`Unknown aggregation type: ${spec.aggregation}`);
126
137
  }
127
138
  }
128
- export function applyMeasureDefinition(qb, ds, name, definition, joinCtx) {
129
- return applyAggregationSpec(qb, ds, measureToAggregationSpec(name, definition), name, joinCtx);
139
+ export function applyMeasureDefinition(qb, ds, name, definition, joinCtx, dialect) {
140
+ return applyAggregationSpec(qb, ds, measureToAggregationSpec(name, definition), name, joinCtx, dialect);
130
141
  }
131
- export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset, joinCtx, dialect = clickhouseDatasetSqlDialect) {
142
+ /**
143
+ * Appends ORDER BY, LIMIT and OFFSET. Under joins, an order on a selected
144
+ * qualified dimension repeats its guarded expression (the GROUP BY key) rather
145
+ * than naming the alias, which the engine may resolve to the raw joined column;
146
+ * any other qualified order (a related measure) sorts by its quoted alias.
147
+ */
148
+ export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset, joinCtx, dialect, selection) {
132
149
  if (orderBy && orderBy.length > 0) {
133
150
  for (const order of orderBy) {
134
- const column = joinCtx && isQualifiedField(order.field)
135
- ? dialect.quoteIdentifier(order.field)
136
- : order.field;
151
+ // A selected related dimension orders by its guarded expression, for the
152
+ // same alias-resolution reason it groups by it.
153
+ const column = joinCtx && isQualifiedField(order.field) && selection?.dimensions.includes(order.field)
154
+ ? resolveDimensionExpression(selection.ds, order.field, joinCtx)
155
+ : dialect.quoteIdentifier(order.field);
137
156
  qb = qb.orderBy(column, semanticOrderDirection(order.direction));
138
157
  }
139
158
  }
140
159
  else if (grain) {
141
- qb = qb.orderBy("period", "ASC");
160
+ qb = qb.orderBy(dialect.quoteIdentifier("period"), "ASC");
142
161
  }
143
162
  if (limit != null) {
144
163
  qb = qb.limit(limit);
@@ -1 +1 @@
1
- {"version":3,"file":"relationship-check.d.ts","sourceRoot":"","sources":["../src/relationship-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAyB,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAEnG,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,YAAY,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,YAAY,EAAE,wBAAwB,CAAC;IACvC;;;OAGG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAKD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAqCnC"}
1
+ {"version":3,"file":"relationship-check.d.ts","sourceRoot":"","sources":["../src/relationship-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAyB,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAInG,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,YAAY,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAE9E,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,YAAY,EAAE,wBAAwB,CAAC;IACvC;;;OAGG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,6DAA6D;IAC7D,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAKD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAkCnC"}
@@ -16,8 +16,11 @@
16
16
  * }
17
17
  * ```
18
18
  */
19
+ import { datasetSourceBuilder } from './utils/dataset-source.js';
19
20
  import { toQueryBuilderFactory } from './query-builder-protocol.js';
20
- import { getRuntimeTenantPredicate, validateTenantRuntime } from './utils/tenant-runtime.js';
21
+ import { validateTenantRuntime } from './utils/tenant-runtime.js';
22
+ import { applyRowScope, datasetRowScope } from './utils/row-scope.js';
23
+ import { resolveDatasetSqlDialect } from './utils/dataset-sql-dialect.js';
21
24
  import { listToOneRelationships, readCount, relationshipKeyIssue, } from './utils/relationship-key-check.js';
22
25
  const ROWS_ALIAS = '__hq_rows';
23
26
  const KEYS_ALIAS = '__hq_keys';
@@ -29,7 +32,7 @@ const KEYS_ALIAS = '__hq_keys';
29
32
  */
30
33
  export async function checkRelationships(ds, options) {
31
34
  const factory = toQueryBuilderFactory(options.queryBuilder);
32
- const tenantPredicate = getRuntimeTenantPredicate(options.context);
35
+ const dialect = resolveDatasetSqlDialect(factory);
33
36
  const entries = listToOneRelationships(ds, options.relationships);
34
37
  const issues = [];
35
38
  for (const entry of entries) {
@@ -37,17 +40,14 @@ export async function checkRelationships(ds, options) {
37
40
  if (tenantError) {
38
41
  throw new Error(`Cannot check relationship "${entry.relationship}": ${tenantError}`);
39
42
  }
40
- let qb = factory
41
- .table(entry.target.source)
43
+ let qb = datasetSourceBuilder(factory, entry.target)
42
44
  .count(entry.column, ROWS_ALIAS)
43
- .countDistinct(entry.columns ? `tuple(${entry.columns.join(', ')})` : entry.column, KEYS_ALIAS);
45
+ .countDistinct(entry.columns ? dialect.packRow(entry.columns) : entry.column, KEYS_ALIAS);
44
46
  if (entry.columns) {
45
47
  for (const column of entry.columns)
46
48
  qb = qb.where(column, 'isNotNull', undefined);
47
49
  }
48
- if (entry.target.tenantKey && tenantPredicate) {
49
- qb = qb.where(entry.target.tenantKey, tenantPredicate.operator, tenantPredicate.value);
50
- }
50
+ qb = applyRowScope(qb, datasetRowScope(entry.target, options.context));
51
51
  const [row] = await qb.execute({
52
52
  abortSignal: options.context?.abortSignal,
53
53
  });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@hypequery/datasets/schemas`: Zod-backed query schemas and agent tools.
3
+ *
4
+ * Everything here builds or reads Zod schemas. It lives apart from the root
5
+ * entry so that defining and querying datasets never loads Zod. In 1.0 the
6
+ * root entry stops re-exporting these and Zod becomes an optional peer
7
+ * dependency needed only by this entry.
8
+ */
9
+ export { generateDatasetTools, toOpenAITools, toAISDKTools, toMcpTools, } from './tools.js';
10
+ export type { AISDKToolDefinition, DatasetToolAnalytics, DatasetToolMode, GenerateDatasetToolsOptions, JsonSchema, McpToolDefinition, OpenAIToolDefinition, SemanticToolDefinition, } from './tools.js';
11
+ export { buildDatasetInputSchema, buildMetricInputSchema, buildCanonicalSemanticQuerySchemas, toSemanticJsonSchema, DEFAULT_SEMANTIC_QUERY_SCHEMA_LIMITS, buildDatasetInputProtocolSchema, buildMetricInputProtocolSchema, } from './semantic-query-schema.js';
12
+ export type { CanonicalSemanticQuerySchemas, SemanticMetricQueryContract, SemanticQuerySchemaLimits, SemanticQuerySchemaOptions, SemanticQuerySchemaSource, } from './semantic-query-schema.js';
13
+ export { ProtocolSchemaAdapterError, zodToProtocolSchema } from './protocol-schema-adapter.js';
14
+ export type { AnyZodSchema } from './utils/zod-schema-version.js';
15
+ export { buildClientContractQuerySchemas } from './client-contract/query-schema.js';
16
+ export type { ClientContractQuerySchemas, ClientEndpointQuerySchema } from './client-contract/query-schema.js';
17
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,2BAA2B,EAC3B,UAAU,EACV,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,kCAAkC,EAClC,oBAAoB,EACpB,oCAAoC,EACpC,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,6BAA6B,EAC7B,2BAA2B,EAC3B,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC/F,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAGlE,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AACpF,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `@hypequery/datasets/schemas`: Zod-backed query schemas and agent tools.
3
+ *
4
+ * Everything here builds or reads Zod schemas. It lives apart from the root
5
+ * entry so that defining and querying datasets never loads Zod. In 1.0 the
6
+ * root entry stops re-exporting these and Zod becomes an optional peer
7
+ * dependency needed only by this entry.
8
+ */
9
+ // Agent/tool metadata
10
+ export { generateDatasetTools, toOpenAITools, toAISDKTools, toMcpTools, } from './tools.js';
11
+ // Canonical semantic query schemas shared by Serve, MCP, and agent adapters.
12
+ export { buildDatasetInputSchema, buildMetricInputSchema, buildCanonicalSemanticQuerySchemas, toSemanticJsonSchema, DEFAULT_SEMANTIC_QUERY_SCHEMA_LIMITS, buildDatasetInputProtocolSchema, buildMetricInputProtocolSchema, } from './semantic-query-schema.js';
13
+ // Zod to RFC 0004 protocol schemas, for Zod 3 or Zod 4 input.
14
+ export { ProtocolSchemaAdapterError, zodToProtocolSchema } from './protocol-schema-adapter.js';
15
+ // Client-contract query schemas.
16
+ export { buildClientContractQuerySchemas } from './client-contract/query-schema.js';
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-planner.d.ts","sourceRoot":"","sources":["../src/semantic-planner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAGhB,WAAW,EACX,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,QAAQ,EAIT,MAAM,oBAAoB,CAAC;AA8L5B,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,kBAAkB,EACtB,KAAK,GAAE,YAAiB,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAmBV;AA2FD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,GAAE,WAAgB,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAaV"}
1
+ {"version":3,"file":"semantic-planner.d.ts","sourceRoot":"","sources":["../src/semantic-planner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAGhB,WAAW,EACX,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,QAAQ,EAKT,MAAM,oBAAoB,CAAC;AAgO5B,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,kBAAkB,EACtB,KAAK,GAAE,YAAiB,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAsBV;AA2FD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,GAAE,WAAgB,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAgBV"}
@@ -4,9 +4,10 @@ import { protocolMetricCapabilityErrors } from './utils/protocol-metric-capabili
4
4
  import { getMetricGrain, getMetricRef, } from './utils/metric-handle.js';
5
5
  import { validateDatasetQuery } from './dataset-query.js';
6
6
  import { isSupportedTimeGrain } from './constants.js';
7
- import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
7
+ import { datasetRowScope, runtimeConstraints } from './utils/row-scope.js';
8
8
  import { isQualifiedField, resolveQualifiedField } from './utils/relationship-fields.js';
9
9
  import { segmentFilters } from './utils/segments.js';
10
+ import { selectsAlternateTimeKey } from './utils/dataset-time-keys.js';
10
11
  function resolveField(ds, field) {
11
12
  const dimension = ds.dimensions[field];
12
13
  if (dimension?.sql) {
@@ -62,6 +63,38 @@ function normalizeFilters(ds, filters = []) {
62
63
  * query's dimensions, filters, or orderBy, scoping each joined target with the
63
64
  * runtime tenant predicate when the target declares a `tenantKey`.
64
65
  */
66
+ /**
67
+ * Semantic backends receive a source name, not SQL, so they cannot apply
68
+ * `FINAL`. Running a final dataset there would count unmerged row versions.
69
+ */
70
+ function rejectFinalOnBackend(ds) {
71
+ if (ds.rowResolution) {
72
+ throw new Error(`Dataset "${ds.name}" reads its source with FINAL, which requires the queryBuilder execution path.`);
73
+ }
74
+ }
75
+ /**
76
+ * The frozen plan protocol has no field for enforced constraints. Dropping
77
+ * them would run the call unrestricted, so it is refused instead.
78
+ */
79
+ function rejectConstraintsOnBackend(context) {
80
+ if (runtimeConstraints(context).length > 0) {
81
+ throw new Error('Enforced constraints require the queryBuilder execution path.');
82
+ }
83
+ }
84
+ /**
85
+ * The dataset's row scope as the plan's single tenant predicate. The plan
86
+ * protocol carries at most one, so a wider scope is refused, never truncated.
87
+ */
88
+ function planRowScope(ds, context) {
89
+ const scope = datasetRowScope(ds, context);
90
+ if (scope.length > 1) {
91
+ throw new Error(`Dataset "${ds.name}" has more than one row predicate, which requires the queryBuilder execution path.`);
92
+ }
93
+ if (scope.length === 0)
94
+ return undefined;
95
+ const { column, ...predicate } = scope[0];
96
+ return { field: column, ...predicate };
97
+ }
65
98
  function collectJoins(ds, dimensions = [], filters = [], orderBy = [], context) {
66
99
  const referenced = [
67
100
  ...dimensions,
@@ -71,12 +104,12 @@ function collectJoins(ds, dimensions = [], filters = [], orderBy = [], context)
71
104
  if (referenced.length === 0) {
72
105
  return undefined;
73
106
  }
74
- const tenantPredicate = getRuntimeTenantPredicate(context);
75
107
  const joins = new Map();
76
108
  for (const name of referenced) {
77
109
  const { relationshipName, relationship, target } = resolveQualifiedPlanField(ds, name);
78
110
  if (relationship.keys && relationship.keys.length > 1)
79
111
  throw new Error('Composite relationships require the queryBuilder execution path.');
112
+ rejectFinalOnBackend(target);
80
113
  if (joins.has(relationshipName)) {
81
114
  continue;
82
115
  }
@@ -86,9 +119,7 @@ function collectJoins(ds, dimensions = [], filters = [], orderBy = [], context)
86
119
  from: relationship.from,
87
120
  to: relationship.to,
88
121
  type: 'left',
89
- tenant: tenantPredicate && target.tenantKey
90
- ? { field: target.tenantKey, ...tenantPredicate }
91
- : undefined,
122
+ tenant: planRowScope(target, context),
92
123
  });
93
124
  }
94
125
  return Array.from(joins.values());
@@ -98,6 +129,10 @@ function aggregationForMeasure(ds, name) {
98
129
  if (!measure) {
99
130
  throw new Error(`Unknown measure "${name}" on dataset "${ds.name}".`);
100
131
  }
132
+ if (measure.aggregation === 'merge') {
133
+ throw new Error(`Semantic backend plans do not support merge measure "${name}": it reads ClickHouse aggregate states. ` +
134
+ 'Query it through createDatasetClient({ queryBuilder }).');
135
+ }
101
136
  if (measure.sql) {
102
137
  throw new Error(`Semantic backend plans do not support SQL-backed measure "${name}". ` +
103
138
  'Use a backend-specific query builder for raw SQL expressions.');
@@ -111,13 +146,6 @@ function aggregationForMeasure(ds, name) {
111
146
  filters: normalizeFilters(ds, measure.filters),
112
147
  };
113
148
  }
114
- function tenantForContext(ds, context) {
115
- const tenantPredicate = getRuntimeTenantPredicate(context);
116
- if (!tenantPredicate || !ds.tenantKey) {
117
- return undefined;
118
- }
119
- return { field: ds.tenantKey, ...tenantPredicate };
120
- }
121
149
  function grainForQuery(ds, unit) {
122
150
  if (!unit) {
123
151
  return undefined;
@@ -148,15 +176,19 @@ function aggregatePlan(ds, query, aggregations, context) {
148
176
  orderBy: query.orderBy,
149
177
  limit: query.limit,
150
178
  offset: query.offset,
151
- tenant: tenantForContext(ds, context),
179
+ tenant: planRowScope(ds, context),
152
180
  joins: collectJoins(ds, query.dimensions, query.filters, query.orderBy, context),
153
181
  };
154
182
  }
155
183
  export function buildDatasetPlan(ds, query = {}, context) {
184
+ rejectFinalOnBackend(ds);
185
+ rejectConstraintsOnBackend(context);
156
186
  if ((query.measures ?? []).some(name => name.includes('.')))
157
187
  throw new Error('Relationship measures require the queryBuilder execution path.');
158
188
  if (query.timezone !== undefined)
159
189
  throw new Error('Execution timezone requires the queryBuilder execution path.');
190
+ if (selectsAlternateTimeKey(ds, query.timeKey))
191
+ throw new Error('Alternate time keys require the queryBuilder execution path.');
160
192
  rejectTimeMeasuresOnBackend(ds, query);
161
193
  if ((query.measures ?? []).some(name => getDerivedMeasure(ds.measures, name) !== undefined)) {
162
194
  throw new Error('Derived dataset measures require the queryBuilder execution path.');
@@ -236,6 +268,10 @@ export function buildMetricPlan(metric, query = {}, context) {
236
268
  if (errors.length)
237
269
  throw new Error(`Invalid metric query: ${errors.join('; ')}`);
238
270
  const ref = getMetricRef(metric);
271
+ if (selectsAlternateTimeKey(ref.dataset, query.timeKey))
272
+ throw new Error('Alternate time keys require the queryBuilder execution path.');
273
+ rejectFinalOnBackend(ref.dataset);
274
+ rejectConstraintsOnBackend(context);
239
275
  const grain = getMetricGrain(metric, query);
240
276
  const plannedQuery = { ...query, by: grain };
241
277
  if (ref.spec.__type === 'derived_metric_spec') {
@@ -2,6 +2,7 @@ import { type ZodTypeAny } from 'zod';
2
2
  import { type DatasetCatalog, type DatasetCatalogSource, type MetricCatalogEntry } from './catalog.js';
3
3
  import type { JsonSchema } from './tools.js';
4
4
  import type { ProtocolSchema } from '@hypequery/protocol';
5
+ import type { AnyZodSchema } from './utils/zod-schema-version.js';
5
6
  export interface SemanticQuerySchemaLimits {
6
7
  defaultResultSize?: number;
7
8
  maxResultSize?: number;
@@ -20,6 +21,12 @@ export interface SemanticQuerySchemaOptions extends SemanticQuerySchemaLimits {
20
21
  * protocol does not carry post-aggregation conditions yet.
21
22
  */
22
23
  having?: boolean;
24
+ /**
25
+ * Accept a `timeKey` selection on datasets that declare alternate time axes.
26
+ * Off by default, like `having`: enable it only on surfaces that pass the
27
+ * field through to the dataset client.
28
+ */
29
+ timeKey?: boolean;
23
30
  /** Include Serve's opt-in result metadata flag. */
24
31
  includeMeta?: boolean;
25
32
  /** Require at least one dimension or measure for dataset queries. */
@@ -60,7 +67,7 @@ export interface CanonicalSemanticQuerySchemas {
60
67
  export type SemanticQuerySchemaSource = DatasetCatalogSource | DatasetCatalog;
61
68
  export declare function buildDatasetInputSchema(dataset: SemanticQuerySchemaSource, options?: SemanticQuerySchemaOptions): ZodTypeAny;
62
69
  export declare function buildMetricInputSchema(dataset: SemanticQuerySchemaSource, metricName: string, options?: SemanticQuerySchemaOptions, metricContract?: SemanticMetricQueryContract): ZodTypeAny;
63
- export declare function toSemanticJsonSchema(schema: ZodTypeAny, options?: {
70
+ export declare function toSemanticJsonSchema(schema: AnyZodSchema, options?: {
64
71
  requireSelection?: boolean;
65
72
  }): JsonSchema;
66
73
  export declare function buildCanonicalSemanticQuerySchemas(datasets: Record<string, SemanticQuerySchemaSource>, options?: SemanticQuerySchemaOptions): CanonicalSemanticQuerySchemas;
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-query-schema.d.ts","sourceRoot":"","sources":["../src/semantic-query-schema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAEzC,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAI1D,MAAM,WAAW,yBAAyB;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA2B,SAAQ,yBAAyB;IAC3E,iFAAiF;IACjF,UAAU,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC;IAC5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,gGAAgG;AAChG,MAAM,MAAM,2BAA2B,GAAG,IAAI,CAC5C,kBAAkB,EAClB,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAC9C,CAAC;AAEF,eAAO,MAAM,oCAAoC;;;;;;;EAO/C,CAAC;AAEH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,sBAAsB,EAAE,UAAU,CAAC;IAC5C,QAAQ,CAAC,qBAAqB,EAAE,UAAU,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,oFAAoF;AACpF,MAAM,MAAM,yBAAyB,GAAG,oBAAoB,GAAG,cAAc,CAAC;AA+M9E,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,yBAAyB,EAClC,OAAO,GAAE,0BAA+B,GACvC,UAAU,CASZ;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,yBAAyB,EAClC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,0BAA+B,EACxC,cAAc,CAAC,EAAE,2BAA2B,GAC3C,UAAU,CAcZ;AAsBD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC3C,UAAU,CAMZ;AAyBD,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,EACnD,OAAO,GAAE,0BAA+B,GACvC,6BAA6B,CAgD/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,yBAAyB,EAClC,OAAO,GAAE,0BAA+B,EACxC,IAAI,SAAkB,GACrB,cAAc,CAEhB;AAED,kEAAkE;AAClE,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,yBAAyB,EAClC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,0BAA+B,EACxC,cAAc,CAAC,EAAE,2BAA2B,EAC5C,IAAI,SAAiB,GACpB,cAAc,CAKhB"}
1
+ {"version":3,"file":"semantic-query-schema.d.ts","sourceRoot":"","sources":["../src/semantic-query-schema.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,13 @@
1
1
  import { isQueryTimezone } from './utils/query-timezone.js';
2
- import { sha256 } from '@noble/hashes/sha2';
3
- import { bytesToHex } from '@noble/hashes/utils';
2
+ import { sha256 } from '@noble/hashes/sha2.js';
3
+ import { bytesToHex } from '@noble/hashes/utils.js';
4
4
  import { z } from 'zod';
5
- import { zodToJsonSchema } from 'zod-to-json-schema';
6
5
  import { getDatasetCatalog, getGroupableRelationshipFields, getQueryableRelationshipFields, getQueryableRelationshipMeasures, } from './catalog.js';
7
6
  import { SEMANTIC_FILTER_OPERATORS, SEMANTIC_HAVING_OPERATORS } from './constants.js';
8
7
  import { zodToProtocolSchema } from './protocol-schema-adapter.js';
9
8
  import { compareStrings, stableStringify, uniqueSorted } from './utils/canonical-json.js';
9
+ import { zodToDraft7JsonSchema } from './utils/zod-json-schema.js';
10
+ import { datasetTimeKeys } from './utils/dataset-time-keys.js';
10
11
  export const DEFAULT_SEMANTIC_QUERY_SCHEMA_LIMITS = Object.freeze({
11
12
  maxResultSize: 10_000,
12
13
  maxOffset: 10_000,
@@ -182,6 +183,11 @@ function queryShape(catalog, metricName, options, relationshipOperators, metric,
182
183
  ? z.number().int().nonnegative()
183
184
  : z.number().int().nonnegative().max(limits.maxOffset)).optional(),
184
185
  [grainField]: fieldEnum(grains).optional(),
186
+ // Only datasets with more than one axis accept the field, so every other
187
+ // schema and manifest hash is unchanged.
188
+ ...(options.timeKey && grains.length > 0 && datasetTimeKeys(catalog).length > 1 ? {
189
+ timeKey: fieldEnum(datasetTimeKeys(catalog)).optional().describe(`Time axis for the grain and time-based measures. Defaults to ${catalog.timeKey}.`),
190
+ } : {}),
185
191
  timezone: z.string().max(100).refine(isQueryTimezone, 'Use an IANA timezone such as UTC or America/New_York.').optional(),
186
192
  ...(options.includeMeta ? { includeMeta: z.boolean().optional() } : {}),
187
193
  };
@@ -190,7 +196,7 @@ export function buildDatasetInputSchema(dataset, options = {}) {
190
196
  const schema = z.object(queryShape(resolveCatalog(dataset), undefined, options, relationshipFilterPolicy(dataset))).strict();
191
197
  if (options.requireSelection === false)
192
198
  return schema;
193
- return schema.refine(input => (input.dimensions?.length ?? 0) > 0 || (input.measures?.length ?? 0) > 0, { message: 'At least one dimension or measure must be specified' });
199
+ return requireSelection(schema);
194
200
  }
195
201
  export function buildMetricInputSchema(dataset, metricName, options = {}, metricContract) {
196
202
  const catalog = resolveCatalog(dataset);
@@ -207,16 +213,16 @@ function unionSchemas(schemas, emptyShape) {
207
213
  return schemas[0];
208
214
  return z.union(schemas);
209
215
  }
210
- function withSelectors(schema, selectors, requireSelection) {
211
- const shape = (schema instanceof z.ZodEffects ? schema.innerType() : schema).shape;
212
- const selected = z.object({ ...selectors, ...shape }).strict();
213
- if (!requireSelection)
214
- return selected;
215
- return selected.refine(input => (input.dimensions?.length ?? 0) > 0 || (input.measures?.length ?? 0) > 0, { message: 'At least one dimension or measure must be specified' });
216
+ function requireSelection(schema) {
217
+ return schema.refine((input) => (input.dimensions?.length ?? 0) > 0 || (input.measures?.length ?? 0) > 0, { message: 'At least one dimension or measure must be specified' });
218
+ }
219
+ function withSelectors(schema, selectors, selectionRequired) {
220
+ // Zod 4 keeps refinements on the object itself, so its shape is readable.
221
+ const selected = z.object({ ...selectors, ...schema.shape }).strict();
222
+ return selectionRequired ? requireSelection(selected) : selected;
216
223
  }
217
224
  export function toSemanticJsonSchema(schema, options = {}) {
218
- const converted = zodToJsonSchema(schema, { target: 'jsonSchema7', $refStrategy: 'none' });
219
- const { $schema: _schema, ...jsonSchema } = converted;
225
+ const { $schema: _schema, ...jsonSchema } = zodToDraft7JsonSchema(schema);
220
226
  const result = jsonSchema;
221
227
  const objectSchema = result.anyOf && !result.type ? { ...result, type: 'object' } : result;
222
228
  return options.requireSelection ? addSelectionRequirement(objectSchema) : objectSchema;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/dist/tools.js CHANGED
@@ -2,7 +2,8 @@ import { getDatasetCatalog, } from './catalog.js';
2
2
  import { buildCanonicalSemanticQuerySchemas, buildDatasetInputSchema, buildMetricInputSchema, toSemanticJsonSchema, } from './semantic-query-schema.js';
3
3
  import { parseCanonicalToolInput, redactSemanticToolSql, semanticToolNamePart, } from './utils/semantic-tool.js';
4
4
  function buildCatalogTool(datasets, analytics, includeSql) {
5
- const schemas = buildCanonicalSemanticQuerySchemas(datasets);
5
+ // Parsed input reaches the client whole, so it can carry a selected time axis.
6
+ const schemas = buildCanonicalSemanticQuerySchemas(datasets, { timeKey: true });
6
7
  return {
7
8
  name: 'query_dataset',
8
9
  description: 'Query governed analytics datasets by selecting dimensions, measures, filters, and time grains.',
@@ -17,7 +18,7 @@ function buildCatalogTool(datasets, analytics, includeSql) {
17
18
  }
18
19
  function buildDatasetTools(datasets, analytics, includeSql) {
19
20
  return Object.entries(datasets).map(([datasetName, dataset]) => {
20
- const schema = buildDatasetInputSchema(dataset);
21
+ const schema = buildDatasetInputSchema(dataset, { timeKey: true });
21
22
  return {
22
23
  name: `query_${semanticToolNamePart(datasetName)}`,
23
24
  description: `Query the ${datasetName} analytics dataset.`,
@@ -34,7 +35,7 @@ function buildMetricTools(datasets, analytics, includeSql) {
34
35
  const tools = [];
35
36
  for (const [datasetName, dataset] of Object.entries(datasets)) {
36
37
  for (const [metricName, metric] of Object.entries(dataset.metrics ?? {})) {
37
- const schema = buildMetricInputSchema(dataset, metricName, {}, metric.contract());
38
+ const schema = buildMetricInputSchema(dataset, metricName, { timeKey: true }, metric.contract());
38
39
  tools.push({
39
40
  name: `query_${semanticToolNamePart(metricName)}`,
40
41
  description: `Query the ${metricName} metric from the ${datasetName} dataset.`,