@hypequery/datasets 0.7.0 → 0.9.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 (57) hide show
  1. package/dist/api.type-test.js +1 -0
  2. package/dist/catalog.d.ts +4 -1
  3. package/dist/catalog.d.ts.map +1 -1
  4. package/dist/catalog.js +16 -6
  5. package/dist/contract.d.ts +3 -1
  6. package/dist/contract.d.ts.map +1 -1
  7. package/dist/contract.js +3 -1
  8. package/dist/dataset-query.d.ts.map +1 -1
  9. package/dist/dataset-query.js +8 -5
  10. package/dist/dataset.d.ts +4 -3
  11. package/dist/dataset.d.ts.map +1 -1
  12. package/dist/dataset.js +5 -4
  13. package/dist/executor.d.ts +7 -1
  14. package/dist/executor.d.ts.map +1 -1
  15. package/dist/executor.js +39 -10
  16. package/dist/field.d.ts +4 -4
  17. package/dist/field.d.ts.map +1 -1
  18. package/dist/in-memory-backend.d.ts +5 -0
  19. package/dist/in-memory-backend.d.ts.map +1 -1
  20. package/dist/in-memory-backend.js +87 -22
  21. package/dist/index.d.ts +3 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -1
  24. package/dist/query-builder-protocol.d.ts +12 -0
  25. package/dist/query-builder-protocol.d.ts.map +1 -1
  26. package/dist/query-planner.d.ts +7 -6
  27. package/dist/query-planner.d.ts.map +1 -1
  28. package/dist/query-planner.js +63 -16
  29. package/dist/relationships.d.ts +9 -9
  30. package/dist/relationships.d.ts.map +1 -1
  31. package/dist/semantic-plan.d.ts +50 -9
  32. package/dist/semantic-plan.d.ts.map +1 -1
  33. package/dist/semantic-plan.js +9 -0
  34. package/dist/semantic-planner.d.ts.map +1 -1
  35. package/dist/semantic-planner.js +67 -5
  36. package/dist/tools.d.ts.map +1 -1
  37. package/dist/tools.js +29 -18
  38. package/dist/types.d.ts +33 -16
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/utils/dataset-normalization.d.ts +1 -1
  41. package/dist/utils/dataset-normalization.d.ts.map +1 -1
  42. package/dist/utils/dataset-normalization.js +11 -1
  43. package/dist/utils/dataset-query-validation.d.ts.map +1 -1
  44. package/dist/utils/dataset-query-validation.js +50 -12
  45. package/dist/utils/filtered-aggregation-sql.d.ts +2 -1
  46. package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -1
  47. package/dist/utils/filtered-aggregation-sql.js +4 -4
  48. package/dist/utils/relationship-builder-plan.d.ts +56 -0
  49. package/dist/utils/relationship-builder-plan.d.ts.map +1 -0
  50. package/dist/utils/relationship-builder-plan.js +92 -0
  51. package/dist/utils/relationship-fields.d.ts +62 -0
  52. package/dist/utils/relationship-fields.d.ts.map +1 -0
  53. package/dist/utils/relationship-fields.js +98 -0
  54. package/dist/utils/relationship-validation.d.ts +15 -0
  55. package/dist/utils/relationship-validation.d.ts.map +1 -0
  56. package/dist/utils/relationship-validation.js +29 -0
  57. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -6,7 +6,8 @@ export { sum, count, countDistinct, avg, min, max } from './aggregations.js';
6
6
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
7
7
  export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
8
8
  export { createDatasetRegistry } from './registry.js';
9
- export { getDatasetCatalog, getDatasetCatalogs } from './catalog.js';
9
+ export { getDatasetCatalog, getDatasetCatalogs, getQueryableRelationshipFields } from './catalog.js';
10
+ export { listQueryableRelationshipFields } from './utils/relationship-fields.js';
10
11
  export type { DatasetCatalog, DatasetCatalogMap, DatasetCatalogSource, DimensionCatalogEntry, MeasureCatalogEntry, MetricCatalogEntry, FilterCatalogEntry, RelationshipCatalogEntry, } from './catalog.js';
11
12
  export { serializeSemanticContract, contractToStableJson, hashContract, SEMANTIC_CONTRACT_VERSION, } from './contract.js';
12
13
  export type { SemanticContract, SerializeSemanticContractOptions, ContractDataset, ContractDimension, ContractMeasure, ContractMetric, ContractFilter, ContractRelationship, } from './contract.js';
