@hypequery/datasets 0.13.5 → 0.14.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 (113) hide show
  1. package/README.md +10 -0
  2. package/dist/agent-catalog.d.ts +97 -0
  3. package/dist/agent-catalog.d.ts.map +1 -0
  4. package/dist/agent-catalog.js +79 -0
  5. package/dist/api.type-test.js +19 -1
  6. package/dist/catalog.d.ts +17 -6
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/catalog.js +18 -1
  9. package/dist/contract.d.ts +11 -7
  10. package/dist/contract.d.ts.map +1 -1
  11. package/dist/contract.js +22 -1
  12. package/dist/dataset-query.d.ts.map +1 -1
  13. package/dist/dataset-query.js +9 -3
  14. package/dist/dataset.d.ts.map +1 -1
  15. package/dist/dataset.js +19 -2
  16. package/dist/executor.d.ts +6 -0
  17. package/dist/executor.d.ts.map +1 -1
  18. package/dist/executor.js +83 -24
  19. package/dist/field.d.ts.map +1 -1
  20. package/dist/field.js +2 -0
  21. package/dist/in-memory-backend.d.ts.map +1 -1
  22. package/dist/in-memory-backend.js +2 -17
  23. package/dist/index.d.ts +10 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +7 -0
  26. package/dist/measure.d.ts.map +1 -1
  27. package/dist/measure.js +4 -0
  28. package/dist/protocol-adapter.d.ts.map +1 -1
  29. package/dist/protocol-adapter.js +21 -0
  30. package/dist/protocol-rehydrate.d.ts +46 -0
  31. package/dist/protocol-rehydrate.d.ts.map +1 -0
  32. package/dist/protocol-rehydrate.js +218 -0
  33. package/dist/publishing/features/dataset-publication.d.ts +10 -0
  34. package/dist/publishing/features/dataset-publication.d.ts.map +1 -0
  35. package/dist/publishing/features/dataset-publication.js +34 -0
  36. package/dist/publishing/node.d.ts +16 -0
  37. package/dist/publishing/node.d.ts.map +1 -0
  38. package/dist/publishing/node.js +35 -0
  39. package/dist/publishing/publisher.d.ts +17 -0
  40. package/dist/publishing/publisher.d.ts.map +1 -0
  41. package/dist/publishing/publisher.js +32 -0
  42. package/dist/publishing/types.d.ts +31 -0
  43. package/dist/publishing/types.d.ts.map +1 -0
  44. package/dist/publishing/types.js +1 -0
  45. package/dist/query-builder-protocol.d.ts +6 -2
  46. package/dist/query-builder-protocol.d.ts.map +1 -1
  47. package/dist/semantic-plan.d.ts +3 -1
  48. package/dist/semantic-plan.d.ts.map +1 -1
  49. package/dist/semantic-planner.d.ts.map +1 -1
  50. package/dist/semantic-planner.js +4 -0
  51. package/dist/semantic-query-schema.d.ts +48 -0
  52. package/dist/semantic-query-schema.d.ts.map +1 -0
  53. package/dist/semantic-query-schema.js +218 -0
  54. package/dist/sql-utils.d.ts +36 -0
  55. package/dist/sql-utils.d.ts.map +1 -1
  56. package/dist/sql-utils.js +76 -0
  57. package/dist/tools.d.ts +5 -0
  58. package/dist/tools.d.ts.map +1 -1
  59. package/dist/tools.js +25 -267
  60. package/dist/types.d.ts +102 -12
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/utils/agent-catalog-projection.d.ts +78 -0
  63. package/dist/utils/agent-catalog-projection.d.ts.map +1 -0
  64. package/dist/utils/agent-catalog-projection.js +179 -0
  65. package/dist/utils/dataset-cache-policy.d.ts +34 -0
  66. package/dist/utils/dataset-cache-policy.d.ts.map +1 -0
  67. package/dist/utils/dataset-cache-policy.js +50 -0
  68. package/dist/utils/dataset-contract.d.ts +2 -2
  69. package/dist/utils/dataset-contract.d.ts.map +1 -1
  70. package/dist/utils/dataset-contract.js +3 -1
  71. package/dist/utils/dataset-definition-validation.d.ts +35 -0
  72. package/dist/utils/dataset-definition-validation.d.ts.map +1 -0
  73. package/dist/utils/dataset-definition-validation.js +215 -0
  74. package/dist/utils/dataset-metric-ref.d.ts +2 -2
  75. package/dist/utils/dataset-metric-ref.d.ts.map +1 -1
  76. package/dist/utils/dataset-metric-ref.js +5 -3
  77. package/dist/utils/metric-alias.d.ts +4 -0
  78. package/dist/utils/metric-alias.d.ts.map +1 -0
  79. package/dist/utils/metric-alias.js +28 -0
  80. package/dist/utils/protocol-metric-capabilities.d.ts +7 -0
  81. package/dist/utils/protocol-metric-capabilities.d.ts.map +1 -0
  82. package/dist/utils/protocol-metric-capabilities.js +57 -0
  83. package/dist/utils/protocol-rehydrate-filters.d.ts +10 -0
  84. package/dist/utils/protocol-rehydrate-filters.d.ts.map +1 -0
  85. package/dist/utils/protocol-rehydrate-filters.js +36 -0
  86. package/dist/utils/protocol-semantic-metadata.d.ts +5 -0
  87. package/dist/utils/protocol-semantic-metadata.d.ts.map +1 -0
  88. package/dist/utils/protocol-semantic-metadata.js +5 -0
  89. package/dist/utils/published-name.d.ts +3 -0
  90. package/dist/utils/published-name.d.ts.map +1 -0
  91. package/dist/utils/published-name.js +7 -0
  92. package/dist/utils/published-relationships.d.ts +34 -0
  93. package/dist/utils/published-relationships.d.ts.map +1 -0
  94. package/dist/utils/published-relationships.js +35 -0
  95. package/dist/utils/relationship-fields.d.ts +7 -0
  96. package/dist/utils/relationship-fields.d.ts.map +1 -1
  97. package/dist/utils/relationship-fields.js +13 -1
  98. package/dist/utils/result-limits.d.ts +34 -0
  99. package/dist/utils/result-limits.d.ts.map +1 -0
  100. package/dist/utils/result-limits.js +40 -0
  101. package/dist/utils/semantic-metadata-validation.d.ts +4 -0
  102. package/dist/utils/semantic-metadata-validation.d.ts.map +1 -0
  103. package/dist/utils/semantic-metadata-validation.js +103 -0
  104. package/dist/utils/semantic-metadata.d.ts +4 -0
  105. package/dist/utils/semantic-metadata.d.ts.map +1 -0
  106. package/dist/utils/semantic-metadata.js +13 -0
  107. package/dist/utils/semantic-result-serialization.d.ts +9 -0
  108. package/dist/utils/semantic-result-serialization.d.ts.map +1 -0
  109. package/dist/utils/semantic-result-serialization.js +26 -0
  110. package/dist/utils/semantic-tool.d.ts +5 -0
  111. package/dist/utils/semantic-tool.d.ts.map +1 -0
  112. package/dist/utils/semantic-tool.js +29 -0
  113. package/package.json +5 -4
