@hypequery/datasets 0.18.0 → 0.20.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 (202) hide show
  1. package/dist/agent-catalog.d.ts +11 -1
  2. package/dist/agent-catalog.d.ts.map +1 -1
  3. package/dist/aggregations.d.ts +2 -0
  4. package/dist/aggregations.d.ts.map +1 -1
  5. package/dist/aggregations.js +4 -0
  6. package/dist/api.type-test.js +57 -0
  7. package/dist/cache/definition-identity.d.ts +26 -0
  8. package/dist/cache/definition-identity.d.ts.map +1 -0
  9. package/dist/cache/definition-identity.js +164 -0
  10. package/dist/cache/protocol-cache-keys.d.ts +38 -0
  11. package/dist/cache/protocol-cache-keys.d.ts.map +1 -0
  12. package/dist/cache/protocol-cache-keys.js +191 -0
  13. package/dist/cache/query-signature.d.ts +6 -0
  14. package/dist/cache/query-signature.d.ts.map +1 -1
  15. package/dist/cache/query-signature.js +27 -13
  16. package/dist/cache/semantic-query-cache.d.ts +23 -0
  17. package/dist/cache/semantic-query-cache.d.ts.map +1 -1
  18. package/dist/catalog.d.ts +14 -2
  19. package/dist/catalog.d.ts.map +1 -1
  20. package/dist/catalog.js +37 -10
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +2 -0
  23. package/dist/contract.d.ts +7 -2
  24. package/dist/contract.d.ts.map +1 -1
  25. package/dist/contract.js +9 -0
  26. package/dist/dataset-query.d.ts.map +1 -1
  27. package/dist/dataset-query.js +27 -5
  28. package/dist/dataset.d.ts +2 -2
  29. package/dist/dataset.d.ts.map +1 -1
  30. package/dist/dataset.js +12 -4
  31. package/dist/executor.d.ts +7 -1
  32. package/dist/executor.d.ts.map +1 -1
  33. package/dist/executor.js +75 -22
  34. package/dist/in-memory-backend.d.ts.map +1 -1
  35. package/dist/in-memory-backend.js +34 -7
  36. package/dist/index.d.ts +8 -6
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3 -2
  39. package/dist/measure.d.ts +17 -2
  40. package/dist/measure.d.ts.map +1 -1
  41. package/dist/measure.js +16 -1
  42. package/dist/portable-execution-errors.d.ts +4 -0
  43. package/dist/portable-execution-errors.d.ts.map +1 -1
  44. package/dist/portable-execution-errors.js +4 -1
  45. package/dist/portable-executor.d.ts.map +1 -1
  46. package/dist/portable-executor.js +6 -3
  47. package/dist/protocol-adapter.d.ts.map +1 -1
  48. package/dist/protocol-adapter.js +25 -8
  49. package/dist/protocol-deployment-adapter.d.ts.map +1 -1
  50. package/dist/protocol-deployment-adapter.js +2 -1
  51. package/dist/protocol-rehydrate.d.ts +5 -1
  52. package/dist/protocol-rehydrate.d.ts.map +1 -1
  53. package/dist/protocol-rehydrate.js +20 -10
  54. package/dist/query-builder-protocol.d.ts +7 -3
  55. package/dist/query-builder-protocol.d.ts.map +1 -1
  56. package/dist/query-planner.d.ts +1 -1
  57. package/dist/query-planner.d.ts.map +1 -1
  58. package/dist/query-planner.js +10 -17
  59. package/dist/relationship-check.d.ts +47 -0
  60. package/dist/relationship-check.d.ts.map +1 -0
  61. package/dist/relationship-check.js +59 -0
  62. package/dist/relationships.d.ts +10 -10
  63. package/dist/relationships.js +10 -10
  64. package/dist/semantic-plan.d.ts +0 -1
  65. package/dist/semantic-plan.d.ts.map +1 -1
  66. package/dist/semantic-planner.d.ts.map +1 -1
  67. package/dist/semantic-planner.js +15 -4
  68. package/dist/semantic-query-schema.d.ts.map +1 -1
  69. package/dist/semantic-query-schema.js +7 -0
  70. package/dist/types.d.ts +99 -18
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/utils/agent-catalog-projection.d.ts +9 -2
  73. package/dist/utils/agent-catalog-projection.d.ts.map +1 -1
  74. package/dist/utils/agent-catalog-projection.js +6 -10
  75. package/dist/utils/approximate-measures.d.ts +10 -0
  76. package/dist/utils/approximate-measures.d.ts.map +1 -0
  77. package/dist/utils/approximate-measures.js +12 -0
  78. package/dist/utils/dataset-contract.d.ts.map +1 -1
  79. package/dist/utils/dataset-contract.js +4 -3
  80. package/dist/utils/dataset-definition-validation.d.ts.map +1 -1
  81. package/dist/utils/dataset-definition-validation.js +6 -24
  82. package/dist/utils/dataset-derived-query.d.ts.map +1 -1
  83. package/dist/utils/dataset-derived-query.js +7 -50
  84. package/dist/utils/dataset-measures.d.ts +13 -6
  85. package/dist/utils/dataset-measures.d.ts.map +1 -1
  86. package/dist/utils/dataset-measures.js +25 -4
  87. package/dist/utils/dataset-metric-ref.d.ts +2 -2
  88. package/dist/utils/dataset-metric-ref.d.ts.map +1 -1
  89. package/dist/utils/dataset-metric-ref.js +5 -0
  90. package/dist/utils/dataset-query-result.d.ts.map +1 -1
  91. package/dist/utils/dataset-query-result.js +2 -1
  92. package/dist/utils/dataset-query-validation.d.ts.map +1 -1
  93. package/dist/utils/dataset-query-validation.js +13 -6
  94. package/dist/utils/dataset-time-grains.d.ts +15 -0
  95. package/dist/utils/dataset-time-grains.d.ts.map +1 -0
  96. package/dist/utils/dataset-time-grains.js +17 -0
  97. package/dist/utils/derived-measure-sql.d.ts +3 -0
  98. package/dist/utils/derived-measure-sql.d.ts.map +1 -0
  99. package/dist/utils/derived-measure-sql.js +46 -0
  100. package/dist/utils/derived-measure-validation.d.ts.map +1 -1
  101. package/dist/utils/derived-measure-validation.js +6 -5
  102. package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -1
  103. package/dist/utils/filtered-aggregation-sql.js +1 -0
  104. package/dist/utils/measure-time-grains.d.ts +4 -0
  105. package/dist/utils/measure-time-grains.d.ts.map +1 -0
  106. package/dist/utils/measure-time-grains.js +16 -0
  107. package/dist/utils/portable-aggregations.d.ts +14 -0
  108. package/dist/utils/portable-aggregations.d.ts.map +1 -0
  109. package/dist/utils/portable-aggregations.js +15 -0
  110. package/dist/utils/portable-grains.d.ts +22 -0
  111. package/dist/utils/portable-grains.d.ts.map +1 -0
  112. package/dist/utils/portable-grains.js +35 -0
  113. package/dist/utils/portable-semantic-query.d.ts.map +1 -1
  114. package/dist/utils/portable-semantic-query.js +2 -1
  115. package/dist/utils/protocol-metric-expressions.d.ts.map +1 -1
  116. package/dist/utils/protocol-metric-expressions.js +2 -1
  117. package/dist/utils/query-timezone.d.ts +9 -0
  118. package/dist/utils/query-timezone.d.ts.map +1 -0
  119. package/dist/utils/query-timezone.js +35 -0
  120. package/dist/utils/relationship-builder-plan.d.ts +6 -3
  121. package/dist/utils/relationship-builder-plan.d.ts.map +1 -1
  122. package/dist/utils/relationship-builder-plan.js +13 -5
  123. package/dist/utils/relationship-key-check.d.ts +43 -0
  124. package/dist/utils/relationship-key-check.d.ts.map +1 -0
  125. package/dist/utils/relationship-key-check.js +72 -0
  126. package/dist/utils/segments.d.ts +31 -0
  127. package/dist/utils/segments.d.ts.map +1 -0
  128. package/dist/utils/segments.js +91 -0
  129. package/dist/utils/semantic-metadata-validation.d.ts.map +1 -1
  130. package/dist/utils/semantic-metadata-validation.js +23 -2
  131. package/dist/utils/semantic-metadata.d.ts.map +1 -1
  132. package/dist/utils/semantic-metadata.js +3 -1
  133. package/dist/utils/shift-measure-definition.d.ts +4 -0
  134. package/dist/utils/shift-measure-definition.d.ts.map +1 -0
  135. package/dist/utils/shift-measure-definition.js +9 -0
  136. package/dist/utils/shift-measure-sql.d.ts +18 -0
  137. package/dist/utils/shift-measure-sql.d.ts.map +1 -0
  138. package/dist/utils/shift-measure-sql.js +46 -0
  139. package/dist/utils/shift-measure-validation.d.ts +3 -0
  140. package/dist/utils/shift-measure-validation.d.ts.map +1 -0
  141. package/dist/utils/shift-measure-validation.js +20 -0
  142. package/dist/utils/sql-under-joins.d.ts +10 -0
  143. package/dist/utils/sql-under-joins.d.ts.map +1 -0
  144. package/dist/utils/sql-under-joins.js +15 -0
  145. package/dist/utils/time-arithmetic-sql.d.ts +4 -0
  146. package/dist/utils/time-arithmetic-sql.d.ts.map +1 -0
  147. package/dist/utils/time-arithmetic-sql.js +9 -0
  148. package/dist/utils/time-axis-bounds.d.ts +24 -0
  149. package/dist/utils/time-axis-bounds.d.ts.map +1 -0
  150. package/dist/utils/time-axis-bounds.js +71 -0
  151. package/dist/utils/time-axis-calendar-guard.d.ts +9 -0
  152. package/dist/utils/time-axis-calendar-guard.d.ts.map +1 -0
  153. package/dist/utils/time-axis-calendar-guard.js +17 -0
  154. package/dist/utils/time-axis-intervals.d.ts +13 -0
  155. package/dist/utils/time-axis-intervals.d.ts.map +1 -0
  156. package/dist/utils/time-axis-intervals.js +81 -0
  157. package/dist/utils/time-measure-axis-sql.d.ts +12 -0
  158. package/dist/utils/time-measure-axis-sql.d.ts.map +1 -0
  159. package/dist/utils/time-measure-axis-sql.js +47 -0
  160. package/dist/utils/time-measure-axis.d.ts +19 -0
  161. package/dist/utils/time-measure-axis.d.ts.map +1 -0
  162. package/dist/utils/time-measure-axis.js +45 -0
  163. package/dist/utils/time-measure-dataset-sql.d.ts +9 -0
  164. package/dist/utils/time-measure-dataset-sql.d.ts.map +1 -0
  165. package/dist/utils/time-measure-dataset-sql.js +63 -0
  166. package/dist/utils/time-measure-result-sql.d.ts +6 -0
  167. package/dist/utils/time-measure-result-sql.d.ts.map +1 -0
  168. package/dist/utils/time-measure-result-sql.js +30 -0
  169. package/dist/utils/time-measure-source-sql.d.ts +22 -0
  170. package/dist/utils/time-measure-source-sql.d.ts.map +1 -0
  171. package/dist/utils/time-measure-source-sql.js +75 -0
  172. package/dist/utils/time-measure-values-sql.d.ts +20 -0
  173. package/dist/utils/time-measure-values-sql.d.ts.map +1 -0
  174. package/dist/utils/time-measure-values-sql.js +87 -0
  175. package/dist/utils/time-query-measures.d.ts +6 -0
  176. package/dist/utils/time-query-measures.d.ts.map +1 -0
  177. package/dist/utils/time-query-measures.js +28 -0
  178. package/dist/utils/unsupported-contract-reasons.d.ts +32 -0
  179. package/dist/utils/unsupported-contract-reasons.d.ts.map +1 -0
  180. package/dist/utils/unsupported-contract-reasons.js +30 -0
  181. package/dist/utils/window-aggregation-sql.d.ts +5 -0
  182. package/dist/utils/window-aggregation-sql.d.ts.map +1 -0
  183. package/dist/utils/window-aggregation-sql.js +17 -0
  184. package/dist/utils/window-catalog-metadata.d.ts +14 -0
  185. package/dist/utils/window-catalog-metadata.d.ts.map +1 -0
  186. package/dist/utils/window-catalog-metadata.js +17 -0
  187. package/dist/utils/window-measure-definition.d.ts +4 -0
  188. package/dist/utils/window-measure-definition.d.ts.map +1 -0
  189. package/dist/utils/window-measure-definition.js +11 -0
  190. package/dist/utils/window-measure-dependencies.d.ts +4 -0
  191. package/dist/utils/window-measure-dependencies.d.ts.map +1 -0
  192. package/dist/utils/window-measure-dependencies.js +5 -0
  193. package/dist/utils/window-measure-validation.d.ts +3 -0
  194. package/dist/utils/window-measure-validation.d.ts.map +1 -0
  195. package/dist/utils/window-measure-validation.js +49 -0
  196. package/dist/utils/window-query-measures.d.ts +4 -0
  197. package/dist/utils/window-query-measures.d.ts.map +1 -0
  198. package/dist/utils/window-query-measures.js +17 -0
  199. package/dist/utils/window-query-signature.d.ts +4 -0
  200. package/dist/utils/window-query-signature.d.ts.map +1 -0
  201. package/dist/utils/window-query-signature.js +25 -0
  202. package/package.json +3 -3