@@ -26,5 +27,5 @@ export type { QueryBuilderLike, QueryBuilderFactoryLike, QueryBuilderFactoryComp
26
27
  export { toQueryBuilderFactory } from './query-builder-protocol.js';
27
28
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
28
29
  export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SUPPORTED_TIME_GRAINS } from './constants.js';
29
- export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetLimits, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetMeasureNames, DatasetOrderableNames, DatasetQueryFor, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
30
+ export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, InferDimensionType, RelationshipKind, RelationshipDefinition, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SemanticFiltersDefinition, DatasetConfig, DatasetLimits, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetQueryableDimensions, DatasetMeasureNames, DatasetOrderableNames, DatasetQueryFor, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
30
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -15,7 +15,8 @@ export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc,
15
15
  // Registry
16
16
  export { createDatasetRegistry } from './registry.js';
17
17
  // Catalog
18
- export { getDatasetCatalog, getDatasetCatalogs } from './catalog.js';
18
+ export { getDatasetCatalog, getDatasetCatalogs, getQueryableRelationshipFields } from './catalog.js';
19
+ export { listQueryableRelationshipFields } from './utils/relationship-fields.js';
19
20
  // Semantic contract (stable, hashable export for snapshots/diffs/validation)
20
21
  export { serializeSemanticContract, contractToStableJson, hashContract, SEMANTIC_CONTRACT_VERSION, } from './contract.js';
21
22
  // Agent/tool metadata
@@ -25,6 +26,9 @@ export { createDatasetClient } from './executor.js';
25
26
  // Semantic query result cache
26
27
  export { createMemoryCacheStore } from './cache/semantic-query-cache.js';
27
28
  export { buildDatasetQuerySignature, buildMetricQuerySignature, } from './cache/query-signature.js';
29
+ // Plan/backend protocol — FROZEN. Deprecated in favor of the query-builder
30
+ // path (`createDatasetClient({ queryBuilder })`); bug fixes only, no new
31
+ // features. See the deprecation notes on each declaration.
28
32
  export { createInMemoryBackend } from './in-memory-backend.js';
29
33
  export { validateFilterValue, matchesFieldType } from './validation.js';
30
34
  export { toQueryBuilderFactory } from './query-builder-protocol.js';
@@ -18,6 +18,13 @@ export interface QueryBuilderLike {
18
18
  min(column: string, alias?: string): QueryBuilderLike;
19
19
  max(column: string, alias?: string): QueryBuilderLike;
20
20
  where(column: string, operator: string, value: unknown): QueryBuilderLike;
21
+ leftJoin(table: string, leftColumn: string, rightColumn: string, alias?: string, on?: QueryBuilderJoinCondition | QueryBuilderJoinCondition[]): QueryBuilderLike;
22
+ /**
23
+ * Optional single-match LEFT JOIN (ClickHouse `LEFT ANY JOIN`). When a
24
+ * builder provides it, relationship joins use it so duplicate target join
25
+ * keys cannot fan out aggregates; otherwise `leftJoin` is used.
26
+ */
27
+ leftAnyJoin?(table: string, leftColumn: string, rightColumn: string, alias?: string, on?: QueryBuilderJoinCondition | QueryBuilderJoinCondition[]): QueryBuilderLike;
21
28
  groupBy(columns: string | string[]): QueryBuilderLike;
22
29
  orderBy(column: string, direction?: 'ASC' | 'DESC'): QueryBuilderLike;
23
30
  limit(count: number): QueryBuilderLike;
@@ -28,6 +35,11 @@ export interface QueryBuilderLike {
28
35
  };
29
36
  execute<T = Record<string, unknown>>(): Promise<T[]>;
30
37
  }
38
+ export interface QueryBuilderJoinCondition {
39
+ column: string;
40
+ operator: string;
41
+ value: unknown;
42
+ }
31
43
  /** A query builder factory (what `createQueryBuilder(config)` returns). */