package/README.md CHANGED
@@ -56,10 +56,14 @@ const result = await analytics.execute(
56
56
  },
57
57
  {
58
58
  runtime: { tenant: session.accountId },
59
+ abortSignal: request.signal,
59
60
  },
60
61
  );
61
62
  ```
62
63
 
64
+ Passing an `AbortSignal` cancels the semantic query and forwards cancellation to
65
+ the backing query builder/database request.
66
+
63
67
  The same definition can become:
64
68
 
65
69
  - a named KPI or flexible dataset query;
@@ -68,6 +72,12 @@ The same definition can become:
68
72
  - an OpenAI, AI SDK, or MCP tool schema;
69
73
  - a stable semantic contract for CI and deployment.
70
74
 
75
+ `buildCanonicalSemanticQuerySchemas()` compiles the same catalog into strict
76
+ dataset and metric Zod validators, JSON Schemas, and a deterministic manifest
77
+ hash. It accepts either live local Dataset definitions or an already-normalized
78
+ catalog from a hosted activation, so Serve and MCP do not maintain separate
79
+ field or operator lists.
80
+
71
81
  ## Analytics teams actually need
72
82
 
73
83
  - sums, counts, distinct counts, averages, min, and max;
@@ -0,0 +1,97 @@
1
+ import type { ProtocolDeploymentContract } from '@hypequery/protocol';
2
+ import { type DatasetCatalog, type DatasetCatalogMap, type DatasetCatalogSource } from './catalog.js';
3
+ import type { SemanticContract } from './contract.js';
4
+ import type { DatasetDefaults, DatasetFreshness, DatasetLimits, FieldType, SemanticMetadata } from './types.js';
5
+ export interface AgentCatalogDimension extends SemanticMetadata {
6
+ name: string;
7
+ type: FieldType;
8
+ label?: string;
9
+ description?: string;
10
+ filterable: boolean;
11
+ groupable: boolean;
12
+ }
13
+ export interface AgentCatalogMeasure extends SemanticMetadata {
14
+ name: string;
15
+ label?: string;
16
+ description?: string;
17
+ }
18
+ export interface AgentCatalogMetric extends SemanticMetadata {
19
+ name: string;
20
+ label?: string;
21
+ description?: string;
22
+ dimensions: string[];
23
+ filters: string[];
24
+ grains: string[];
25
+ grain?: string;
26
+ }
27
+ export interface AgentCatalogFilter extends SemanticMetadata {
28
+ name: string;
29
+ type: FieldType;
30
+ label?: string;
31
+ description?: string;
32
+ operators: string[];
33
+ }
34
+ export interface AgentCatalogRelationship {
35
+ name: string;
36
+ target: string;
37
+ fields: string[];
38
+ }
39
+ export interface AgentCatalogDataset extends SemanticMetadata {
40
+ name: string;
41
+ description: string;
42
+ freshness?: DatasetFreshness;
43
+ owner?: string;
44
+ defaults?: DatasetDefaults;
45
+ timeDimension: string | null;
46
+ dimensions: AgentCatalogDimension[];
47
+ measures: AgentCatalogMeasure[];
48
+ metrics: AgentCatalogMetric[];
49
+ filters: AgentCatalogFilter[];
50
+ relationships: AgentCatalogRelationship[];
51
+ limits: DatasetLimits;
52
+ }
53
+ export interface AgentSafeCatalog {
54
+ datasets: AgentCatalogDataset[];
55
+ }
56
+ export interface AgentCatalogProjectionOptions {
57
+ /** Maximum UTF-8 bytes in the complete safe catalog. Defaults to 256 KiB. */
58
+ maxCatalogBytes?: number;
59
+ }
60
+ export declare const DEFAULT_AGENT_CATALOG_MAX_BYTES: number;
61
+ export type AgentCatalogDatasetRegistry = Readonly<Record<string, DatasetCatalogSource | DatasetCatalog>>;
62
+ export type AgentCatalogSource = AgentCatalogDatasetRegistry | SemanticContract | ProtocolDeploymentContract;
63
+ /**
64
+ * Proof supplied by an owning application after it authorizes a trusted-debug
65
+ * request. The datasets package deliberately does not manufacture this value:
66
+ * authentication and authorization belong to the calling transport/runtime.
67
+ */
68
+ export interface TrustedDebugCatalogAuthorization {
69
+ readonly authorized: true;
70
+ }
71
+ export type TrustedDebugCatalog = {
72
+ readonly kind: 'dataset-catalog';
73
+ readonly datasets: DatasetCatalogMap;
74
+ } | {
75
+ readonly kind: 'semantic-contract';
76
+ readonly contract: SemanticContract;
77
+ } | {
78
+ readonly kind: 'deployment-contract';
79
+ readonly contract: ProtocolDeploymentContract;
80
+ };
81
+ /** Build the deterministic logical catalog that may safely be shown to an agent. */
82
+ export declare function projectAgentSafeCatalog(source: AgentCatalogSource, options?: AgentCatalogProjectionOptions): AgentSafeCatalog;
83
+ /**
84
+ * Enforce the agent-safe catalog byte budget.
85
+ *
86
+ * Exported so an adapter that builds a projection by another route — the MCP
87
+ * legacy registry fallback is the only one today — gets the same guarantee as
88
+ * `projectAgentSafeCatalog` rather than serializing an unbounded catalog and
89
+ * failing later against an unrelated response limit.
90
+ */
91
+ export declare function assertAgentSafeCatalogBudget(catalog: AgentSafeCatalog, options?: AgentCatalogProjectionOptions): void;
92
+ /**
93
+ * Return physical diagnostics only after the owning application has performed
94
+ * a separate authorization check. Never place this projection in model context.
95
+ */
96
+ export declare function projectTrustedDebugCatalog(source: AgentCatalogSource, authorization: TrustedDebugCatalogAuthorization): TrustedDebugCatalog;
97
+ //# sourceMappingURL=agent-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-catalog.d.ts","sourceRoot":"","sources":["../src/agent-catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import { getDatasetCatalog, } from './catalog.js';
2
+ import { compareStrings } from './utils/canonical-json.js';
3
+ import { protocolDatasetToAgentDataset, recordDatasetToAgentDataset, } from './utils/agent-catalog-projection.js';
4
+ export const DEFAULT_AGENT_CATALOG_MAX_BYTES = 256 * 1024;
5
+ function isProtocolDeploymentContract(source) {
6
+ return 'kind' in source && source.kind === 'hypequery-deployment';
7
+ }
8
+ function isSemanticContract(source) {
9
+ return 'contentHash' in source && typeof source.contentHash === 'string';
10
+ }
11
+ /** Build the deterministic logical catalog that may safely be shown to an agent. */
12
+ export function projectAgentSafeCatalog(source, options = {}) {
13
+ let catalog;
14
+ if (isProtocolDeploymentContract(source)) {
15
+ const datasets = new Map(source.datasets.map(dataset => [dataset.name, dataset]));
16
+ catalog = {
17
+ datasets: source.datasets
18
+ .map(dataset => protocolDatasetToAgentDataset(dataset, datasets))
19
+ .sort((left, right) => compareStrings(left.name, right.name)),
20
+ };
21
+ }
22
+ else if (isSemanticContract(source)) {
23
+ catalog = {
24
+ datasets: Object.values(source.datasets)
25
+ .map(recordDatasetToAgentDataset)
26
+ .sort((left, right) => compareStrings(left.name, right.name)),
27
+ };
28
+ }
29
+ else {
30
+ catalog = {
31
+ datasets: Object.entries(source)
32
+ .map(([, dataset]) => ('requiresTenant' in dataset ? dataset : getDatasetCatalog(dataset)))
33
+ .map(recordDatasetToAgentDataset)
34
+ .sort((left, right) => compareStrings(left.name, right.name)),
35
+ };
36
+ }
37
+ assertAgentSafeCatalogBudget(catalog, options);
38
+ return catalog;
39
+ }
40
+ /**
41
+ * Enforce the agent-safe catalog byte budget.
42
+ *
43
+ * Exported so an adapter that builds a projection by another route — the MCP
44
+ * legacy registry fallback is the only one today — gets the same guarantee as
45
+ * `projectAgentSafeCatalog` rather than serializing an unbounded catalog and
46
+ * failing later against an unrelated response limit.
47
+ */
48
+ export function assertAgentSafeCatalogBudget(catalog, options = {}) {
49
+ const maxBytes = options.maxCatalogBytes ?? DEFAULT_AGENT_CATALOG_MAX_BYTES;
50
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
51
+ throw new RangeError('maxCatalogBytes must be a positive safe integer.');
52
+ }
53
+ const byteLength = new TextEncoder().encode(JSON.stringify(catalog)).byteLength;
54
+ if (byteLength > maxBytes) {
55
+ throw new RangeError(`Agent-safe catalog exceeds the ${maxBytes}-byte limit.`);
56
+ }
57
+ }
58
+ /**
59
+ * Return physical diagnostics only after the owning application has performed
60
+ * a separate authorization check. Never place this projection in model context.
61
+ */
62
+ export function projectTrustedDebugCatalog(source, authorization) {
63
+ if (authorization?.authorized !== true) {
64
+ throw new Error('Trusted debug catalog access requires explicit authorization.');
65
+ }
66
+ if (isProtocolDeploymentContract(source)) {
67
+ return { kind: 'deployment-contract', contract: source };
68
+ }
69
+ if (isSemanticContract(source)) {
70
+ return { kind: 'semantic-contract', contract: source };
71
+ }
72
+ return {
73
+ kind: 'dataset-catalog',
74
+ datasets: Object.fromEntries(Object.entries(source).map(([name, dataset]) => [
75
+ name,
76
+ 'requiresTenant' in dataset ? dataset : getDatasetCatalog(dataset),
77
+ ])),
78
+ };
79
+ }
@@ -1,4 +1,4 @@
1
- import { add, dataset, dimension, measure, eq, between, desc, createDatasetClient } from './index.js';
1
+ import { add, between, buildCanonicalSemanticQuerySchemas, createDatasetClient, dataset, desc, dimension, eq, measure, publishDatasets, } from './index.js';
2
2
  const Orders = dataset('orders', {
3
3
  source: 'orders',
4
4
  tenantKey: 'tenant_id',
@@ -34,6 +34,20 @@ const averageRevenueMetric = Orders.metric('averageRevenueMetric', {
34
34
  formula: ({ revenue, completedRevenue }) => add(revenue, completedRevenue),
35
35
  });
36
36
  const customerCountMetric = Customers.metric('customerCountMetric', { measure: 'customerCount' });
37
+ const _publishedDatasets = publishDatasets()
38
+ .publish(Orders, { metrics: { revenue: revenueMetric } })
39
+ .publish(Customers, {
40
+ alias: 'accounts',
41
+ metrics: { customers: customerCountMetric },
42
+ })
43
+ .build();
44
+ // @ts-expect-error published metrics must belong to the dataset being published.
45
+ publishDatasets().publish(Orders, { metrics: { customerCountMetric } });
46
+ const canonicalSchemas = buildCanonicalSemanticQuerySchemas({
47
+ orders: { ...Orders, metrics: { revenueMetric } },
48
+ });
49
+ canonicalSchemas.queryDataset.parse({ dataset: 'orders', measures: ['revenue'] });
50
+ const _manifestHash = canonicalSchemas.manifestHash;
37
51
  const _statusFilter = eq('status', 'completed');
38
52
  const _createdAtRange = between('createdAt', '2025-01-01', '2025-01-31');
39
53
  const _revenueSort = desc('revenueMetric');
@@ -56,6 +70,10 @@ const runtimeContext = {
56
70
  tenant: 'tenant-1',
57
71
  },
58
72
  };
73
+ const abortableContext = {
74
+ abortSignal: new AbortController().signal,
75
+ };
76
+ void abortableContext;
59
77
  const _legacyTenantRuntimeContext = {
60
78
  runtime: {
61
79
  tenant: { id: 'tenant-1' },
package/dist/catalog.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { AnyDatasetInstance, DimensionDefinition, MeasureDefinition, MetricHandle, RelationshipDefinition, SemanticFilterDefinition, DatasetLimits, TimeGrain } from './types.js';
2
- export interface DimensionCatalogEntry {
1
+ import type { AnyDatasetInstance, DimensionDefinition, MeasureDefinition, MetricHandle, RelationshipDefinition, SemanticFilterDefinition, DatasetLimits, DatasetDefaults, DatasetFreshness, SemanticMetadata, TimeGrain } from './types.js';
2
+ export interface DimensionCatalogEntry extends SemanticMetadata {
3
3
  type: DimensionDefinition['fieldType'];
4
4
  column?: string;
5
5
  sql?: string;
@@ -8,7 +8,7 @@ export interface DimensionCatalogEntry {
8
8
  filterable: boolean;
9
9
  groupable: boolean;
10
10
  }
11
- export interface MeasureCatalogEntry {
11
+ export interface MeasureCatalogEntry extends SemanticMetadata {
12
12
  aggregation: MeasureDefinition['aggregation'];
13
13
  field: string;
14
14
  /** Second column for argMax/argMin. */
@@ -20,14 +20,14 @@ export interface MeasureCatalogEntry {
20
20
  description?: string;
21
21
  filterCount: number;
22
22
  }
23
- export interface FilterCatalogEntry {
23
+ export interface FilterCatalogEntry extends SemanticMetadata {
24
24
  field: string;
25
25
  label?: string;
26
26
  description?: string;
27
27
  operators: SemanticFilterDefinition['operators'];
28
28
  valueType?: DimensionDefinition['fieldType'];
29
29
  }
30
- export interface MetricCatalogEntry {
30
+ export interface MetricCatalogEntry extends SemanticMetadata {
31
31
  kind: ReturnType<MetricHandle['contract']>['kind'];
32
32
  dataset: string;
33
33
  valueType: 'number';
@@ -47,10 +47,19 @@ export interface RelationshipCatalogEntry {
47
47
  to: string;
48
48
  queryable: boolean;
49
49
  fields: string[];
50
+ /**
51
+ * Subset of `fields` usable as a grouping key. Optional so an externally
52
+ * supplied catalog that predates it still resolves, falling back to `fields`.
53
+ */
54
+ groupableFields?: string[];
50
55
  }
51
- export interface DatasetCatalog {
56
+ export interface DatasetCatalog extends SemanticMetadata {
52
57
  name: string;
58
+ description?: string;
53
59
  source: string;
60
+ freshness?: DatasetFreshness;
61
+ owner?: string;
62
+ defaults?: DatasetDefaults;
54
63
  tenantKey?: string;
55
64
  timeKey?: string;
56
65
  dimensions: Record<string, DimensionCatalogEntry>;
@@ -70,6 +79,8 @@ export type DatasetCatalogSource = AnyDatasetInstance & {
70
79
  };
71
80
  /** All queryable relationship field names (`<relationship>.<dimension>`) a catalog advertises. */
72
81
  export declare function getQueryableRelationshipFields(catalog: DatasetCatalog): string[];
82
+ /** The queryable relationship fields a catalog also allows as grouping keys. */
83
+ export declare function getGroupableRelationshipFields(catalog: DatasetCatalog): string[];
73
84
  export declare function getDatasetCatalog(dataset: DatasetCatalogSource): DatasetCatalog;
74
85
  export declare function getDatasetCatalogs(datasets: Record<string, DatasetCatalogSource>): DatasetCatalogMap;
75
86
  //# sourceMappingURL=catalog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
package/dist/catalog.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { SEMANTIC_FILTER_OPERATORS, SUPPORTED_TIME_GRAINS } from './constants.js';
2
- import { listQueryableRelationshipFields } from './utils/relationship-fields.js';
2
+ import { listGroupableRelationshipFields, listQueryableRelationshipFields, } from './utils/relationship-fields.js';
3
+ import { snapshotSemanticMetadata } from './utils/semantic-metadata.js';
3
4
  function dimensionToCatalog(dimension) {
4
5
  return {
5
6
  type: dimension.fieldType,
@@ -7,6 +8,7 @@ function dimensionToCatalog(dimension) {
7
8
  sql: dimension.sql,
8
9
  label: dimension.label,
9
10
  description: dimension.description,
11
+ ...snapshotSemanticMetadata(dimension),
10
12
  filterable: dimension.filterable !== false,
11
13
  groupable: dimension.groupable !== false,
12
14
  };
@@ -20,6 +22,7 @@ function measureToCatalog(measure) {
20
22
  sql: measure.sql,
21
23
  label: measure.label,
22
24
  description: measure.description,
25
+ ...snapshotSemanticMetadata(measure),
23
26
  filterCount: measure.filters?.length ?? 0,
24
27
  };
25
28
  }
@@ -28,6 +31,7 @@ function filterToCatalog(filter, dimensions) {
28
31
  field: filter.field,
29
32
  label: filter.label,
30
33
  description: filter.description,
34
+ ...snapshotSemanticMetadata(filter),
31
35
  operators: filter.operators ? [...filter.operators] : [...SEMANTIC_FILTER_OPERATORS],
32
36
  valueType: dimensions[filter.field]?.fieldType,
33
37
  };
@@ -40,6 +44,7 @@ function metricToCatalog(metric) {
40
44
  valueType: contract.valueType,
41
45
  label: contract.label,
42
46
  description: contract.description,
47
+ ...snapshotSemanticMetadata(contract),
43
48
  dimensions: contract.dimensions,
44
49
  measures: contract.measures,
45
50
  filters: contract.filters,
@@ -56,6 +61,7 @@ function relationshipToCatalog(name, relationship) {
56
61
  to: relationship.to,
57
62
  queryable: relationship.kind !== 'hasMany',
58
63
  fields: listQueryableRelationshipFields(name, relationship),
64
+ groupableFields: listGroupableRelationshipFields(name, relationship),
59
65
  };
60
66
  }
61
67
  /** All queryable relationship field names (`<relationship>.<dimension>`) a catalog advertises. */
@@ -64,6 +70,12 @@ export function getQueryableRelationshipFields(catalog) {
64
70
  .filter(relationship => relationship.queryable)
65
71
  .flatMap(relationship => relationship.fields);
66
72
  }
73
+ /** The queryable relationship fields a catalog also allows as grouping keys. */
74
+ export function getGroupableRelationshipFields(catalog) {
75
+ return Object.values(catalog.relationships)
76
+ .filter(relationship => relationship.queryable)
77
+ .flatMap(relationship => relationship.groupableFields ?? relationship.fields);
78
+ }
67
79
  export function getDatasetCatalog(dataset) {
68
80
  const dimensionNames = Object.keys(dataset.dimensions);
69
81
  const measureNames = Object.keys(dataset.measures);
@@ -76,7 +88,12 @@ export function getDatasetCatalog(dataset) {
76
88
  ]));
77
89
  return {
78
90
  name: dataset.name,
91
+ description: dataset.description,
92
+ ...snapshotSemanticMetadata(dataset),
79
93
  source: dataset.source,
94
+ freshness: dataset.freshness,
95
+ owner: dataset.owner,
96
+ defaults: dataset.defaults,
80
97
  tenantKey: dataset.tenantKey,
81
98
  timeKey: dataset.timeKey,
82
99
  dimensions: Object.fromEntries(Object.entries(dataset.dimensions).map(([name, dimension]) => [
@@ -1,11 +1,11 @@
1
1
  import { type DatasetCatalogSource, type DimensionCatalogEntry, type MeasureCatalogEntry, type MetricCatalogEntry, type FilterCatalogEntry, type RelationshipCatalogEntry } from './catalog.js';
2
- import type { DatasetLimits } from './types.js';
2
+ import type { DatasetDefaults, DatasetFreshness, DatasetLimits, SemanticMetadata } from './types.js';
3
3
  /**
4
4
  * Version of the semantic contract format. Bump when the serialized shape
5
5
  * changes in a way that snapshot consumers must account for.
6
6
  */
7
- export declare const SEMANTIC_CONTRACT_VERSION = 2;
8
- export interface ContractDimension {
7
+ export declare const SEMANTIC_CONTRACT_VERSION = 3;
8
+ export interface ContractDimension extends SemanticMetadata {
9
9
  type: DimensionCatalogEntry['type'];
10
10
  column?: string;
11
11
  sql?: string;
@@ -14,7 +14,7 @@ export interface ContractDimension {
14
14
  filterable: boolean;
15
15
  groupable: boolean;
16
16
  }
17
- export interface ContractMeasure {
17
+ export interface ContractMeasure extends SemanticMetadata {
18
18
  aggregation: MeasureCatalogEntry['aggregation'];
19
19
  field: string;
20
20
  /** Second column for argMax/argMin. */
@@ -25,7 +25,7 @@ export interface ContractMeasure {
25
25
  label?: string;
26
26
  description?: string;
27
27
  }
28
- export interface ContractMetric {
28
+ export interface ContractMetric extends SemanticMetadata {
29
29
  kind: MetricCatalogEntry['kind'];
30
30
  valueType: MetricCatalogEntry['valueType'];
31
31
  label?: string;
@@ -37,7 +37,7 @@ export interface ContractMetric {
37
37
  grain?: string;
38
38
  requires?: string[];
39
39
  }
40
- export interface ContractFilter {
40
+ export interface ContractFilter extends SemanticMetadata {
41
41
  field: string;
42
42
  label?: string;
43
43
  description?: string;
@@ -52,9 +52,13 @@ export interface ContractRelationship {
52
52
  queryable: boolean;
53
53
  fields: string[];
54
54
  }
55
- export interface ContractDataset {
55
+ export interface ContractDataset extends SemanticMetadata {
56
56
  name: string;
57
+ description?: string;
57
58
  source: string;
59
+ freshness?: DatasetFreshness;
60
+ owner?: string;
61
+ defaults?: DatasetDefaults;
58
62
  tenantKey?: string;
59
63
  timeKey?: string;
60
64
  requiresTenant: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
package/dist/contract.js CHANGED
@@ -2,11 +2,12 @@ import { sha256 } from '@noble/hashes/sha2';
2
2
  import { bytesToHex } from '@noble/hashes/utils';
3
3
  import { getDatasetCatalogs, } from './catalog.js';
4
4
  import { sortedRecord, uniqueSorted } from './utils/canonical-json.js';
5
+ import { snapshotSemanticMetadata } from './utils/semantic-metadata.js';
5
6
  /**
6
7
  * Version of the semantic contract format. Bump when the serialized shape
7
8
  * changes in a way that snapshot consumers must account for.
8
9
  */
9
- export const SEMANTIC_CONTRACT_VERSION = 2;
10
+ export const SEMANTIC_CONTRACT_VERSION = 3;
10
11
  /**
11
12
  * Builds a deterministic semantic contract from dataset instances.
12
13
  *
@@ -31,7 +32,23 @@ export function serializeSemanticContract(datasets, options = {}) {
31
32
  function datasetToContract(catalog, includeSql) {
32
33
  return {
33
34
  name: catalog.name,
35
+ ...(catalog.description !== undefined ? { description: catalog.description } : {}),
36
+ ...snapshotSemanticMetadata(catalog),
34
37
  source: catalog.source,
38
+ ...(catalog.freshness !== undefined ? { freshness: { ...catalog.freshness } } : {}),
39
+ ...(catalog.owner !== undefined ? { owner: catalog.owner } : {}),
40
+ ...(catalog.defaults !== undefined
41
+ ? {
42
+ defaults: {
43
+ ...(catalog.defaults.dimensions !== undefined
44
+ ? { dimensions: uniqueSorted(catalog.defaults.dimensions) }
45
+ : {}),
46
+ ...(catalog.defaults.timeGrain !== undefined
47
+ ? { timeGrain: catalog.defaults.timeGrain }
48
+ : {}),
49
+ },
50
+ }
51
+ : {}),
35
52
  ...(catalog.tenantKey !== undefined ? { tenantKey: catalog.tenantKey } : {}),
36
53
  ...(catalog.timeKey !== undefined ? { timeKey: catalog.timeKey } : {}),
37
54
  requiresTenant: catalog.requiresTenant,
@@ -64,6 +81,7 @@ function dimensionToContract(entry, includeSql) {
64
81
  ...(includeSql && entry.sql !== undefined ? { sql: normalizeSql(entry.sql) } : {}),
65
82
  ...(entry.label !== undefined ? { label: entry.label } : {}),
66
83
  ...(entry.description !== undefined ? { description: entry.description } : {}),
84
+ ...snapshotSemanticMetadata(entry),
67
85
  filterable: entry.filterable,
68
86
  groupable: entry.groupable,
69
87
  };
@@ -77,6 +95,7 @@ function measureToContract(entry, includeSql) {
77
95
  ...(includeSql && entry.sql !== undefined ? { sql: normalizeSql(entry.sql) } : {}),
78
96
  ...(entry.label !== undefined ? { label: entry.label } : {}),
79
97
  ...(entry.description !== undefined ? { description: entry.description } : {}),
98
+ ...snapshotSemanticMetadata(entry),
80
99
  };
81
100
  }
82
101
  function metricToContract(entry) {
@@ -85,6 +104,7 @@ function metricToContract(entry) {
85
104
  valueType: entry.valueType,
86
105
  ...(entry.label !== undefined ? { label: entry.label } : {}),
87
106
  ...(entry.description !== undefined ? { description: entry.description } : {}),
107
+ ...snapshotSemanticMetadata(entry),
88
108
  dimensions: uniqueSorted(entry.dimensions),
89
109
  ...(entry.measures !== undefined ? { measures: uniqueSorted(entry.measures) } : {}),
90
110
  filters: uniqueSorted(entry.filters),
@@ -98,6 +118,7 @@ function filterToContract(entry) {
98
118
  field: entry.field,
99
119
  ...(entry.label !== undefined ? { label: entry.label } : {}),
100
120
  ...(entry.description !== undefined ? { description: entry.description } : {}),
121
+ ...snapshotSemanticMetadata(entry),
101
122
  operators: uniqueSorted(entry.operators ?? []),
102
123
  ...(entry.valueType !== undefined ? { valueType: entry.valueType } : {}),
103
124
  };
@@ -1 +1 @@
1
- {"version":3,"file":"dataset-query.d.ts","sourceRoot":"","sources":["../src/dataset-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAQ7F,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAyBxD,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,uBAAuB,CAAC;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,gBAAgB,CAElB;AAED,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,gBAAgB,CA4ClB;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAa7B"}
1
+ {"version":3,"file":"dataset-query.d.ts","sourceRoot":"","sources":["../src/dataset-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAQ7F,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA0BxD,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,uBAAuB,CAAC;IACxC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,gBAAgB,CAElB;AAED,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,gBAAgB,CA4ClB;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,kBAAkB,CAAC,CAqB7B"}
@@ -3,6 +3,7 @@ import { validateDatasetQueryInput } from './utils/dataset-query-validation.js';
3
3
  import { getRuntimeTenantId, getRuntimeTenantPredicate, } from './utils/tenant-runtime.js';
4
4
  import { applyPagination, overfetchLimit } from './utils/pagination.js';
5
5
  import { applyRelationshipJoins, buildRelationshipBuilderContext, qualifyBaseColumn, } from './utils/relationship-builder-plan.js';
6
+ import { serializeSemanticMeasureValues } from './utils/semantic-result-serialization.js';
6
7
  function toResultMeta(qb, timingMs, context) {
7
8
  return {
8
9
  sql: qb.toSQLWithParams().sql,
@@ -50,10 +51,15 @@ export async function runDatasetQuery(ds, query, options) {
50
51
  ...options,
51
52
  executionLimit: overfetchLimit(query.limit),
52
53
  });
53
- const rows = await qb.execute();
54
+ const rows = await qb.execute({ abortSignal: options.context?.abortSignal });
54
55
  const { data, pagination } = applyPagination(rows, query.limit, query.offset);
56
+ const serializedData = serializeSemanticMeasureValues(data, query.measures ?? Object.keys(ds.measures));
55
57
  return {
56
- data,
57
- meta: { ...toResultMeta(qb, Date.now() - start, options.context), rowCount: data.length, pagination },
58
+ data: serializedData,
59
+ meta: {
60
+ ...toResultMeta(qb, Date.now() - start, options.context),
61
+ rowCount: serializedData.length,
62
+ pagination,
63
+ },
58
64
  };
59
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EAKvB,MAAM,YAAY,CAAC;AAkBpB,wBAAgB,OAAO,CACrB,YAAY,SAAS,MAAM,EAC3B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC3E,cAAc,SAAS,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAErF,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,GAC5D,eAAe,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,CAAC,CA2DvE"}
1
+ {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../src/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EAKvB,MAAM,YAAY,CAAC;AAqBpB,wBAAgB,OAAO,CACrB,YAAY,SAAS,MAAM,EAC3B,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC3E,cAAc,SAAS,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAErF,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,GAC5D,eAAe,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,CAAC,CA2EvE"}
package/dist/dataset.js CHANGED
@@ -32,16 +32,24 @@
32
32
  import { createDerivedMetricSpec, createMetricRef, isDerivedMetricConfig, } from './utils/dataset-metric-ref.js';
33
33
  import { measureToAggregationSpec, normalizeDimensions, normalizeFilters, normalizeMeasures, normalizeRelationships, } from './utils/dataset-normalization.js';
34
34
  import { validateBaseMetric, validateDerivedMetric, } from './utils/dataset-validation.js';
35
+ import { validateDatasetDefinition } from './utils/dataset-definition-validation.js';
36
+ import { snapshotSemanticMetadata } from './utils/semantic-metadata.js';
37
+ import { validateSemanticMetadata } from './utils/semantic-metadata-validation.js';
35
38
  export function dataset(name, config) {
39
+ // Structural validation runs before anything is normalized, so an invalid
40
+ // model fails at definition time rather than on the first query that reaches
41
+ // the broken part of it.
42
+ validateDatasetDefinition(name, config);
36
43
  const dimensions = normalizeDimensions(config);
37
44
  const measures = normalizeMeasures(config.measures);
38
45
  const filters = normalizeFilters(dimensions, config.filters);
39
46
  const relationships = normalizeRelationships(config.relationships, config.source);
40
47
  function metric(metricName, metricConfig) {
48
+ validateSemanticMetadata(ds.name, `metrics.${metricName}`, metricConfig);
41
49
  if (isDerivedMetricConfig(metricConfig)) {
42
50
  validateDerivedMetric(ds, metricName, metricConfig);
43
51
  const derivedSpec = createDerivedMetricSpec(metricConfig);
44
- return createMetricRef(ds, metricName, derivedSpec, metricConfig.label, metricConfig.description);
52
+ return createMetricRef(ds, metricName, derivedSpec, metricConfig.label, metricConfig.description, metricConfig);
45
53
  }
46
54
  const measureName = metricConfig.measure;
47
55
  const measure = ds.measures[measureName];
@@ -50,12 +58,20 @@ export function dataset(name, config) {
50
58
  }
51
59
  const spec = measureToAggregationSpec(measureName, measure);
52
60
  validateBaseMetric(ds, metricName, spec, { allowHiddenField: true });
53
- return createMetricRef(ds, metricName, spec, metricConfig.label ?? measure.label, metricConfig.description ?? measure.description);
61
+ return createMetricRef(ds, metricName, spec, metricConfig.label ?? measure.label, metricConfig.description ?? measure.description, { ...measure, ...metricConfig });
54
62
  }
55
63
  const ds = {
56
64
  __type: 'dataset',
57
65
  name,
58
66
  source: config.source,
67
+ description: config.description,
68
+ ...snapshotSemanticMetadata(config),
69
+ freshness: config.freshness === undefined ? undefined : { ...config.freshness },
70
+ owner: config.owner,
71
+ defaults: config.defaults === undefined ? undefined : {
72
+ ...config.defaults,
73
+ ...(config.defaults.dimensions === undefined ? {} : { dimensions: [...config.defaults.dimensions] }),
74
+ },
59
75
  tenantKey: config.tenantKey,
60
76
  timeKey: config.timeKey,
61
77
  dimensions,
@@ -63,6 +79,7 @@ export function dataset(name, config) {
63
79
  filters,
64
80
  relationships,
65
81
  limits: config.limits,
82
+ cache: config.cache,
66
83
  metric,
67
84
  };
68
85
  return ds;