package/dist/executor.js CHANGED
@@ -1,9 +1,13 @@
1
+ import { queryTimezoneErrors, queryTimeFilterSql } from './utils/query-timezone.js';
2
+ import { selectedTimeMeasures, rejectTimeMeasuresOnBackend } from './utils/time-query-measures.js';
3
+ import { buildTimeMeasureDatasetSql } from './utils/time-measure-dataset-sql.js';
4
+ import { baseMeasureNames } from './utils/dataset-measures.js';
1
5
  import { protocolMetricCapabilityErrors } from './utils/protocol-metric-capabilities.js';
2
6
  import { toQueryBuilderFactory } from './query-builder-protocol.js';
3
7
  import { quoteSQLIdentifier, validateSQLIdentifier } from './sql-utils.js';
4
- import { SUPPORTED_TIME_GRAINS, isSupportedTimeGrain } from './constants.js';
8
+ import { unsupportedTimeGrainError } from './utils/dataset-time-grains.js';
5
9
  import { validateFilterValue } from './validation.js';
6
- import { applyAggregationSpec, appendOrderLimitOffset, buildDimensionSelectionPlan, resolveFilterField, resolveTenantFilterColumn, } from './query-planner.js';
10
+ import { applyAggregationSpec, appendOrderLimitOffset, buildDimensionSelectionPlan, resolveDimensionExpression, resolveFilterField, resolveTenantFilterColumn, } from './query-planner.js';
7
11
  import { assertMetricHandle, getMetricGrain, getMetricRef, isTenantScopedFilter, } from './utils/metric-handle.js';