32
44
  export interface QueryBuilderFactoryLike {
33
45
  table(name: string): QueryBuilderLike;
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder-protocol.d.ts","sourceRoot":"","sources":["../src/query-builder-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAGrD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACxD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAChE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGtD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAG1E,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,gBAAgB,CAAC;IAGtD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,gBAAgB,CAAC;IACtE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAGxC,eAAe,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAC1D,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACtD;AAED,2EAA2E;AAC3E,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACtC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;CACtF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,6BAA6B;IAC5C,KAAK,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACzD;AAED,iEAAiE;AACjE,MAAM,MAAM,wBAAwB,GAChC,uBAAuB,GACvB,6BAA6B,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,wBAAwB,GAChC,uBAAuB,CAEzB"}
1
+ {"version":3,"file":"query-builder-protocol.d.ts","sourceRoot":"","sources":["../src/query-builder-protocol.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,16 @@
1
1
  import type { AggregationSpec, AnyDatasetInstance, ExecutionContext, MeasureDefinition, MetricOrderBy, TimeGrain } from "./types.js";
2
2
  import type { QueryBuilderLike } from "./query-builder-protocol.js";
3
+ import { type RelationshipBuilderContext } from './utils/relationship-builder-plan.js';
3
4
  type DatasetShape = AnyDatasetInstance;
4
- export declare function resolveDimensionExpression(ds: DatasetShape, dimensionName: string): string;
5
- export declare function resolveFilterField(ds: DatasetShape, filterField: string): string;
6
- export declare function buildDimensionSelectionPlan(ds: DatasetShape, dimensions: string[], grain: TimeGrain | undefined): {
5
+ export declare function resolveDimensionExpression(ds: DatasetShape, dimensionName: string, joinCtx?: RelationshipBuilderContext): string;
6
+ export declare function resolveFilterField(ds: DatasetShape, filterField: string, joinCtx?: RelationshipBuilderContext): string;
7
+ export declare function buildDimensionSelectionPlan(ds: DatasetShape, dimensions: string[], grain: TimeGrain | undefined, joinCtx?: RelationshipBuilderContext): {
7
8
  selectParts: string[];
8
9
  groupByParts: string[];
9
10
  };
10
- export declare function applyAggregationSpec(qb: QueryBuilderLike, ds: DatasetShape, spec: AggregationSpec, alias: string): QueryBuilderLike;
11
- export declare function applyMeasureDefinition(qb: QueryBuilderLike, ds: DatasetShape, name: string, definition: MeasureDefinition): QueryBuilderLike;
12
- export declare function appendOrderLimitOffset(qb: QueryBuilderLike, orderBy: MetricOrderBy[] | undefined, grain: TimeGrain | undefined, limit?: number, offset?: number): QueryBuilderLike;
11
+ export declare function applyAggregationSpec(qb: QueryBuilderLike, ds: DatasetShape, spec: AggregationSpec, alias: string, joinCtx?: RelationshipBuilderContext): QueryBuilderLike;
12
+ export declare function applyMeasureDefinition(qb: QueryBuilderLike, ds: DatasetShape, name: string, definition: MeasureDefinition, joinCtx?: RelationshipBuilderContext): QueryBuilderLike;
13
+ export declare function appendOrderLimitOffset(qb: QueryBuilderLike, orderBy: MetricOrderBy[] | undefined, grain: TimeGrain | undefined, limit?: number, offset?: number, joinCtx?: RelationshipBuilderContext): QueryBuilderLike;
13
14
  export declare function resolveTenantFilterColumn(ds: DatasetShape, context?: ExecutionContext): string | undefined;
14
15
  export {};
15
16
  //# sourceMappingURL=query-planner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-planner.d.ts","sourceRoot":"","sources":["../src/query-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAKpE,KAAK,YAAY,GAAG,kBAAkB,CAAC;AAMvC,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,YAAY,EAChB,aAAa,EAAE,MAAM,GACpB,MAAM,CAGR;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,YAAY,EAChB,WAAW,EAAE,MAAM,GAClB,MAAM,CAGR;AAED,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,YAAY,EAChB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,SAAS,GAAG,SAAS,GAC3B;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAwBnD;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,MAAM,GACZ,gBAAgB,CAuBlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,iBAAiB,GAC5B,gBAAgB,CA6BlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,aAAa,EAAE,GAAG,SAAS,EACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,gBAAgB,CAiBlB;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,YAAY,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,GAAG,SAAS,CAMpB"}
1
+ {"version":3,"file":"query-planner.d.ts","sourceRoot":"","sources":["../src/query-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,SAAS,EACV,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAMpE,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,sCAAsC,CAAC;AAE9C,KAAK,YAAY,GAAG,kBAAkB,CAAC;AA6BvC,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,YAAY,EAChB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,0BAA0B,GACnC,MAAM,CAUR;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,YAAY,EAChB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,0BAA0B,GACnC,MAAM,CAMR;AAED,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,YAAY,EAChB,UAAU,EAAE,MAAM,EAAE,EACpB,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,OAAO,CAAC,EAAE,0BAA0B,GACnC;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAkCnD;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,0BAA0B,GACnC,gBAAgB,CA2BlB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,iBAAiB,EAC7B,OAAO,CAAC,EAAE,0BAA0B,GACnC,gBAAgB,CAiClB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,aAAa,EAAE,GAAG,SAAS,EACpC,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,0BAA0B,GACnC,gBAAgB,CAoBlB;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,YAAY,EAChB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,GAAG,SAAS,CAMpB"}
@@ -1,18 +1,46 @@
1
1
  import { GRAIN_FUNCTIONS } from "./constants.js";
2
2
  import { applyFilteredAggregationExpression } from './utils/filtered-aggregation-sql.js';
3
3
  import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
4
+ import { quoteSQLIdentifier } from './sql-utils.js';
5
+ import { isQualifiedField } from './utils/relationship-fields.js';
6
+ import { qualifyBaseColumn, resolveQualifiedColumn, } from './utils/relationship-builder-plan.js';
4
7
  function toOrderDirection(direction) {
5
8
  return direction === 'asc' ? 'ASC' : 'DESC';
6
9
  }
7
- export function resolveDimensionExpression(ds, dimensionName) {
10
+ /**
11
+ * Raw SQL expressions on the base dataset are emitted verbatim, so their column
12
+ * references are not table-qualified. When relationship joins are active a bare
13
+ * `price` in such an expression is ambiguous if the joined table also has a
14
+ * `price` column. Until the builder rewrites identifiers inside expressions,
15
+ * reject the combination rather than emit ambiguous SQL.
16
+ */
17
+ function assertNoRawSqlUnderJoins(kind, name, sql, joinCtx) {
18
+ if (!joinCtx) {
19
+ return;
20
+ }
21
+ throw new Error(`SQL-backed ${kind} "${name}" cannot be combined with relationship joins: its expression ` +
22
+ `("${sql}") is not table-qualified and may collide with joined columns. Query it without ` +
23
+ `relationship-qualified fields, or redeclare it as a plain column.`);
24
+ }
25
+ export function resolveDimensionExpression(ds, dimensionName, joinCtx) {
26
+ if (joinCtx && isQualifiedField(dimensionName)) {
27
+ return resolveQualifiedColumn(ds, dimensionName);
28
+ }
8
29
  const definition = ds.dimensions[dimensionName];
9
- return definition?.sql ?? definition?.column ?? dimensionName;
30
+ if (definition?.sql) {
31
+ assertNoRawSqlUnderJoins('dimension', dimensionName, definition.sql, joinCtx);
32
+ return definition.sql;
33
+ }
34
+ return qualifyBaseColumn(joinCtx, definition?.column ?? dimensionName);
10
35
  }
11
- export function resolveFilterField(ds, filterField) {
36
+ export function resolveFilterField(ds, filterField, joinCtx) {
37
+ if (joinCtx && isQualifiedField(filterField)) {
38
+ return resolveQualifiedColumn(ds, filterField);
39
+ }
12
40
  const resolvedField = ds.filters[filterField]?.field ?? filterField;
13
- return resolveDimensionExpression(ds, resolvedField);
41
+ return resolveDimensionExpression(ds, resolvedField, joinCtx);
14
42
  }
15
- export function buildDimensionSelectionPlan(ds, dimensions, grain) {
43
+ export function buildDimensionSelectionPlan(ds, dimensions, grain, joinCtx) {
16
44
  const selectParts = [];
17
45
  const groupByParts = new Set();
18
46
  if (grain) {
@@ -20,23 +48,36 @@ export function buildDimensionSelectionPlan(ds, dimensions, grain) {
20
48
  if (!fn) {
21
49
  throw new Error(`Unsupported time grain "${grain}".`);
22
50
  }
23
- selectParts.push(`${fn}(${ds.timeKey}) AS period`);
51
+ selectParts.push(`${fn}(${qualifyBaseColumn(joinCtx, String(ds.timeKey))}) AS period`);
24
52
  groupByParts.add("period");
25
53
  }
26
54
  for (const dimensionName of dimensions) {
27
- const expression = resolveDimensionExpression(ds, dimensionName);
28
- if (expression === dimensionName) {
55
+ const expression = resolveDimensionExpression(ds, dimensionName, joinCtx);
56
+ if (joinCtx) {
57
+ // With joins in scope, every selection is table-qualified and aliased so
58
+ // grouping/ordering can reference the alias unambiguously.
59
+ const alias = isQualifiedField(dimensionName)
60
+ ? quoteSQLIdentifier(dimensionName)
61
+ : dimensionName;
62
+ selectParts.push(`${expression} AS ${alias}`);
63
+ groupByParts.add(alias);
64
+ }
65
+ else if (expression === dimensionName) {
29
66
  selectParts.push(dimensionName);
67
+ groupByParts.add(dimensionName);
30
68
  }
31
69
  else {
32
70
  selectParts.push(`${expression} AS ${dimensionName}`);
71
+ groupByParts.add(dimensionName);
33
72
  }
34
- groupByParts.add(dimensionName);
35
73
  }
36
74
  return { selectParts, groupByParts: Array.from(groupByParts) };
37
75
  }
38
- export function applyAggregationSpec(qb, ds, spec, alias) {
39
- const fieldOrExpr = applyFilteredAggregationExpression(ds, spec, spec.sql ?? resolveDimensionExpression(ds, spec.field));
76
+ export function applyAggregationSpec(qb, ds, spec, alias, joinCtx) {
77
+ if (spec.sql) {
78
+ assertNoRawSqlUnderJoins('measure', alias, spec.sql, joinCtx);
79
+ }
80
+ const fieldOrExpr = applyFilteredAggregationExpression(ds, spec, spec.sql ?? resolveDimensionExpression(ds, spec.field, joinCtx), joinCtx);
40
81
  switch (spec.aggregation) {
41
82
  case "sum":
42
83
  return qb.sum(fieldOrExpr, alias);
@@ -54,14 +95,17 @@ export function applyAggregationSpec(qb, ds, spec, alias) {
54
95
  throw new Error(`Unknown aggregation type: ${spec.aggregation}`);
55
96
  }
56
97
  }
57
- export function applyMeasureDefinition(qb, ds, name, definition) {
58
- const baseFieldOrExpr = definition.sql ?? resolveDimensionExpression(ds, definition.field);
98
+ export function applyMeasureDefinition(qb, ds, name, definition, joinCtx) {
99
+ if (definition.sql) {
100
+ assertNoRawSqlUnderJoins('measure', name, definition.sql, joinCtx);
101
+ }
102
+ const baseFieldOrExpr = definition.sql ?? resolveDimensionExpression(ds, definition.field, joinCtx);
59
103
  const fieldOrExpr = applyFilteredAggregationExpression(ds, {
60
104
  __type: 'aggregation_spec',
61
105
  aggregation: definition.aggregation,
62
106
  field: definition.field,
63
107
  filters: definition.filters,
64
- }, baseFieldOrExpr);
108
+ }, baseFieldOrExpr, joinCtx);
65
109
  switch (definition.aggregation) {
66
110
  case "sum":
67
111
  return qb.sum(fieldOrExpr, name);
@@ -79,10 +123,13 @@ export function applyMeasureDefinition(qb, ds, name, definition) {
79
123
  throw new Error(`Unsupported measure aggregation: ${definition.aggregation}`);
80
124
  }
81
125
  }
82
- export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset) {
126
+ export function appendOrderLimitOffset(qb, orderBy, grain, limit, offset, joinCtx) {
83
127
  if (orderBy && orderBy.length > 0) {
84
128
  for (const order of orderBy) {
85
- qb = qb.orderBy(order.field, toOrderDirection(order.direction));
129
+ const column = joinCtx && isQualifiedField(order.field)
130
+ ? quoteSQLIdentifier(order.field)
131
+ : order.field;
132
+ qb = qb.orderBy(column, toOrderDirection(order.direction));
86
133
  }
87
134
  }
88
135
  else if (grain) {
@@ -18,27 +18,27 @@
18
18
  */
19
19
  import type { RelationshipDefinition } from './types.js';
20
20
  /** Many-to-one relationship (FK on this table). */
21
- export declare function belongsTo(target: () => {
21
+ export declare function belongsTo<TTarget extends {
22
22
  __type: 'dataset';
23
23
  name: string;
24
- }, join: {
24
+ }>(target: () => TTarget, join: {
25
25
  from: string;
26
26
  to: string;
27
- }): RelationshipDefinition;
27
+ }): RelationshipDefinition<TTarget, 'belongsTo'>;
28
28
  /** One-to-many relationship (FK on target table). */
29
- export declare function hasMany(target: () => {
29
+ export declare function hasMany<TTarget extends {
30
30
  __type: 'dataset';
31
31
  name: string;
32
- }, join: {
32
+ }>(target: () => TTarget, join: {
33
33
  from: string;
34
34
  to: string;
35
- }): RelationshipDefinition;
35
+ }): RelationshipDefinition<TTarget, 'hasMany'>;
36
36
  /** One-to-one relationship (FK on target table). */
37
- export declare function hasOne(target: () => {
37
+ export declare function hasOne<TTarget extends {
38
38
  __type: 'dataset';
39
39
  name: string;
40
- }, join: {
40
+ }>(target: () => TTarget, join: {
41
41
  from: string;
42
42
  to: string;
43
- }): RelationshipDefinition;
43
+ }): RelationshipDefinition<TTarget, 'hasOne'>;
44
44
  //# sourceMappingURL=relationships.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../src/relationships.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAoB,MAAM,YAAY,CAAC;AAgB3E,mDAAmD;AACnD,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjD,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAExB;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CACrB,MAAM,EAAE,MAAM;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjD,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAExB;AAED,oDAAoD;AACpD,wBAAgB,MAAM,CACpB,MAAM,EAAE,MAAM;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjD,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAExB"}
1
+ {"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../src/relationships.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAoB,MAAM,YAAY,CAAC;AAmB3E,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,OAAO,SAAS;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC3E,MAAM,EAAE,MAAM,OAAO,EACrB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,CAE9C;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,OAAO,SAAS;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACzE,MAAM,EAAE,MAAM,OAAO,EACrB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAAC,OAAO,EAAE,SAAS,CAAC,CAE5C;AAED,oDAAoD;AACpD,wBAAgB,MAAM,CAAC,OAAO,SAAS;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACxE,MAAM,EAAE,MAAM,OAAO,EACrB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACjC,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAE3C"}
@@ -1,6 +1,16 @@
1
+ /**
2
+ * Database-neutral semantic plan protocol (`PlanNode` / `SemanticBackend`).
3
+ *
4
+ * FROZEN: this execution path is superseded by the query-builder path —
5
+ * `createDatasetClient({ queryBuilder })` is the canonical way to execute
6
+ * semantic queries. The plan/backend protocol receives bug fixes only; new
7
+ * semantic features land on the query-builder path and are not guaranteed to
8
+ * be mirrored here.
9
+ */
1
10
  import type { AggregationType, FieldType, MetricFilter, MetricOrderBy, TimeGrain } from './types.js';
2
11
  export type SemanticBinaryOperator = 'add' | 'subtract' | 'multiply' | 'divide';
3
12
  export type SemanticFunctionName = 'nullIfZero' | 'coalesce' | 'round' | 'floor' | 'ceil';
13
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
4
14
  export type SemanticExpression = {
5
15
  kind: 'ref';
6
16
  name: string;
@@ -17,17 +27,43 @@ export type SemanticExpression = {
17
27
  name: SemanticFunctionName;
18
28
  args: SemanticExpression[];
19
29
  };
30
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
20
31
  export interface SemanticDimensionPlan {
21
32
  name: string;
22
33
  field: string;
23
34
  fieldType?: FieldType;
24
35
  }
36
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
25
37
  export interface SemanticAggregationPlan {
26
38
  name: string;
27
39
  aggregation: AggregationType;
28
40
  field: string;
29
41
  filters?: MetricFilter[];
30
42
  }
43
+ export type SemanticTenantPredicate = {
44
+ field: string;
45
+ operator: 'eq';
46
+ value: string;
47
+ } | {
48
+ field: string;
49
+ operator: 'in';
50
+ value: string[];
51
+ };
52
+ /**
53
+ * A query-time LEFT JOIN for a to-one relationship. `relationship` is the alias
54
+ * used to qualify joined columns (`<relationship>.<column>`); `from`/`to` are
55
+ * the unqualified base and target join columns. An optional `tenant` predicate
56
+ * scopes the joined target when runtime tenancy is active on the target.
57
+ */
58
+ export interface SemanticJoinPlan {
59
+ relationship: string;
60
+ source: string;
61
+ from: string;
62
+ to: string;
63
+ type: 'left';
64
+ tenant?: SemanticTenantPredicate;
65
+ }
66
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
31
67
  export interface SemanticGrainPlan {
32
68
  field: string;
33
69
  unit: TimeGrain;
@@ -35,6 +71,7 @@ export interface SemanticGrainPlan {
35
71
  timezone?: string;
36
72
  weekStart?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
37
73
  }
74
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
38
75
  export type PlanNode = {
39
76
  kind: 'aggregate';
40
77
  source: string;
@@ -45,15 +82,13 @@ export type PlanNode = {
45
82
  orderBy?: MetricOrderBy[];
46
83
  limit?: number;
47
84
  offset?: number;
48
- tenant?: {
49
- field: string;
50
- operator: 'eq';
51
- value: string;
52
- } | {
53
- field: string;
54
- operator: 'in';
55
- value: string[];
56
- };
85
+ tenant?: SemanticTenantPredicate;
86
+ /**
87
+ * To-one relationship LEFT JOINs. When present, joined columns referenced by
88
+ * dimensions/filters are qualified as `<relationship>.<column>`; base columns
89
+ * stay unqualified (SQL backends qualify them with `source` as needed).
90
+ */
91
+ joins?: SemanticJoinPlan[];
57
92
  } | {
58
93
  kind: 'derive';
59
94
  input: PlanNode;
@@ -65,6 +100,7 @@ export type PlanNode = {
65
100
  limit?: number;
66
101
  offset?: number;
67
102
  };
103
+ /** @deprecated Part of the frozen plan/backend protocol; use `createDatasetClient({ queryBuilder })` instead. */
68
104
  export interface SemanticBackendResult<T = Record<string, unknown>> {
69
105
  data: T[];
70
106
  meta?: {
@@ -73,6 +109,11 @@ export interface SemanticBackendResult<T = Record<string, unknown>> {
73
109
  tenant?: string;
74
110
  };
75
111
  }
112
+ /**
113
+ * @deprecated The plan/backend execution path is frozen (bug fixes only).
114
+ * Pass a query builder to `createDatasetClient({ queryBuilder })` instead of
115
+ * implementing a backend.
116
+ */
76
117
  export interface SemanticBackend {
77
118
  execute<T = Record<string, unknown>>(plan: PlanNode): Promise<SemanticBackendResult<T>>;
78
119
  explain?(plan: PlanNode): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-plan.d.ts","sourceRoot":"","sources":["../src/semantic-plan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"semantic-plan.d.ts","sourceRoot":"","sources":["../src/semantic-plan.ts"],"names":[],"mappings":"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"}
@@ -1 +1,10 @@
1
+ /**
2
+ * Database-neutral semantic plan protocol (`PlanNode` / `SemanticBackend`).
3
+ *
4
+ * FROZEN: this execution path is superseded by the query-builder path —
5
+ * `createDatasetClient({ queryBuilder })` is the canonical way to execute
6
+ * semantic queries. The plan/backend protocol receives bug fixes only; new
7
+ * semantic features land on the query-builder path and are not guaranteed to
8
+ * be mirrored here.
9
+ */
1
10
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-planner.d.ts","sourceRoot":"","sources":["../src/semantic-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,oBAAoB,CAAC;AAgH5B,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,kBAAkB,EACtB,KAAK,GAAE,YAAiB,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAaV;AAuFD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,GAAE,WAAgB,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAUV"}
1
+ {"version":3,"file":"semantic-planner.d.ts","sourceRoot":"","sources":["../src/semantic-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAGhB,WAAW,EACX,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,QAAQ,EAIT,MAAM,oBAAoB,CAAC;AAuL5B,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,kBAAkB,EACtB,KAAK,GAAE,YAAiB,EACxB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAaV;AAuFD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,GAAE,WAAgB,EACvB,OAAO,CAAC,EAAE,gBAAgB,GACzB,QAAQ,CAUV"}
@@ -2,6 +2,7 @@ import { getMetricGrain, getMetricRef, } from './utils/metric-handle.js';
2
2
  import { validateDatasetQuery } from './dataset-query.js';
3
3
  import { isSupportedTimeGrain } from './constants.js';
4
4
  import { getRuntimeTenantPredicate } from './utils/tenant-runtime.js';
5
+ import { isQualifiedField, resolveQualifiedField } from './utils/relationship-fields.js';
5
6
  function resolveField(ds, field) {
6
7
  const dimension = ds.dimensions[field];
7
8
  if (dimension?.sql) {
@@ -10,15 +11,41 @@ function resolveField(ds, field) {
10
11
  }
11
12
  return dimension?.column ?? field;
12
13
  }
14
+ /**
15
+ * Resolves a relationship-qualified field to its plan field name
16
+ * (`<relationship>.<targetColumn>`). Validation runs before planning, so an
17
+ * unresolved qualified name here is a programming error.
18
+ */
19
+ function resolveQualifiedPlanField(ds, name) {
20
+ const resolution = resolveQualifiedField(ds, name);
21
+ if (!resolution || !resolution.resolved) {
22
+ throw new Error(resolution?.error ?? `Cannot resolve relationship field "${name}".`);
23
+ }
24
+ return resolution.resolved;
25
+ }
13
26
  function dimensionsForQuery(ds, dimensions = []) {
14
- return dimensions.map((name) => ({
15
- name,
16
- field: resolveField(ds, name),
17
- fieldType: ds.dimensions[name]?.fieldType,
18
- }));
27
+ return dimensions.map((name) => {
28
+ if (isQualifiedField(name)) {
29
+ const { relationshipName, targetColumn, targetDimension } = resolveQualifiedPlanField(ds, name);
30
+ return {
31
+ name,
32
+ field: `${relationshipName}.${targetColumn}`,
33
+ fieldType: targetDimension.fieldType,
34
+ };
35
+ }
36
+ return {
37
+ name,
38
+ field: resolveField(ds, name),
39
+ fieldType: ds.dimensions[name]?.fieldType,
40
+ };
41
+ });
19
42
  }
20
43
  function normalizeFilters(ds, filters = []) {
21
44
  return filters.map((filter) => {
45
+ if (isQualifiedField(filter.field)) {
46
+ const { relationshipName, targetColumn } = resolveQualifiedPlanField(ds, filter.field);
47
+ return { ...filter, field: `${relationshipName}.${targetColumn}` };
48
+ }
22
49
  const resolvedField = ds.filters[filter.field]?.field ?? filter.field;
23
50
  return {
24
51
  ...filter,
@@ -26,6 +53,40 @@ function normalizeFilters(ds, filters = []) {
26
53
  };
27
54
  });
28
55
  }
56
+ /**
57
+ * Collects deduped to-one LEFT JOINs for every relationship referenced by the
58
+ * query's dimensions, filters, or orderBy, scoping each joined target with the
59
+ * runtime tenant predicate when the target declares a `tenantKey`.
60
+ */
61
+ function collectJoins(ds, dimensions = [], filters = [], orderBy = [], context) {
62
+ const referenced = [
63
+ ...dimensions,
64
+ ...filters.map((filter) => filter.field),
65
+ ...orderBy.map((order) => order.field),
66
+ ].filter(isQualifiedField);
67
+ if (referenced.length === 0) {
68
+ return undefined;
69
+ }
70
+ const tenantPredicate = getRuntimeTenantPredicate(context);
71
+ const joins = new Map();
72
+ for (const name of referenced) {
73
+ const { relationshipName, relationship, target } = resolveQualifiedPlanField(ds, name);
74
+ if (joins.has(relationshipName)) {
75
+ continue;
76
+ }
77
+ joins.set(relationshipName, {
78
+ relationship: relationshipName,
79
+ source: target.source,
80
+ from: relationship.from,
81
+ to: relationship.to,
82
+ type: 'left',
83
+ tenant: tenantPredicate && target.tenantKey
84
+ ? { field: target.tenantKey, ...tenantPredicate }
85
+ : undefined,
86
+ });
87
+ }
88
+ return Array.from(joins.values());
89
+ }
29
90
  function aggregationForMeasure(ds, name) {
30
91
  const measure = ds.measures[name];
31
92
  if (!measure) {
@@ -77,6 +138,7 @@ function aggregatePlan(ds, query, aggregations, context) {
77
138
  limit: query.limit,
78
139
  offset: query.offset,
79
140
  tenant: tenantForContext(ds, context),
141
+ joins: collectJoins(ds, query.dimensions, query.filters, query.orderBy, context),
80
142
  };
81
143
  }
82
144
  export function buildDatasetPlan(ds, query = {}, context) {
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EAIjB,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtE;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,OAAO,CACL,MAAM,EAAE,kBAAkB,GAAG,YAAY,EACzC,KAAK,CAAC,EAAE,YAAY,GAAG,WAAW,EAClC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC/C,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,UAAU,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;CACzB;AA8VD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,sBAAsB,EAAE,CAenG;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,oBAAoB,EAAE,CASrF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAWjG;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,iBAAiB,EAAE,CAM/E;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,WAAW,EAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EAKjB,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAGtB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtE;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,aAAa,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,OAAO,CACL,MAAM,EAAE,kBAAkB,GAAG,YAAY,EACzC,KAAK,CAAC,EAAE,YAAY,GAAG,WAAW,EAClC,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC/C,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,UAAU,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;CACzB;AAoXD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,sBAAsB,EAAE,CAenG;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,oBAAoB,EAAE,CASrF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAWjG;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,sBAAsB,EAAE,GAAG,iBAAiB,EAAE,CAM/E;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}