8
12
  import { validateDerivedCteGrouping } from './utils/derived-cte-validation.js';
9
13
  import { buildDatasetQueryBuilder, runDatasetQuery, validateDatasetQuery, } from './dataset-query.js';
@@ -13,14 +17,15 @@ import { getRuntimeTenantId, getRuntimeTenantPredicate, validateTenantRuntime, }
13
17
  import { applyPagination, overfetchLimit } from './utils/pagination.js';
14
18
  import { serializeSemanticMeasureValues } from './utils/semantic-result-serialization.js';
15
19
  import { SemanticQueryCache, } from './cache/semantic-query-cache.js';
16
- import { buildDatasetQuerySignature, buildMetricQuerySignature, } from './cache/query-signature.js';
20
+ import { datasetCacheKey, metricCacheKey, resolveProtocolCacheKeySettings, } from './cache/protocol-cache-keys.js';
17
21
  import { resolveResultLimit, withResultLimit } from './utils/result-limits.js';
18
22
  import { resolveDatasetCacheRuntime, } from './utils/dataset-cache-policy.js';
19
23
  import { isQualifiedField, resolveQualifiedField } from './utils/relationship-fields.js';
20
24
  import { validateQualifiedFilter, validateRelationshipTenantRuntime, } from './utils/relationship-validation.js';
21
25
  import { applyRelationshipJoins, buildRelationshipBuilderContext, qualifyBaseColumn, } from './utils/relationship-builder-plan.js';
26
+ import { segmentFilters, segmentSelectionErrors } from './utils/segments.js';
22
27
  function validateQuery(metric, query, context) {
23
- const errors = protocolMetricCapabilityErrors(metric, query);
28
+ const errors = [...protocolMetricCapabilityErrors(metric, query), ...queryTimezoneErrors(query.timezone)];
24
29
  const ref = getMetricRef(metric);
25
30
  const ds = ref.dataset;
26
31
  const dimensionNames = Object.keys(ds.dimensions);
@@ -97,8 +102,10 @@ function validateQuery(metric, query, context) {
97
102
  errors.push(`Cannot use "by" grain — dataset "${ds.name}" has no timeKey.`);
98
103
  }
99
104
  // Validate grain is one the planner can bucket on
100
- if (query.by && !isSupportedTimeGrain(query.by)) {
101
- errors.push(`Unsupported time grain "${query.by}". Supported: ${SUPPORTED_TIME_GRAINS.join(', ')}`);
105
+ errors.push(...segmentSelectionErrors(ds, query.segments));
106
+ const grainError = query.by && ds.timeKey ? unsupportedTimeGrainError(ds, query.by) : undefined;
107
+ if (grainError) {
108
+ errors.push(grainError);
102
109
  }
103
110
  if (query.limit != null && (!Number.isInteger(query.limit) || query.limit < 0)) {
104
111
  errors.push(`Invalid limit: expected a non-negative integer.`);
@@ -249,7 +256,7 @@ export class MetricQueryEngine {
249
256
  const joinCtx = buildRelationshipBuilderContext(ds, query, context);
250
257
  let qb = activeBuilderFactory.table(ds.source);
251
258
  qb = applyRelationshipJoins(qb, joinCtx);
252
- const { selectParts, groupByParts } = buildDimensionSelectionPlan(ds, query.dimensions ?? [], grain, joinCtx);
259
+ const { selectParts, groupByParts } = buildDimensionSelectionPlan(ds, query.dimensions ?? [], grain, joinCtx, query.timezone);
253
260
  if (selectParts.length > 0) {
254
261
  qb = qb.select(selectParts);
255
262
  }
@@ -271,7 +278,12 @@ export class MetricQueryEngine {
271
278
  throw new Error(`Cannot filter on tenant field "${filter.field}" when runtime tenancy enforcement is active.`);
272
279
  }
273
280
  const resolvedField = resolveFilterField(ds, filter.field, joinCtx);
274
- qb = qb.where(resolvedField, filter.operator, filter.value);
281
+ qb = qb.where(queryTimeFilterSql(ds, filter.field, resolvedField, query.timezone), filter.operator, filter.value);
282
+ }
283
+ // Segments: author-defined, so they resolve dimensions directly rather
284
+ // than through the caller-facing filter allow-list.
285
+ for (const filter of segmentFilters(ds, query.segments)) {
286
+ qb = qb.where(resolveDimensionExpression(ds, filter.field, joinCtx), filter.operator, filter.value);
275
287
  }
276
288
  // Order, limit, offset
277
289
  qb = appendOrderLimitOffset(qb, query.orderBy, grain, query.limit, query.offset, joinCtx);
@@ -284,7 +296,7 @@ export class MetricQueryEngine {
284
296
  // Build the CTE inner query using the builder
285
297
  let cteBuilder = activeBuilderFactory.table(ds.source);
286
298
  cteBuilder = applyRelationshipJoins(cteBuilder, joinCtx);
287
- const { selectParts, groupByParts } = buildDimensionSelectionPlan(ds, query.dimensions ?? [], grain, joinCtx);
299
+ const { selectParts, groupByParts } = buildDimensionSelectionPlan(ds, query.dimensions ?? [], grain, joinCtx, query.timezone);
288
300
  if (selectParts.length > 0) {
289
301
  cteBuilder = cteBuilder.select(selectParts);
290
302
  }
@@ -314,7 +326,10 @@ export class MetricQueryEngine {
314
326
  throw new Error(`Cannot filter on tenant field "${filter.field}" when runtime tenancy enforcement is active.`);
315
327
  }
316
328
  const resolvedField = resolveFilterField(ds, filter.field, joinCtx);
317
- cteBuilder = cteBuilder.where(resolvedField, filter.operator, filter.value);
329
+ cteBuilder = cteBuilder.where(queryTimeFilterSql(ds, filter.field, resolvedField, query.timezone), filter.operator, filter.value);
330
+ }
331
+ for (const filter of segmentFilters(ds, query.segments)) {
332
+ cteBuilder = cteBuilder.where(resolveDimensionExpression(ds, filter.field, joinCtx), filter.operator, filter.value);
318
333
  }
319
334
  const { sql: cteSql, parameters: cteParams } = cteBuilder.toSQLWithParams();
320
335
  const groupingErrors = validateDerivedCteGrouping(cteSql, aggregateAliases, groupByParts);
@@ -368,10 +383,12 @@ export class MetricQueryEngine {
368
383
  }
369
384
  export class DatasetClientImpl extends MetricQueryEngine {
370
385
  backend;
386
+ defaultTimezone;
371
387
  queryCache;
372
388
  cacheEnabledByDefault;
373
389
  cacheDefaults;
374
390
  defaultCacheScope;
391
+ cacheKeySettings;
375
392
  constructor(options) {
376
393
  if (!options.queryBuilder && !options.backend) {
377
394
  throw new Error('createDatasetClient requires either queryBuilder or backend.');
@@ -386,8 +403,16 @@ export class DatasetClientImpl extends MetricQueryEngine {
386
403
  },
387
404
  },
388
405
  });
406
+ const timezoneErrors = queryTimezoneErrors(options.timezone);
407
+ if (timezoneErrors.length)
408
+ throw new Error(timezoneErrors[0]);
409
+ if (options.backend && options.timezone !== undefined) {
410
+ throw new Error('Execution timezone requires the queryBuilder execution path.');
411
+ }
412
+ this.defaultTimezone = options.backend ? undefined : options.timezone ?? 'UTC';
389
413
  this.backend = options.backend;
390
414
  this.queryCache = new SemanticQueryCache(options.cache);
415
+ this.cacheKeySettings = resolveProtocolCacheKeySettings(options.cache ?? {}, options.cache?.store !== undefined);
391
416
  this.cacheEnabledByDefault = (options.cache?.ttlMs ?? 0) > 0;
392
417
  this.defaultCacheScope = options.cache?.scope;
393
418
  // Kept so a dataset's declared ceiling can clamp the client default too; the
@@ -397,6 +422,10 @@ export class DatasetClientImpl extends MetricQueryEngine {
397
422
  staleWhileRevalidateMs: options.cache?.staleWhileRevalidateMs,
398
423
  };
399
424
  }
425
+ withTimezone(query) {
426
+ return query.timezone !== undefined || this.defaultTimezone === undefined
427
+ ? query : { ...query, timezone: this.defaultTimezone };
428
+ }
400
429
  getCacheStats() {
401
430
  return this.queryCache.getStats();
402
431
  }
@@ -436,16 +465,14 @@ export class DatasetClientImpl extends MetricQueryEngine {
436
465
  * `cache.scope` unless the call sets its own, so clients sharing a custom
437
466
  * store can be namespaced apart.
438
467
  */
439
- signatureContext(context) {
440
- if (this.defaultCacheScope === undefined) {
441
- return context;
442
- }
443
- if (context?.cache === false || context?.cache?.scope != null) {
444
- return context;
445
- }
446
- return { ...context, cache: { ...context?.cache, scope: this.defaultCacheScope } };
468
+ /** The call's cache partition: its own `cache.scope`, else the client default. */
469
+ cacheScope(context) {
470
+ if (context?.cache === false)
471
+ return undefined;
472
+ return context?.cache?.scope ?? this.defaultCacheScope;
447
473
  }
448
474
  planMetric(metric, query = {}, context) {
475
+ query = this.withTimezone(query);
449
476
  assertMetricHandle(metric);
450
477
  const validation = validateQuery(metric, query, context);
451
478
  if (!validation.valid) {
@@ -454,21 +481,33 @@ export class DatasetClientImpl extends MetricQueryEngine {
454
481
  return buildMetricPlan(metric, query, context);
455
482
  }
456
483
  planDataset(ds, query = {}, context) {
457
- return buildDatasetPlan(ds, query, context);
484
+ return buildDatasetPlan(ds, this.withTimezone(query), context);
458
485
  }
459
486
  execute(target, query = {}, context) {
487
+ query = this.withTimezone(query);
488
+ if (this.backend && query.timezone !== undefined) {
489
+ throw new Error('Execution timezone requires the queryBuilder execution path.');
490
+ }
460
491
  if (isDatasetInstance(target)) {
461
492
  return this.executeDataset(target, query, context);
462
493
  }
463
494
  return this.executeMetric(target, query, context);
464
495
  }
465
496
  toSQL(target, query = {}, context) {
497
+ query = this.withTimezone(query);
498
+ if (this.backend && query.timezone !== undefined) {
499
+ throw new Error('Execution timezone requires the queryBuilder execution path.');
500
+ }
466
501
  if (isDatasetInstance(target)) {
467
502
  return this.toDatasetSQL(target, query, context);
468
503
  }
469
504
  return super.toSQL(target, query, context);
470
505
  }
471
506
  validate(target, query = {}, context) {
507
+ query = this.withTimezone(query);
508
+ if (this.backend && query.timezone !== undefined) {
509
+ return { valid: false, errors: ['Execution timezone requires the queryBuilder execution path.'] };
510
+ }
472
511
  if (isDatasetInstance(target)) {
473
512
  return validateDatasetQuery(target, query, context);
474
513
  }
@@ -505,7 +544,12 @@ export class DatasetClientImpl extends MetricQueryEngine {
505
544
  if (!validation.valid) {
506
545
  throw new Error(`Invalid metric query: ${validation.errors.join('; ')}`);
507
546
  }
508
- return withResultLimit(this.queryCache.through(buildMetricQuerySignature(metric, boundedQuery, this.signatureContext(cacheRuntime)), run, cacheRuntime?.cache), resultLimit.meta);
547
+ const key = metricCacheKey(this.cacheKeySettings, metric, boundedQuery, cacheRuntime, this.cacheScope(cacheRuntime));
548
+ if (key === undefined) {
549
+ // No portable key for this call (see metricCacheKey): run uncached.
550
+ return withResultLimit(run(), resultLimit.meta);
551
+ }
552
+ return withResultLimit(this.queryCache.through(key, run, cacheRuntime?.cache), resultLimit.meta);
509
553
  }
510
554
  executeDataset(ds, query, context) {
511
555
  const validation = this.validate(ds, query, context);
@@ -519,6 +563,7 @@ export class DatasetClientImpl extends MetricQueryEngine {
519
563
  const cacheRuntime = this.datasetCacheContext(ds, context);
520
564
  const run = () => {
521
565
  if (this.backend) {
566
+ rejectTimeMeasuresOnBackend(ds, boundedQuery);
522
567
  if (hasSelectedDerivedMeasure(ds, boundedQuery)) {
523
568
  throw new Error('Derived dataset measures require the queryBuilder execution path.');
524
569
  }
@@ -526,7 +571,7 @@ export class DatasetClientImpl extends MetricQueryEngine {
526
571
  ...result,
527
572
  data: serializeSemanticMeasureValues(result.data,
528
573
  // Same measures either way; boundedQuery differs only in `limit`.
529
- boundedQuery.measures ?? Object.keys(ds.measures)),
574
+ boundedQuery.measures ?? baseMeasureNames(ds.measures)),
530
575
  }));
531
576
  }
532
577
  return runDatasetQuery(ds, boundedQuery, {
@@ -539,7 +584,12 @@ export class DatasetClientImpl extends MetricQueryEngine {
539
584
  }
540
585
  // Annotated outside the cache: the ceiling is derived from the query, not
541
586
  // from the rows, so it must not be stored in or read back from an entry.
542
- return withResultLimit(this.queryCache.through(buildDatasetQuerySignature(ds, boundedQuery, this.signatureContext(cacheRuntime)), run, cacheRuntime?.cache), resultLimit.meta);
587
+ const key = datasetCacheKey(this.cacheKeySettings, ds, boundedQuery, cacheRuntime, this.cacheScope(cacheRuntime));
588
+ if (key === undefined) {
589
+ // No portable key for this call (see datasetCacheKey): run uncached.
590
+ return withResultLimit(run(), resultLimit.meta);
591
+ }
592
+ return withResultLimit(this.queryCache.through(key, run, cacheRuntime?.cache), resultLimit.meta);
543
593
  }
544
594
  /**
545
595
  * Folds the dataset's declared cache policy into the call's context, so both
@@ -554,6 +604,9 @@ export class DatasetClientImpl extends MetricQueryEngine {
554
604
  }
555
605
  toDatasetSQL(ds, query, context) {
556
606
  const builderFactory = resolveBuilderFactory(context, this.getBuilderFactory());
607
+ if (selectedTimeMeasures(ds, query).size) {
608
+ return buildTimeMeasureDatasetSql(ds, query, { builderFactory, context }).sql;
609
+ }
557
610
  if (hasSelectedDerivedMeasure(ds, query)) {
558
611
  return buildDerivedDatasetSql(ds, query, { builderFactory, context }, buildDatasetQueryBuilder).sql;
559
612
  }
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory-backend.d.ts","sourceRoot":"","sources":["../src/in-memory-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AA0T3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAwE7E"}
1
+ {"version":3,"file":"in-memory-backend.d.ts","sourceRoot":"","sources":["../src/in-memory-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAuV3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAwE7E"}
@@ -48,7 +48,12 @@ function applyTenant(rows, tenant) {
48
48
  /**
49
49
  * Enriches base rows with columns from to-one joined targets, keyed by the
50
50
  * qualified name `<relationship>.<column>`. Mirrors a query-time LEFT JOIN:
51
- * base rows without a matching target keep the joined columns undefined.
51
+ * base rows without a matching target keep the joined columns undefined, and
52
+ * NULL keys never match.
53
+ *
54
+ * A duplicate target key means the relationship is not really to-one. Rather
55
+ * than silently picking one of the matches, the join is refused so the
56
+ * mis-declaration surfaces in tests.
52
57
  */
53
58
  function applyJoins(rows, joins, tables) {
54
59
  if (!joins || joins.length === 0) {
@@ -58,18 +63,24 @@ function applyJoins(rows, joins, tables) {
58
63
  const targetRows = applyTenant(tables[join.source] ?? [], join.tenant);
59
64
  const index = new Map();
60
65
  for (const row of targetRows) {
61
- const key = String(row[join.to]);
62
- // To-one: first matching target wins; a mis-declared to-many still won't fan out.
63
- if (!index.has(key)) {
64
- index.set(key, row);
66
+ const value = row[join.to];
67
+ if (value == null) {
68
+ continue;
69
+ }
70
+ const key = String(value);
71
+ if (index.has(key)) {
72
+ throw new Error(`Relationship "${join.relationship}" is declared to-one, but "${join.source}.${join.to}" ` +
73
+ `has more than one row with key ${JSON.stringify(key)}. Declare it as hasMany or make the key unique.`);
65
74
  }
75
+ index.set(key, row);
66
76
  }
67
77
  return { join, index };
68
78
  });
69
79
  return rows.map((row) => {
70
80
  const enriched = { ...row };
71
81
  for (const { join, index } of indexes) {
72
- const match = index.get(String(row[join.from]));
82
+ const key = row[join.from];
83
+ const match = key == null ? undefined : index.get(String(key));
73
84
  if (match) {
74
85
  for (const [column, value] of Object.entries(match)) {
75
86
  enriched[`${join.relationship}.${column}`] = value;
@@ -84,6 +95,20 @@ function periodForValue(value, grain) {
84
95
  if (Number.isNaN(date.getTime())) {
85
96
  return String(value);
86
97
  }
98
+ // Sub-day buckets keep their time of day, in the form a ClickHouse DateTime
99
+ // takes in JSON (RFC 0015).
100
+ if (grain.unit === 'minute' || grain.unit === 'hour') {
101
+ // ClickHouse DateTime strings have no offset. Keep their wall-clock hour
102
+ // instead of interpreting them in the Node process's local time zone.
103
+ const naive = typeof value === 'string'
104
+ ? /^(\d{4}-\d{2}-\d{2})[ T](\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?$/.exec(value)
105
+ : null;
106
+ if (naive) {
107
+ return `${naive[1]} ${naive[2]}:${grain.unit === 'hour' ? '00' : naive[3]}:00`;
108
+ }
109
+ const iso = date.toISOString();
110
+ return `${iso.slice(0, 10)} ${grain.unit === 'hour' ? `${iso.slice(11, 13)}:00` : iso.slice(11, 16)}:00`;
111
+ }
87
112
  if (grain.unit === 'year') {
88
113
  return `${date.getUTCFullYear()}-01-01`;
89
114
  }
@@ -172,8 +197,10 @@ function aggregateRows(rows, aggregation) {
172
197
  return values.reduce((total, value) => total + Number(value ?? 0), 0);
173
198
  case 'count':
174
199
  return filteredRows.length;
200
+ // Exact computation is a faithful approxCountDistinct (RFC 0015).
175
201
  case 'countDistinct':
176
- return new Set(values).size;
202
+ case 'approxCountDistinct':
203
+ return new Set(values.filter(value => value != null)).size;
177
204
  case 'avg':
178
205
  return values.length === 0
179
206
  ? 0
package/dist/index.d.ts CHANGED
@@ -2,7 +2,9 @@ export { dataset } from './dataset.js';
2
2
  export { dimension } from './field.js';
3
3
  export { measure } from './measure.js';
4
4
  export { belongsTo, hasMany, hasOne } from './relationships.js';
5
- export { sum, count, countDistinct, avg, min, max, percentile, median, argMax, argMin, stddev, variance } from './aggregations.js';
5
+ export { checkRelationships } from './relationship-check.js';
6
+ export type { CheckRelationshipsOptions, CheckRelationshipsResult, RelationshipKeyIssue, } from './relationship-check.js';
7
+ export { sum, count, countDistinct, approxCountDistinct, avg, min, max, percentile, median, argMax, argMin, stddev, variance, } from './aggregations.js';
6
8
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
7
9
  export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
8
10
  export { createDatasetRegistry } from './registry.js';
@@ -11,12 +13,12 @@ export type { DatasetPublisher } from './publishing/publisher.js';
11
13
  export type { PublishableMetric, PublishedMetricHandle, PublishedMetricMap, PublishedMetrics, PublishedDataset, PublishedDatasetRegistry, PublishDatasetOptions, } from './publishing/types.js';
12
14
  export { getDatasetCatalog, getDatasetCatalogs, getQueryableRelationshipFields } from './catalog.js';
13
15
  export { listQueryableRelationshipFields } from './utils/relationship-fields.js';
14
- export type { DatasetCatalog, DatasetCatalogMap, DatasetCatalogSource, DimensionCatalogEntry, MeasureCatalogEntry, MetricCatalogEntry, FilterCatalogEntry, RelationshipCatalogEntry, } from './catalog.js';
16
+ export type { DatasetCatalog, DatasetCatalogMap, DatasetCatalogSource, DimensionCatalogEntry, MeasureCatalogEntry, SegmentCatalogEntry, MetricCatalogEntry, FilterCatalogEntry, RelationshipCatalogEntry, } from './catalog.js';
15
17
  export { DEFAULT_AGENT_CATALOG_MAX_BYTES, assertAgentSafeCatalogBudget, projectAgentSafeCatalog, projectTrustedDebugCatalog, } from './agent-catalog.js';
16
- export type { AgentCatalogDataset, AgentCatalogDatasetRegistry, AgentCatalogProjectionOptions, AgentCatalogDimension, AgentCatalogFilter, AgentCatalogMeasure, AgentCatalogMetric, AgentCatalogRelationship, AgentCatalogSource, AgentSafeCatalog, TrustedDebugCatalog, TrustedDebugCatalogAuthorization, } from './agent-catalog.js';
18
+ export type { AgentCatalogDataset, AgentCatalogDatasetRegistry, AgentCatalogProjectionOptions, AgentCatalogDimension, AgentCatalogFilter, AgentCatalogMeasure, AgentCatalogSegment, AgentCatalogMetric, AgentCatalogRelationship, AgentCatalogSource, AgentSafeCatalog, TrustedDebugCatalog, TrustedDebugCatalogAuthorization, } from './agent-catalog.js';
17
19
  export { serializeSemanticContract, contractToStableJson, hashContract, SEMANTIC_CONTRACT_VERSION, } from './contract.js';
18
- export { rehydrateProtocolDatasets, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
19
- export type { RehydratedDataset, RehydrateProtocolDatasetsOptions, } from './protocol-rehydrate.js';
20
+ export { rehydrateProtocolDatasets, UNSUPPORTED_CONTRACT_REASONS, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
21
+ export type { RehydratedDataset, RehydrateProtocolDatasetsOptions, UnsupportedContractReason, } from './protocol-rehydrate.js';
20
22
  export { buildProtocolDatasetContract } from './protocol-adapter.js';
21
23
  export { buildProtocolDeploymentContract } from './protocol-deployment-adapter.js';
22
24
  export type { BuildProtocolDeploymentContractOptions } from './protocol-deployment-adapter.js';
@@ -47,6 +49,6 @@ export type { QueryBuilderLike, QueryBuilderFactoryLike, QueryBuilderFactoryComp
47
49
  export { toQueryBuilderFactory } from './query-builder-protocol.js';
48
50
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
49
51
  export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SUPPORTED_TIME_GRAINS } from './constants.js';
50
- export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, DatasetMeasureDefinition, DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetDefaults, DatasetFreshness, DatasetLimits, DatasetCachePolicy, SemanticMetadata, SemanticSensitivity, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetQueryableDimensions, DatasetMeasureNames, DatasetOrderableNames, DatasetQueryFor, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
52
+ export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, MeasureTimeInterval, WindowMeasureDefinition, ShiftMeasureDefinition, DatasetMeasureDefinition, DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SegmentDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetDefaults, DatasetFreshness, DatasetLimits, DatasetCachePolicy, SemanticMetadata, SemanticSensitivity, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetQueryableDimensions, DatasetMeasureNames, DatasetSegmentNames, DatasetOrderableNames, DatasetQueryFor, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
51
53
  export { ProtocolSchemaAdapterError, zodToProtocolSchema } from './protocol-schema-adapter.js';
52
54
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGnI,OAAO,EACL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAC/B,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,KAAK,EAAE,IAAI,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAChC,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,KAAK,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjF,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,6BAA6B,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,gCAAgC,GACjC,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,iBAAiB,EACjB,gCAAgC,GACjC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,YAAY,EAAE,sCAAsC,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,EAAE,mCAAmC,EAAE,MAAM,yBAAyB,CAAC;AAC9E,YAAY,EAAE,mCAAmC,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,sBAAsB,EACtB,8BAA8B,EAC9B,+BAA+B,GAChC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,gBAAgB,EAChB,gCAAgC,EAChC,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,UAAU,GACX,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;AACpC,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,2BAA2B,EAC3B,UAAU,EACV,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGnG,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,yBAAyB,EACzB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAC7D,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GACrD,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAC/B,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,KAAK,EAAE,IAAI,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAChC,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,KAAK,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjF,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,6BAA6B,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,gCAAgC,GACjC,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,iBAAiB,EACjB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,YAAY,EAAE,sCAAsC,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,EAAE,mCAAmC,EAAE,MAAM,yBAAyB,CAAC;AAC9E,YAAY,EAAE,mCAAmC,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,EACL,8BAA8B,EAC9B,4BAA4B,EAC5B,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,sBAAsB,EACtB,8BAA8B,EAC9B,+BAA+B,GAChC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,gBAAgB,EAChB,gCAAgC,EAChC,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,UAAU,GACX,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;AACpC,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,2BAA2B,EAC3B,UAAU,EACV,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGhG,OAAO,EAAE,eAAe,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGnG,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,yBAAyB,EACzB,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/index.js CHANGED
@@ -6,8 +6,9 @@ export { dimension } from './field.js';
6
6
  export { measure } from './measure.js';
7
7
  // Relationship helpers
8
8
  export { belongsTo, hasMany, hasOne } from './relationships.js';
9
+ export { checkRelationships } from './relationship-check.js';
9
10
  // Aggregation helpers
10
- export { sum, count, countDistinct, avg, min, max, percentile, median, argMax, argMin, stddev, variance } from './aggregations.js';
11
+ export { sum, count, countDistinct, approxCountDistinct, avg, min, max, percentile, median, argMax, argMin, stddev, variance, } from './aggregations.js';
11
12
  // Formula helpers
12
13
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
13
14
  // Semantic query helpers
@@ -24,7 +25,7 @@ export { DEFAULT_AGENT_CATALOG_MAX_BYTES, assertAgentSafeCatalogBudget, projectA
24
25
  // Semantic contract (stable, hashable export for snapshots/diffs/validation)
25
26
  export { serializeSemanticContract, contractToStableJson, hashContract, SEMANTIC_CONTRACT_VERSION, } from './contract.js';
26
27
  // Portable deployment contract adapter
27
- export { rehydrateProtocolDatasets, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
28
+ export { rehydrateProtocolDatasets, UNSUPPORTED_CONTRACT_REASONS, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
28
29
  export { buildProtocolDatasetContract } from './protocol-adapter.js';
29
30
  export { buildProtocolDeploymentContract } from './protocol-deployment-adapter.js';
30
31
  export { rehydrateProtocolDeploymentContract } from './protocol-rehydrate.js';
package/dist/measure.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import type { DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, MeasureDefinition, MeasureOptions } from './types.js';
1
+ import { type ShiftMeasureOptions } from './utils/shift-measure-definition.js';
2
+ import type { DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, MeasureDefinition, MeasureOptions, MeasureTimeInterval, TimeGrain, WindowMeasureDefinition, ShiftMeasureDefinition } from './types.js';
3
+ import { type WindowMeasureOptions } from './utils/window-measure-definition.js';
2
4
  export declare function validatePercentileLevel(level: number): void;
3
5
  declare function createPercentileMeasure(field: string, level: number, opts?: MeasureOptions): MeasureDefinition;
4
6
  declare function createDerivedMeasure<const TUses extends DerivedMeasureUses>(options: DerivedMeasureOptions<TUses>): DerivedMeasureDefinition<TUses>;
@@ -6,6 +8,11 @@ export declare const measure: {
6
8
  readonly sum: (field: string, opts?: MeasureOptions) => MeasureDefinition;
7
9
  readonly count: (field: string, opts?: MeasureOptions) => MeasureDefinition;
8
10
  readonly countDistinct: (field: string, opts?: MeasureOptions) => MeasureDefinition;
11
+ /**
12
+ * Estimated number of distinct values (ClickHouse `uniq`). Uses bounded
13
+ * memory on high-cardinality columns; catalogs mark it `approximate`.
14
+ */
15
+ readonly approxCountDistinct: (field: string, opts?: MeasureOptions) => MeasureDefinition;
9
16
  readonly avg: (field: string, opts?: MeasureOptions) => MeasureDefinition;
10
17
  readonly min: (field: string, opts?: MeasureOptions) => MeasureDefinition;
11
18
  readonly max: (field: string, opts?: MeasureOptions) => MeasureDefinition;
@@ -26,8 +33,16 @@ export declare const measure: {
26
33
  readonly stddev: (field: string, opts?: MeasureOptions) => MeasureDefinition;
27
34
  /** Sample variance (ClickHouse `varSamp`). */
28
35
  readonly variance: (field: string, opts?: MeasureOptions) => MeasureDefinition;
29
- /** A formula over base measures owned by this dataset. */
36
+ /** A formula over base, window, or shifted measures owned by this dataset. */
30
37
  readonly derived: typeof createDerivedMeasure;
38
+ /** Evaluate a base measure in an earlier aligned period. */
39
+ readonly shift: <const TMeasureName extends string>(baseMeasure: TMeasureName, interval: MeasureTimeInterval, options?: ShiftMeasureOptions) => ShiftMeasureDefinition<TMeasureName>;
40
+ /** Re-aggregate rows over a trailing interval of whole query buckets. */
41
+ readonly trailing: <const TMeasureName extends string>(baseMeasure: TMeasureName, interval: MeasureTimeInterval, options?: WindowMeasureOptions) => WindowMeasureDefinition<TMeasureName>;
42
+ /** Re-aggregate rows from the enclosing period's start through each bucket. */
43
+ readonly toDate: <const TMeasureName extends string>(baseMeasure: TMeasureName, grain: Exclude<TimeGrain, "minute">, options?: WindowMeasureOptions) => WindowMeasureDefinition<TMeasureName>;
44
+ /** Running sum/count/minimum/maximum over all rows through each bucket. */
45
+ readonly cumulative: <const TMeasureName extends string>(baseMeasure: TMeasureName, options?: WindowMeasureOptions) => WindowMeasureDefinition<TMeasureName>;
31
46
  };
32
47
  export {};
33
48
  //# sourceMappingURL=measure.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EAEf,MAAM,YAAY,CAAC;AAiBpB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI3D;AAqBD,iBAAS,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAcvG;AAED,iBAAS,oBAAoB,CAAC,KAAK,CAAC,KAAK,SAAS,kBAAkB,EAClE,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,GACpC,wBAAwB,CAAC,KAAK,CAAC,CASjC;AAED,eAAO,MAAM,OAAO;0BAnEH,MAAM,SAAS,cAAc,KAAG,iBAAiB;4BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;oCAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;IA0EhE,gFAAgF;;IAEhF,mDAAmD;6BACnC,MAAM,SAAS,cAAc,KAAG,iBAAiB;IAEjE;;;;;OAKG;6BAhEY,MAAM,MAAM,MAAM,SAAS,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,KAAG,iBAAiB;IAkE7F,gFAAgF;6BAlEjE,MAAM,MAAM,MAAM,SAAS,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,KAAG,iBAAiB;IAoE7F,2DAA2D;6BAxF5C,MAAM,SAAS,cAAc,KAAG,iBAAiB;IA0FhE,8CAA8C;+BA1F/B,MAAM,SAAS,cAAc,KAAG,iBAAiB;IA4FhE,0DAA0D;;CAElD,CAAC"}
1
+ {"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AACnG,OAAO,KAAK,EACV,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EAEd,mBAAmB,EACnB,SAAS,EACT,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAgBtG,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI3D;AAqBD,iBAAS,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAcvG;AAED,iBAAS,oBAAoB,CAAC,KAAK,CAAC,KAAK,SAAS,kBAAkB,EAClE,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,GACpC,wBAAwB,CAAC,KAAK,CAAC,CASjC;AAED,eAAO,MAAM,OAAO;0BAnEH,MAAM,SAAS,cAAc,KAAG,iBAAiB;4BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;oCAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;IAuEhE;;;OAGG;0CA1EY,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;0BAAjD,MAAM,SAAS,cAAc,KAAG,iBAAiB;IA+EhE,gFAAgF;;IAEhF,mDAAmD;6BACnC,MAAM,SAAS,cAAc,KAAG,iBAAiB;IAEjE;;;;;OAKG;6BArEY,MAAM,MAAM,MAAM,SAAS,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,KAAG,iBAAiB;IAuE7F,gFAAgF;6BAvEjE,MAAM,MAAM,MAAM,SAAS,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,KAAG,iBAAiB;IAyE7F,2DAA2D;6BA7F5C,MAAM,SAAS,cAAc,KAAG,iBAAiB;IA+FhE,8CAA8C;+BA/F/B,MAAM,SAAS,cAAc,KAAG,iBAAiB;IAiGhE,8EAA8E;;IAE9E,4DAA4D;2BAC9C,YAAY,SAAS,MAAM,eAAe,YAAY,YAAY,mBAAmB,YAAY,mBAAmB,KAAG,sBAAsB,CAAC,YAAY,CAAC;IAEzK,yEAAyE;8BACxD,YAAY,SAAS,MAAM,eAAe,YAAY,YAAY,mBAAmB,YAAY,oBAAoB,KAAG,uBAAuB,CAAC,YAAY,CAAC;IAE9K,+EAA+E;4BAChE,YAAY,SAAS,MAAM,eAAe,YAAY,SAAS,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,YAAY,oBAAoB,KAAG,uBAAuB,CAAC,YAAY,CAAC;IAElL,2EAA2E;gCACxD,YAAY,SAAS,MAAM,eAAe,YAAY,YAAY,oBAAoB,KAAG,uBAAuB,CAAC,YAAY,CAAC;CAEzI,CAAC"}
package/dist/measure.js CHANGED
@@ -1,4 +1,6 @@
1
+ import { createShiftMeasure } from './utils/shift-measure-definition.js';
1
2
  import { snapshotSemanticMetadata } from './utils/semantic-metadata.js';
3
+ import { createWindowMeasure } from './utils/window-measure-definition.js';
2
4
  function createMeasureHelper(aggregation) {
3
5
  return (field, opts) => ({
4
6
  __type: 'measure_definition',
@@ -64,6 +66,11 @@ export const measure = {
64
66
  sum: createMeasureHelper('sum'),
65
67
  count: createMeasureHelper('count'),
66
68
  countDistinct: createMeasureHelper('countDistinct'),
69
+ /**
70
+ * Estimated number of distinct values (ClickHouse `uniq`). Uses bounded
71
+ * memory on high-cardinality columns; catalogs mark it `approximate`.
72
+ */
73
+ approxCountDistinct: createMeasureHelper('approxCountDistinct'),
67
74
  avg: createMeasureHelper('avg'),
68
75
  min: createMeasureHelper('min'),
69
76
  max: createMeasureHelper('max'),
@@ -84,6 +91,14 @@ export const measure = {
84
91
  stddev: createMeasureHelper('stddev'),
85
92
  /** Sample variance (ClickHouse `varSamp`). */
86
93
  variance: createMeasureHelper('variance'),
87
- /** A formula over base measures owned by this dataset. */
94
+ /** A formula over base, window, or shifted measures owned by this dataset. */
88
95
  derived: createDerivedMeasure,
96
+ /** Evaluate a base measure in an earlier aligned period. */
97
+ shift: (baseMeasure, interval, options) => createShiftMeasure(baseMeasure, interval, options),
98
+ /** Re-aggregate rows over a trailing interval of whole query buckets. */
99
+ trailing: (baseMeasure, interval, options) => createWindowMeasure(baseMeasure, { trailing: { ...interval } }, options),
100
+ /** Re-aggregate rows from the enclosing period's start through each bucket. */
101
+ toDate: (baseMeasure, grain, options) => createWindowMeasure(baseMeasure, { toDate: grain }, options),
102
+ /** Running sum/count/minimum/maximum over all rows through each bucket. */
103
+ cumulative: (baseMeasure, options) => createWindowMeasure(baseMeasure, { cumulative: true }, options),
89
104
  };
@@ -1,3 +1,4 @@
1
+ import type { UnsupportedContractReason } from './utils/unsupported-contract-reasons.js';
1
2
  /**
2
3
  * An error that deliberately claims a portable failure category.
3
4
  *
@@ -25,8 +26,11 @@ declare abstract class PortableExecutionError extends Error {
25
26
  export declare class PortableExecutionUnsupportedError extends PortableExecutionError {
26
27
  readonly code = "HQ_SEMANTIC_UNSUPPORTED_CAPABILITY";
27
28
  readonly category = "unsupported-capability";
29
+ /** Which excluded surface this is; see `UNSUPPORTED_CONTRACT_REASONS`. */
30
+ readonly reason: UnsupportedContractReason | undefined;
28
31
  constructor(message: string, options?: {
29
32
  cause?: unknown;
33
+ reason?: UnsupportedContractReason;
30
34
  });
31
35
  }
32
36
  export declare class PortableExecutionBudgetError extends PortableExecutionError {
@@ -1 +1 @@
1
- {"version":3,"file":"portable-execution-errors.d.ts","sourceRoot":"","sources":["../src/portable-execution-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,uBAAe,sBAAuB,SAAQ,KAAK;IACjD,wEAAwE;IACxE,QAAQ,CAAC,wBAAwB,EAAG,IAAI,CAAU;IAClD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CACpC;AAED,0EAA0E;AAC1E,qBAAa,iCAAkC,SAAQ,sBAAsB;IAC3E,QAAQ,CAAC,IAAI,wCAAwC;IACrD,QAAQ,CAAC,QAAQ,4BAA4B;gBAEjC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAI/D;AAED,qBAAa,4BAA6B,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,QAAQ,qBAAqB;gBAE1B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,qBAAa,4BAA6B,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,IAAI,sCAAsC;IACnD,QAAQ,CAAC,QAAQ,2BAA2B;gBAEhC,OAAO,EAAE,MAAM;CAI5B"}
1
+ {"version":3,"file":"portable-execution-errors.d.ts","sourceRoot":"","sources":["../src/portable-execution-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AAEzF;;;;;;;;;;;;;;;;GAgBG;AACH,uBAAe,sBAAuB,SAAQ,KAAK;IACjD,wEAAwE;IACxE,QAAQ,CAAC,wBAAwB,EAAG,IAAI,CAAU;IAClD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CACpC;AAED,0EAA0E;AAC1E,qBAAa,iCAAkC,SAAQ,sBAAsB;IAC3E,QAAQ,CAAC,IAAI,wCAAwC;IACrD,QAAQ,CAAC,QAAQ,4BAA4B;IAC7C,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,yBAAyB,GAAG,SAAS,CAAC;gBAGrD,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,yBAAyB,CAAA;KAAO;CAMxE;AAED,qBAAa,4BAA6B,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,QAAQ,qBAAqB;gBAE1B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,qBAAa,4BAA6B,SAAQ,sBAAsB;IACtE,QAAQ,CAAC,IAAI,sCAAsC;IACnD,QAAQ,CAAC,QAAQ,2BAA2B;gBAEhC,OAAO,EAAE,MAAM;CAI5B"}
@@ -23,9 +23,12 @@ class PortableExecutionError extends Error {
23
23
  export class PortableExecutionUnsupportedError extends PortableExecutionError {
24
24
  code = 'HQ_SEMANTIC_UNSUPPORTED_CAPABILITY';
25
25
  category = 'unsupported-capability';
26
+ /** Which excluded surface this is; see `UNSUPPORTED_CONTRACT_REASONS`. */
27
+ reason;
26
28
  constructor(message, options = {}) {
27
- super(message, options);
29
+ super(message, options.cause === undefined ? {} : { cause: options.cause });
28
30
  this.name = 'PortableExecutionUnsupportedError';
31
+ this.reason = options.reason;
29
32
  }
30
33
  }
31
34
  export class PortableExecutionBudgetError extends PortableExecutionError {
@@ -1 +1 @@
1
- {"version":3,"file":"portable-executor.d.ts","sourceRoot":"","sources":["../src/portable-executor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iCAAiC,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAK/I;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,gCAAgC,EAChC,qBAAqB,EACtB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAA;KAAE,CAAC;IACjF,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,yEAAyE;IACzE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,YAAY,EAAE,wBAAwB,CAAC;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAID;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,CAAC,KAAK,EAAE,8BAA8B,KAAK,OAAO,CAAC,gCAAgC,CAAC,CAwEtF"}
1
+ {"version":3,"file":"portable-executor.d.ts","sourceRoot":"","sources":["../src/portable-executor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iCAAiC,EAAE,4BAA4B,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAK/I;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,gCAAgC,EAChC,qBAAqB,EACtB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAA;KAAE,CAAC;IACjF,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,yEAAyE;IACzE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,YAAY,EAAE,wBAAwB,CAAC;IAChD;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAID;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,CAAC,KAAK,EAAE,8BAA8B,KAAK,OAAO,CAAC,gCAAgC,CAAC,CA4EtF"}
@@ -4,7 +4,7 @@ import { tenantRuntime, semanticQuery } from './utils/portable-semantic-query.js
4
4
  import { bounded } from './utils/portable-result-budget.js';
5
5
  import { withDeadline } from './utils/portable-execution-deadline.js';
6
6
  import { createDatasetClient } from './executor.js';
7
- import { rehydrateProtocolDatasets, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
7
+ import { rehydrateProtocolDatasets, UNSUPPORTED_CONTRACT_REASONS, UnsupportedContractFeatureError, } from './protocol-rehydrate.js';
8
8
  /**
9
9
  * Build the executor the deployment data plane injects.
10
10
  *
@@ -26,7 +26,10 @@ export function createPortableSemanticExecutor(options) {
26
26
  if (error instanceof UnsupportedContractFeatureError) {
27
27
  // Decision 0005: a surface portable execution cannot reproduce is
28
28
  // excluded from it, never approximated.
29
- throw new PortableExecutionUnsupportedError(error.message, { cause: error });
29
+ throw new PortableExecutionUnsupportedError(error.message, {
30
+ cause: error,
31
+ ...(error.reason === undefined ? {} : { reason: error.reason }),
32
+ });
30
33
  }
31
34
  throw error;
32
35
  }
@@ -37,7 +40,7 @@ export function createPortableSemanticExecutor(options) {
37
40
  const registry = registryFor(input);
38
41
  const rebuilt = registry[String(input.dataset.name)];
39
42
  if (rebuilt === undefined) {
40
- throw new PortableExecutionUnsupportedError(`Dataset "${String(input.dataset.name)}" is not part of the activated contract.`);
43
+ throw new PortableExecutionUnsupportedError(`Dataset "${String(input.dataset.name)}" is not part of the activated contract.`, { reason: UNSUPPORTED_CONTRACT_REASONS.datasetNotActivated });
41
44
  }
42
45
  const target = rebuilt;
43
46
  const tenant = tenantRuntime(input.tenant);
@@ -1 +1 @@
1
- {"version":3,"file":"protocol-adapter.d.ts","sourceRoot":"","sources":["../src/protocol-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,uBAAuB,EAE5B,KAAK,sBAAsB,EAG5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,kBAAkB,EAElB,YAAY,EAEb,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC;CAC7E;AAsFD;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,GAAE,mCAAwC,GAChD,uBAAuB,CAiHzB"}
1
+ {"version":3,"file":"protocol-adapter.d.ts","sourceRoot":"","sources":["../src/protocol-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,uBAAuB,EAE5B,KAAK,sBAAsB,EAI5B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,kBAAkB,EAElB,YAAY,EAEb,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC;CAC7E;AAuFD;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,GAAE,mCAAwC,GAChD,uBAAuB,CAmIzB"}