@hypequery/datasets 0.23.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/aggregations.d.ts +3 -0
- package/dist/aggregations.d.ts.map +1 -1
- package/dist/aggregations.js +6 -0
- package/dist/cache/definition-identity.d.ts +9 -6
- package/dist/cache/definition-identity.d.ts.map +1 -1
- package/dist/cache/definition-identity.js +14 -8
- package/dist/cache/protocol-cache-keys.d.ts.map +1 -1
- package/dist/cache/protocol-cache-keys.js +29 -6
- package/dist/cache/query-signature.d.ts.map +1 -1
- package/dist/cache/query-signature.js +12 -1
- package/dist/catalog.d.ts +7 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +5 -2
- package/dist/client-contract/query-schema.d.ts +19 -0
- package/dist/client-contract/query-schema.d.ts.map +1 -0
- package/dist/client-contract/query-schema.js +85 -0
- package/dist/constants.d.ts +5 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -6
- package/dist/contract.d.ts +5 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +6 -3
- package/dist/dataset-compilation.d.ts +2 -0
- package/dist/dataset-compilation.d.ts.map +1 -1
- package/dist/dataset-sql-dialect.d.ts +119 -0
- package/dist/dataset-sql-dialect.d.ts.map +1 -1
- package/dist/dataset.d.ts +4 -2
- package/dist/dataset.d.ts.map +1 -1
- package/dist/dataset.js +23 -31
- package/dist/in-memory-backend.d.ts.map +1 -1
- package/dist/in-memory-backend.js +2 -0
- package/dist/index.d.ts +49 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -6
- package/dist/internal.d.ts +5 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -1
- package/dist/measure.d.ts +9 -1
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +9 -1
- package/dist/metric-query-engine.d.ts +0 -1
- package/dist/metric-query-engine.d.ts.map +1 -1
- package/dist/metric-query-engine.js +11 -3
- package/dist/protocol-adapter.d.ts.map +1 -1
- package/dist/protocol-adapter.js +2 -3
- package/dist/protocol-deployment-adapter.d.ts.map +1 -1
- package/dist/protocol-deployment-adapter.js +7 -1
- package/dist/protocol-rehydrate.d.ts.map +1 -1
- package/dist/protocol-rehydrate.js +1 -0
- package/dist/protocol-schema-adapter.d.ts +7 -7
- package/dist/protocol-schema-adapter.d.ts.map +1 -1
- package/dist/protocol-schema-adapter.js +12 -245
- package/dist/query-builder-protocol.d.ts +34 -1
- package/dist/query-builder-protocol.d.ts.map +1 -1
- package/dist/query-planner.d.ts +14 -5
- package/dist/query-planner.d.ts.map +1 -1
- package/dist/query-planner.js +53 -34
- package/dist/relationship-check.d.ts.map +1 -1
- package/dist/relationship-check.js +8 -8
- package/dist/schemas.d.ts +17 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +16 -0
- package/dist/semantic-planner.d.ts.map +1 -1
- package/dist/semantic-planner.js +49 -13
- package/dist/semantic-query-schema.d.ts +8 -1
- package/dist/semantic-query-schema.d.ts.map +1 -1
- package/dist/semantic-query-schema.js +18 -12
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +4 -3
- package/dist/types.d.ts +105 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/aggregate-state-functions.d.ts +24 -0
- package/dist/utils/aggregate-state-functions.d.ts.map +1 -0
- package/dist/utils/aggregate-state-functions.js +60 -0
- package/dist/utils/approximate-measures.d.ts +3 -1
- package/dist/utils/approximate-measures.d.ts.map +1 -1
- package/dist/utils/approximate-measures.js +8 -2
- package/dist/utils/base-measure-definition.d.ts +16 -0
- package/dist/utils/base-measure-definition.d.ts.map +1 -1
- package/dist/utils/base-measure-definition.js +31 -0
- package/dist/utils/build-dataset-query-builder.d.ts +1 -1
- package/dist/utils/build-dataset-query-builder.d.ts.map +1 -1
- package/dist/utils/build-dataset-query-builder.js +26 -21
- package/dist/utils/by-name.d.ts +8 -0
- package/dist/utils/by-name.d.ts.map +1 -0
- package/dist/utils/by-name.js +44 -0
- package/dist/utils/calendar-shift-sql.d.ts +5 -4
- package/dist/utils/calendar-shift-sql.d.ts.map +1 -1
- package/dist/utils/calendar-shift-sql.js +8 -8
- package/dist/utils/clickhouse-dataset-sql-dialect.d.ts +2 -2
- package/dist/utils/clickhouse-dataset-sql-dialect.d.ts.map +1 -1
- package/dist/utils/clickhouse-dataset-sql-dialect.js +143 -1
- package/dist/utils/compile-dataset-query.d.ts +1 -1
- package/dist/utils/compile-dataset-query.d.ts.map +1 -1
- package/dist/utils/compile-dataset-query.js +22 -8
- package/dist/utils/composite-time-measure-sql.d.ts +3 -5
- package/dist/utils/composite-time-measure-sql.d.ts.map +1 -1
- package/dist/utils/composite-time-measure-sql.js +15 -16
- package/dist/utils/count-aggregations.d.ts +4 -0
- package/dist/utils/count-aggregations.d.ts.map +1 -0
- package/dist/utils/count-aggregations.js +6 -0
- package/dist/utils/dataset-definition-validation.d.ts +1 -1
- package/dist/utils/dataset-definition-validation.d.ts.map +1 -1
- package/dist/utils/dataset-definition-validation.js +55 -26
- package/dist/utils/dataset-derived-query.d.ts +2 -4
- package/dist/utils/dataset-derived-query.d.ts.map +1 -1
- package/dist/utils/dataset-derived-query.js +11 -14
- package/dist/utils/dataset-having.d.ts +5 -7
- package/dist/utils/dataset-having.d.ts.map +1 -1
- package/dist/utils/dataset-having.js +9 -12
- package/dist/utils/dataset-normalization.d.ts.map +1 -1
- package/dist/utils/dataset-normalization.js +1 -0
- package/dist/utils/dataset-query-validation.d.ts +1 -1
- package/dist/utils/dataset-query-validation.d.ts.map +1 -1
- package/dist/utils/dataset-query-validation.js +19 -2
- package/dist/utils/dataset-source.d.ts +42 -0
- package/dist/utils/dataset-source.d.ts.map +1 -0
- package/dist/utils/dataset-source.js +59 -0
- package/dist/utils/dataset-sql-dialect.d.ts +13 -2
- package/dist/utils/dataset-sql-dialect.d.ts.map +1 -1
- package/dist/utils/dataset-sql-dialect.js +74 -1
- package/dist/utils/dataset-time-keys.d.ts +32 -0
- package/dist/utils/dataset-time-keys.d.ts.map +1 -0
- package/dist/utils/dataset-time-keys.js +55 -0
- package/dist/utils/dataset-validation.d.ts.map +1 -1
- package/dist/utils/dataset-validation.js +7 -0
- package/dist/utils/deployable-formulas.d.ts +33 -0
- package/dist/utils/deployable-formulas.d.ts.map +1 -0
- package/dist/utils/deployable-formulas.js +102 -0
- package/dist/utils/derived-cte-validation.d.ts +5 -0
- package/dist/utils/derived-cte-validation.d.ts.map +1 -1
- package/dist/utils/derived-cte-validation.js +77 -8
- package/dist/utils/derived-measure-sql.d.ts +10 -2
- package/dist/utils/derived-measure-sql.d.ts.map +1 -1
- package/dist/utils/derived-measure-sql.js +23 -43
- package/dist/utils/enforced-constraints.d.ts +14 -0
- package/dist/utils/enforced-constraints.d.ts.map +1 -0
- package/dist/utils/enforced-constraints.js +57 -0
- package/dist/utils/filter-field-type.d.ts +14 -0
- package/dist/utils/filter-field-type.d.ts.map +1 -0
- package/dist/utils/filter-field-type.js +21 -0
- package/dist/utils/filtered-aggregation-sql.d.ts +2 -1
- package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -1
- package/dist/utils/filtered-aggregation-sql.js +18 -35
- package/dist/utils/groupable.d.ts +7 -0
- package/dist/utils/groupable.d.ts.map +1 -0
- package/dist/utils/groupable.js +8 -0
- package/dist/utils/metric-derived-query.d.ts +2 -4
- package/dist/utils/metric-derived-query.d.ts.map +1 -1
- package/dist/utils/metric-derived-query.js +58 -51
- package/dist/utils/metric-query-builder.d.ts +1 -1
- package/dist/utils/metric-query-builder.d.ts.map +1 -1
- package/dist/utils/metric-query-builder.js +22 -20
- package/dist/utils/metric-query-validation.d.ts.map +1 -1
- package/dist/utils/metric-query-validation.js +14 -1
- package/dist/utils/portable-aggregations.d.ts +1 -0
- package/dist/utils/portable-aggregations.d.ts.map +1 -1
- package/dist/utils/portable-aggregations.js +5 -0
- package/dist/utils/protocol-schema-conversion.d.ts +12 -0
- package/dist/utils/protocol-schema-conversion.d.ts.map +1 -0
- package/dist/utils/protocol-schema-conversion.js +61 -0
- package/dist/utils/query-field-references.d.ts +10 -0
- package/dist/utils/query-field-references.d.ts.map +1 -0
- package/dist/utils/query-field-references.js +38 -0
- package/dist/utils/query-timezone.d.ts +41 -3
- package/dist/utils/query-timezone.d.ts.map +1 -1
- package/dist/utils/query-timezone.js +76 -9
- package/dist/utils/raw-sql-dialect-check.d.ts +12 -0
- package/dist/utils/raw-sql-dialect-check.d.ts.map +1 -0
- package/dist/utils/raw-sql-dialect-check.js +37 -0
- package/dist/utils/relationship-builder-plan.d.ts +37 -18
- package/dist/utils/relationship-builder-plan.d.ts.map +1 -1
- package/dist/utils/relationship-builder-plan.js +43 -28
- package/dist/utils/relationship-measure-sql.d.ts +14 -4
- package/dist/utils/relationship-measure-sql.d.ts.map +1 -1
- package/dist/utils/relationship-measure-sql.js +36 -10
- package/dist/utils/relationship-measures.d.ts.map +1 -1
- package/dist/utils/relationship-measures.js +3 -0
- package/dist/utils/relationship-validation.d.ts.map +1 -1
- package/dist/utils/relationship-validation.js +2 -0
- package/dist/utils/row-scope.d.ts +23 -0
- package/dist/utils/row-scope.d.ts.map +1 -0
- package/dist/utils/row-scope.js +26 -0
- package/dist/utils/scoped-dataset-source.d.ts +23 -0
- package/dist/utils/scoped-dataset-source.d.ts.map +1 -0
- package/dist/utils/scoped-dataset-source.js +34 -0
- package/dist/utils/semantic-tool.d.ts +2 -2
- package/dist/utils/semantic-tool.d.ts.map +1 -1
- package/dist/utils/semantic-tool.js +1 -1
- package/dist/utils/shift-measure-sql.d.ts +5 -4
- package/dist/utils/shift-measure-sql.d.ts.map +1 -1
- package/dist/utils/shift-measure-sql.js +25 -26
- package/dist/utils/shift-wall-time-sql.d.ts +2 -1
- package/dist/utils/shift-wall-time-sql.d.ts.map +1 -1
- package/dist/utils/shift-wall-time-sql.js +7 -7
- package/dist/utils/snapshot-execution-context.d.ts.map +1 -1
- package/dist/utils/snapshot-execution-context.js +3 -0
- package/dist/utils/statement-parameters.d.ts +58 -0
- package/dist/utils/statement-parameters.d.ts.map +1 -0
- package/dist/utils/statement-parameters.js +101 -0
- package/dist/utils/time-axis-calendar-guard.d.ts +2 -1
- package/dist/utils/time-axis-calendar-guard.d.ts.map +1 -1
- package/dist/utils/time-axis-calendar-guard.js +5 -7
- package/dist/utils/time-measure-axis-sql.d.ts +3 -2
- package/dist/utils/time-measure-axis-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-axis-sql.js +20 -22
- package/dist/utils/time-measure-context-sql.d.ts +3 -2
- package/dist/utils/time-measure-context-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-context-sql.js +11 -11
- package/dist/utils/time-measure-dataset-sql.d.ts +7 -5
- package/dist/utils/time-measure-dataset-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-dataset-sql.js +17 -12
- package/dist/utils/time-measure-leaf-sql.d.ts +3 -2
- package/dist/utils/time-measure-leaf-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-leaf-sql.js +19 -18
- package/dist/utils/time-measure-result-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-result-sql.js +10 -11
- package/dist/utils/time-measure-source-sql.d.ts +5 -2
- package/dist/utils/time-measure-source-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-source-sql.js +33 -23
- package/dist/utils/time-measure-values-sql.d.ts +4 -3
- package/dist/utils/time-measure-values-sql.d.ts.map +1 -1
- package/dist/utils/time-measure-values-sql.js +26 -29
- package/dist/utils/timestamp-instants.d.ts +17 -0
- package/dist/utils/timestamp-instants.d.ts.map +1 -0
- package/dist/utils/timestamp-instants.js +34 -0
- package/dist/utils/timestamp-text.d.ts +12 -0
- package/dist/utils/timestamp-text.d.ts.map +1 -0
- package/dist/utils/timestamp-text.js +18 -0
- package/dist/utils/zod-json-schema.d.ts +8 -0
- package/dist/utils/zod-json-schema.d.ts.map +1 -0
- package/dist/utils/zod-json-schema.js +18 -0
- package/dist/utils/zod-schema-version.d.ts +19 -0
- package/dist/utils/zod-schema-version.d.ts.map +1 -0
- package/dist/utils/zod-schema-version.js +6 -0
- package/dist/utils/zod-v3-protocol-schema.d.ts +10 -0
- package/dist/utils/zod-v3-protocol-schema.d.ts.map +1 -0
- package/dist/utils/zod-v3-protocol-schema.js +164 -0
- package/dist/utils/zod-v4-protocol-schema.d.ts +12 -0
- package/dist/utils/zod-v4-protocol-schema.d.ts.map +1 -0
- package/dist/utils/zod-v4-protocol-schema.js +171 -0
- package/dist/validation.d.ts +7 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +42 -8
- package/package.json +21 -12
- package/dist/api.type-test.d.ts +0 -2
- package/dist/api.type-test.d.ts.map +0 -1
- package/dist/api.type-test.js +0 -251
- package/dist/utils/time-arithmetic-sql.d.ts +0 -4
- package/dist/utils/time-arithmetic-sql.d.ts.map +0 -1
- package/dist/utils/time-arithmetic-sql.js +0 -9
- package/dist/utils/window-aggregation-sql.d.ts +0 -5
- package/dist/utils/window-aggregation-sql.d.ts.map +0 -1
- package/dist/utils/window-aggregation-sql.js +0 -17
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnyDatasetInstance, ExecutionContext, MetricFilter } from '../types.js';
|
|
2
|
+
import type { QueryBuilderLike } from '../query-builder-protocol.js';
|
|
3
|
+
import { type TenantPredicate } from './tenant-runtime.js';
|
|
4
|
+
/** A trusted predicate on one of a dataset's own physical columns. */
|
|
5
|
+
export type RowScopePredicate = TenantPredicate & {
|
|
6
|
+
readonly column: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The trusted predicates restricting which source rows of `ds` any query may
|
|
10
|
+
* read (RFC 0020). They apply to the queried dataset and to every joined
|
|
11
|
+
* relationship target alike. `tenantKey` with a runtime tenant lowers to one
|
|
12
|
+
* predicate; the trusted cross-tenant scope (`scope: 'all'`) lowers to none.
|
|
13
|
+
*/
|
|
14
|
+
export declare function datasetRowScope(ds: Pick<AnyDatasetInstance, 'tenantKey'>, context?: ExecutionContext): RowScopePredicate[];
|
|
15
|
+
/**
|
|
16
|
+
* The call's RFC 0019 enforced constraints, from trusted context only. They
|
|
17
|
+
* apply to the queried dataset, in its filter vocabulary, never to joined
|
|
18
|
+
* targets.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runtimeConstraints(context?: ExecutionContext): readonly MetricFilter[];
|
|
21
|
+
/** ANDs each row-scope predicate onto `qb`, with columns qualified by `qualify`. */
|
|
22
|
+
export declare function applyRowScope(qb: QueryBuilderLike, scope: readonly RowScopePredicate[], qualify?: (column: string) => string): QueryBuilderLike;
|
|
23
|
+
//# sourceMappingURL=row-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-scope.d.ts","sourceRoot":"","sources":["../../src/utils/row-scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtF,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,EACzC,OAAO,CAAC,EAAE,gBAAgB,GACzB,iBAAiB,EAAE,CAGrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,YAAY,EAAE,CAEtF;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAC3B,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,OAAO,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAyB,GACrD,gBAAgB,CAKlB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getRuntimeTenantPredicate } from './tenant-runtime.js';
|
|
2
|
+
/**
|
|
3
|
+
* The trusted predicates restricting which source rows of `ds` any query may
|
|
4
|
+
* read (RFC 0020). They apply to the queried dataset and to every joined
|
|
5
|
+
* relationship target alike. `tenantKey` with a runtime tenant lowers to one
|
|
6
|
+
* predicate; the trusted cross-tenant scope (`scope: 'all'`) lowers to none.
|
|
7
|
+
*/
|
|
8
|
+
export function datasetRowScope(ds, context) {
|
|
9
|
+
const tenant = getRuntimeTenantPredicate(context);
|
|
10
|
+
return tenant && ds.tenantKey ? [{ column: ds.tenantKey, ...tenant }] : [];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The call's RFC 0019 enforced constraints, from trusted context only. They
|
|
14
|
+
* apply to the queried dataset, in its filter vocabulary, never to joined
|
|
15
|
+
* targets.
|
|
16
|
+
*/
|
|
17
|
+
export function runtimeConstraints(context) {
|
|
18
|
+
return context?.runtime?.constraints ?? [];
|
|
19
|
+
}
|
|
20
|
+
/** ANDs each row-scope predicate onto `qb`, with columns qualified by `qualify`. */
|
|
21
|
+
export function applyRowScope(qb, scope, qualify = column => column) {
|
|
22
|
+
for (const predicate of scope) {
|
|
23
|
+
qb = qb.where(qualify(predicate.column), predicate.operator, predicate.value);
|
|
24
|
+
}
|
|
25
|
+
return qb;
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnyDatasetInstance, ExecutionContext } from '../types.js';
|
|
2
|
+
import type { QueryBuilderFactoryLike, QueryBuilderLike } from '../query-builder-protocol.js';
|
|
3
|
+
import type { DatasetSqlDialectRules } from '../dataset-sql-dialect.js';
|
|
4
|
+
import { type RelationshipBuilderContext } from './relationship-builder-plan.js';
|
|
5
|
+
export interface ScopedDatasetSourceOptions {
|
|
6
|
+
builderFactory: Pick<QueryBuilderFactoryLike, 'table'>;
|
|
7
|
+
ds: AnyDatasetInstance;
|
|
8
|
+
context?: ExecutionContext;
|
|
9
|
+
joinCtx: RelationshipBuilderContext | undefined;
|
|
10
|
+
dialect: DatasetSqlDialectRules;
|
|
11
|
+
timezone: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The dataset's source as a builder with every trusted row restriction
|
|
15
|
+
* applied (RFC 0020): `FINAL`, relationship joins scoped by each target's own
|
|
16
|
+
* row scope, the dataset's row scope, and the call's enforced constraints.
|
|
17
|
+
*
|
|
18
|
+
* Every builder-path query shape reads its source through here, so none can
|
|
19
|
+
* read rows the context does not allow. Callers add their own selections,
|
|
20
|
+
* filters and aggregations on top; every predicate here is ANDed with them.
|
|
21
|
+
*/
|
|
22
|
+
export declare function scopedDatasetSource(options: ScopedDatasetSourceOptions): QueryBuilderLike;
|
|
23
|
+
//# sourceMappingURL=scoped-dataset-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scoped-dataset-source.d.ts","sourceRoot":"","sources":["../../src/utils/scoped-dataset-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAIxE,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,gCAAgC,CAAC;AAIxC,MAAM,WAAW,0BAA0B;IACzC,cAAc,EAAE,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;IACvD,EAAE,EAAE,kBAAkB,CAAC;IACvB,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAChD,OAAO,EAAE,sBAAsB,CAAC;IAChC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,gBAAgB,CAiBzF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolveFilterField } from '../query-planner.js';
|
|
2
|
+
import { FINAL_SAFETY_SETTINGS, datasetSourceBuilder, queryReadsFinal } from './dataset-source.js';
|
|
3
|
+
import { queryTimeFilter } from './query-timezone.js';
|
|
4
|
+
import { applyRelationshipJoins, qualifyBaseColumn, } from './relationship-builder-plan.js';
|
|
5
|
+
import { assertEnforcedConstraints } from './enforced-constraints.js';
|
|
6
|
+
import { applyRowScope, datasetRowScope, runtimeConstraints } from './row-scope.js';
|
|
7
|
+
/**
|
|
8
|
+
* The dataset's source as a builder with every trusted row restriction
|
|
9
|
+
* applied (RFC 0020): `FINAL`, relationship joins scoped by each target's own
|
|
10
|
+
* row scope, the dataset's row scope, and the call's enforced constraints.
|
|
11
|
+
*
|
|
12
|
+
* Every builder-path query shape reads its source through here, so none can
|
|
13
|
+
* read rows the context does not allow. Callers add their own selections,
|
|
14
|
+
* filters and aggregations on top; every predicate here is ANDed with them.
|
|
15
|
+
*/
|
|
16
|
+
export function scopedDatasetSource(options) {
|
|
17
|
+
const { ds, context, joinCtx, dialect, timezone } = options;
|
|
18
|
+
// Validators report this too; checked here so no path can skip it.
|
|
19
|
+
assertEnforcedConstraints(ds, context);
|
|
20
|
+
let qb = applyRelationshipJoins(datasetSourceBuilder(options.builderFactory, ds), joinCtx);
|
|
21
|
+
// A resolved join target is read with FINAL even when this dataset isn't.
|
|
22
|
+
if (queryReadsFinal(ds, joinCtx) && qb.settings)
|
|
23
|
+
qb = qb.settings(FINAL_SAFETY_SETTINGS);
|
|
24
|
+
qb = applyRowScope(qb, datasetRowScope(ds, context), column => qualifyBaseColumn(joinCtx, column));
|
|
25
|
+
// Constraints are filters in the dataset's vocabulary, applied exactly as a
|
|
26
|
+
// caller filter on the same field would be.
|
|
27
|
+
for (const constraint of runtimeConstraints(context)) {
|
|
28
|
+
const expression = resolveFilterField(ds, constraint.field, joinCtx);
|
|
29
|
+
for (const predicate of queryTimeFilter(dialect, ds, constraint, expression, timezone)) {
|
|
30
|
+
qb = qb.where(predicate.expression, predicate.operator, predicate.value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return qb;
|
|
34
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ZodType } from 'zod';
|
|
2
2
|
export declare function semanticToolNamePart(name: string): string;
|
|
3
|
-
export declare function parseCanonicalToolInput(schema:
|
|
3
|
+
export declare function parseCanonicalToolInput(schema: ZodType, input: Record<string, unknown>, label: string): Record<string, unknown>;
|
|
4
4
|
export declare function redactSemanticToolSql(result: unknown, includeSql: boolean): unknown;
|
|
5
5
|
//# sourceMappingURL=semantic-tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-tool.d.ts","sourceRoot":"","sources":["../../src/utils/semantic-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"semantic-tool.d.ts","sourceRoot":"","sources":["../../src/utils/semantic-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAEnC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,OAAO,CAenF"}
|
|
@@ -6,7 +6,7 @@ export function parseCanonicalToolInput(schema, input, label) {
|
|
|
6
6
|
const result = schema.safeParse(input);
|
|
7
7
|
if (!result.success) {
|
|
8
8
|
const issues = result.error.issues.map((issue) => {
|
|
9
|
-
const path = issue.path.length > 0 ? issue.path.join('.') : 'input';
|
|
9
|
+
const path = issue.path.length > 0 ? issue.path.map(String).join('.') : 'input';
|
|
10
10
|
return `${path}: ${issue.message}`;
|
|
11
11
|
}).join('; ');
|
|
12
12
|
throw new Error(`Invalid ${label}: ${issues}`);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { DatasetSqlDialectRules } from '../dataset-sql-dialect.js';
|
|
1
2
|
import type { ShiftMeasureDefinition } from '../types.js';
|
|
2
3
|
import type { TimeMeasureAxis } from './time-measure-axis.js';
|
|
3
4
|
/** Preserve the selected portion of a bucket and both authored endpoint operators. */
|
|
4
|
-
export declare function shiftRangeSql(shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, period?: string): {
|
|
5
|
+
export declare function shiftRangeSql(dialect: DatasetSqlDialectRules, shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, period?: string): {
|
|
5
6
|
lower: string;
|
|
6
7
|
upper: string;
|
|
7
8
|
lowerInclusive: string;
|
|
@@ -9,11 +10,11 @@ export declare function shiftRangeSql(shift: ShiftMeasureDefinition, axis: TimeM
|
|
|
9
10
|
};
|
|
10
11
|
export declare function shiftRangePredicateSql(time: string, range: ReturnType<typeof shiftRangeSql>): string;
|
|
11
12
|
/** Check the shifted scan independently of whether it contains source rows. */
|
|
12
|
-
export declare function shiftCalendarGuardSql(shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, axisGuard: string): string;
|
|
13
|
+
export declare function shiftCalendarGuardSql(dialect: DatasetSqlDialectRules, shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, axisGuard: string): string;
|
|
13
14
|
/** Validate each output bucket after the series exists, including empty source populations. */
|
|
14
|
-
export declare function shiftWallTimeSeriesGuardSql(shift: ShiftMeasureDefinition, grain: TimeMeasureAxis['grain']): string;
|
|
15
|
+
export declare function shiftWallTimeSeriesGuardSql(dialect: DatasetSqlDialectRules, shift: ShiftMeasureDefinition, grain: TimeMeasureAxis['grain']): string;
|
|
15
16
|
/** Map output buckets to their earlier half-open ranges, retaining calendar arithmetic. */
|
|
16
|
-
export declare function shiftBucketCtes(shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, index: number): {
|
|
17
|
+
export declare function shiftBucketCtes(dialect: DatasetSqlDialectRules, shift: ShiftMeasureDefinition, axis: TimeMeasureAxis, index: number): {
|
|
17
18
|
ctes: string[];
|
|
18
19
|
rowsSql: string;
|
|
19
20
|
sourceTimesSql: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shift-measure-sql.d.ts","sourceRoot":"","sources":["../../src/utils/shift-measure-sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"shift-measure-sql.d.ts","sourceRoot":"","sources":["../../src/utils/shift-measure-sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAK9D,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM;;;;;EAoBnI;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GAAG,MAAM,CAGpG;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAOtJ;AAED,+FAA+F;AAC/F,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,MAAM,CAMnJ;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,sBAAsB,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAuBjM"}
|
|
@@ -1,27 +1,25 @@
|
|
|
1
|
-
import { GRAIN_FUNCTIONS } from '../constants.js';
|
|
2
|
-
import { addTimeSql, subtractTimeSql } from './time-arithmetic-sql.js';
|
|
3
1
|
import { calendarBucketGuardSql } from './time-axis-calendar-guard.js';
|
|
4
2
|
import { calendarShiftAtFineGrain } from './shift-measure-grains.js';
|
|
5
3
|
import { shiftWallTimeGuardSql } from './shift-wall-time-sql.js';
|
|
6
4
|
import { anchoredCalendarShiftSql } from './calendar-shift-sql.js';
|
|
7
5
|
/** Preserve the selected portion of a bucket and both authored endpoint operators. */
|
|
8
|
-
export function shiftRangeSql(shift, axis, period) {
|
|
6
|
+
export function shiftRangeSql(dialect, shift, axis, period) {
|
|
9
7
|
const first = period ?? '_hq_first';
|
|
10
8
|
const last = period ?? '_hq_last';
|
|
11
|
-
const end =
|
|
9
|
+
const end = dialect.addTime(last, 1, axis.grain);
|
|
12
10
|
const calendar = calendarShiftAtFineGrain(shift.interval, axis.grain);
|
|
13
11
|
// Clamp the bucket anchor, then retain its width. Independently clamping both
|
|
14
12
|
// dates would turn March 30–31 into February 28–28, dropping an entire day.
|
|
15
13
|
// A partial bucket keeps the matching slice of that shifted range, so both
|
|
16
14
|
// bounds are placed relative to the anchor rather than shifted on their own.
|
|
17
15
|
const shiftBound = (point, anchor) => calendar
|
|
18
|
-
? anchoredCalendarShiftSql(point, anchor, shift.interval)
|
|
19
|
-
:
|
|
20
|
-
const upper = shiftBound(
|
|
21
|
-
const shiftedEnd =
|
|
16
|
+
? anchoredCalendarShiftSql(dialect, point, anchor, shift.interval)
|
|
17
|
+
: dialect.subtractTime(point, shift.interval.amount, shift.interval.unit);
|
|
18
|
+
const upper = shiftBound(dialect.least(end, '_hq_upper'), last);
|
|
19
|
+
const shiftedEnd = dialect.addTime(dialect.subtractTime(last, shift.interval.amount, shift.interval.unit), 1, axis.grain);
|
|
22
20
|
return {
|
|
23
|
-
lower: shiftBound(
|
|
24
|
-
upper: calendar ? `
|
|
21
|
+
lower: shiftBound(dialect.greatest(first, '_hq_lower'), first),
|
|
22
|
+
upper: calendar ? dialect.ifElse(`_hq_upper >= ${end}`, shiftedEnd, upper) : upper,
|
|
25
23
|
lowerInclusive: period ? `(${period} > _hq_lower OR ${Number(axis.lowerInclusive)})` : String(Number(axis.lowerInclusive)),
|
|
26
24
|
upperInclusive: `(_hq_upper < ${end} AND ${Number(axis.upperInclusive)})`,
|
|
27
25
|
};
|
|
@@ -31,29 +29,30 @@ export function shiftRangePredicateSql(time, range) {
|
|
|
31
29
|
+ ` AND (${time} < ${range.upper} OR (${range.upperInclusive} AND ${time} = ${range.upper}))`;
|
|
32
30
|
}
|
|
33
31
|
/** Check the shifted scan independently of whether it contains source rows. */
|
|
34
|
-
export function shiftCalendarGuardSql(shift, axis, axisGuard) {
|
|
32
|
+
export function shiftCalendarGuardSql(dialect, shift, axis, axisGuard) {
|
|
35
33
|
const { grain } = axis;
|
|
36
|
-
const { lower, upper } = shiftRangeSql(shift, axis);
|
|
37
|
-
const first =
|
|
38
|
-
const last =
|
|
39
|
-
const count =
|
|
40
|
-
return calendarBucketGuardSql(first, count, grain);
|
|
34
|
+
const { lower, upper } = shiftRangeSql(dialect, shift, axis);
|
|
35
|
+
const first = dialect.truncateTime(lower, grain);
|
|
36
|
+
const last = dialect.truncateTime(upper, grain);
|
|
37
|
+
const count = `${dialect.timeDiff(grain, first, last)} + ${axisGuard}`;
|
|
38
|
+
return calendarBucketGuardSql(dialect, first, count, grain);
|
|
41
39
|
}
|
|
42
40
|
/** Validate each output bucket after the series exists, including empty source populations. */
|
|
43
|
-
export function shiftWallTimeSeriesGuardSql(shift, grain) {
|
|
44
|
-
const end =
|
|
45
|
-
return shiftWallTimeGuardSql(shift.interval, grain, '_hq_series CROSS JOIN _hq_bounds', '_hq_period',
|
|
41
|
+
export function shiftWallTimeSeriesGuardSql(dialect, shift, grain) {
|
|
42
|
+
const end = dialect.addTime('_hq_period', 1, grain);
|
|
43
|
+
return shiftWallTimeGuardSql(dialect, shift.interval, grain, '_hq_series CROSS JOIN _hq_bounds', '_hq_period', dialect.greatest('_hq_period', '_hq_lower'), dialect.least(end, '_hq_upper'), end);
|
|
46
44
|
}
|
|
47
45
|
/** Map output buckets to their earlier half-open ranges, retaining calendar arithmetic. */
|
|
48
|
-
export function shiftBucketCtes(shift, axis, index) {
|
|
46
|
+
export function shiftBucketCtes(dialect, shift, axis, index) {
|
|
49
47
|
const { grain } = axis;
|
|
50
48
|
const ranges = `_hq_shift_ranges${index}`;
|
|
51
49
|
const keys = `_hq_shift_keys${index}`;
|
|
52
|
-
const range = shiftRangeSql(shift, axis, '_hq_period');
|
|
53
|
-
const bucket =
|
|
54
|
-
const upperBucket =
|
|
55
|
-
const
|
|
56
|
-
const
|
|
50
|
+
const range = shiftRangeSql(dialect, shift, axis, '_hq_period');
|
|
51
|
+
const bucket = dialect.truncateTime('_hq_shift_lower', grain);
|
|
52
|
+
const upperBucket = dialect.truncateTime('_hq_shift_upper', grain);
|
|
53
|
+
const partialUpper = dialect.ifElse(`_hq_shift_upper > ${upperBucket} OR _hq_shift_upper_inclusive`, '1', '0');
|
|
54
|
+
const count = dialect.greatest('0', `${dialect.timeDiff(grain, bucket, upperBucket)} + ${partialUpper}`);
|
|
55
|
+
const join = ` AS r INNER JOIN ${keys} AS b ON ${dialect.truncateTime('r._hq_time', grain)} = b._hq_source_period WHERE ${shiftRangePredicateSql('r._hq_time', { lower: 'b._hq_shift_lower', upper: 'b._hq_shift_upper', lowerInclusive: 'b._hq_shift_lower_inclusive', upperInclusive: 'b._hq_shift_upper_inclusive' })}`;
|
|
57
56
|
return {
|
|
58
57
|
// Membership preserves duplicate source rows while excluding dates and
|
|
59
58
|
// partial ranges that no output bucket maps to, including clamped overlaps.
|
|
@@ -63,7 +62,7 @@ export function shiftBucketCtes(shift, axis, index) {
|
|
|
63
62
|
// A DST transition can map a one-hour output bucket to zero or two
|
|
64
63
|
// source hours. Enumerate source bucket keys and keep exact endpoints.
|
|
65
64
|
// The equality join avoids a source-rows × output-series Cartesian product.
|
|
66
|
-
`${keys} AS (SELECT *, ${
|
|
65
|
+
`${keys} AS (SELECT *, ${dialect.addTime(bucket, dialect.seriesIndex(count), grain)} AS _hq_source_period FROM ${ranges})`,
|
|
67
66
|
],
|
|
68
67
|
rowsSql: `SELECT r.*, b._hq_period FROM _hq_scanned${join}`,
|
|
69
68
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import type { DatasetSqlDialectRules } from '../dataset-sql-dialect.js';
|
|
1
2
|
import type { MeasureTimeInterval, TimeGrain } from '../types.js';
|
|
2
3
|
/** Reject DST normalization that moves a shifted sub-day bucket to another local time. */
|
|
3
|
-
export declare function shiftWallTimeGuardSql(interval: MeasureTimeInterval, grain: TimeGrain, source: string, period: string, lower: string, upper: string, end: string): string;
|
|
4
|
+
export declare function shiftWallTimeGuardSql(dialect: DatasetSqlDialectRules, interval: MeasureTimeInterval, grain: TimeGrain, source: string, period: string, lower: string, upper: string, end: string): string;
|
|
4
5
|
//# sourceMappingURL=shift-wall-time-sql.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shift-wall-time-sql.d.ts","sourceRoot":"","sources":["../../src/utils/shift-wall-time-sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"shift-wall-time-sql.d.ts","sourceRoot":"","sources":["../../src/utils/shift-wall-time-sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKlE,0FAA0F;AAC1F,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACV,MAAM,CAaR"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { subtractTimeSql } from './time-arithmetic-sql.js';
|
|
2
1
|
import { calendarShiftAtFineGrain } from './shift-measure-grains.js';
|
|
2
|
+
const CLOCK_PARTS = ['Hour', 'Minute', 'Second'];
|
|
3
3
|
/** Reject DST normalization that moves a shifted sub-day bucket to another local time. */
|
|
4
|
-
export function shiftWallTimeGuardSql(interval, grain, source, period, lower, upper, end) {
|
|
4
|
+
export function shiftWallTimeGuardSql(dialect, interval, grain, source, period, lower, upper, end) {
|
|
5
5
|
if (!calendarShiftAtFineGrain(interval, grain) || (grain !== 'minute' && grain !== 'hour'))
|
|
6
6
|
return '0';
|
|
7
7
|
const changesWallTime = (value) => {
|
|
8
|
-
const shifted =
|
|
9
|
-
return
|
|
10
|
-
.map(part =>
|
|
8
|
+
const shifted = dialect.subtractTime(value, interval.amount, interval.unit);
|
|
9
|
+
return CLOCK_PARTS
|
|
10
|
+
.map(part => `${dialect.clockPart(part, value)} != ${dialect.clockPart(part, shifted)}`)
|
|
11
11
|
.join(' OR ');
|
|
12
12
|
};
|
|
13
13
|
const changed = `(${changesWallTime(period)}) OR (${changesWallTime(lower)})`
|
|
14
14
|
+ ` OR (${upper} != ${end} AND (${changesWallTime(upper)}))`;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const guard = dialect.guard(`${dialect.countIf(changed)} > 0`, 'Calendar shift lands on a nonexistent local time; use a UTC query timezone.');
|
|
16
|
+
return `(SELECT ${guard} FROM ${source})`;
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-execution-context.d.ts","sourceRoot":"","sources":["../../src/utils/snapshot-execution-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"snapshot-execution-context.d.ts","sourceRoot":"","sources":["../../src/utils/snapshot-execution-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,CAgBjG"}
|
|
@@ -9,6 +9,9 @@ export function snapshotExecutionContext(context) {
|
|
|
9
9
|
...context.runtime,
|
|
10
10
|
// Copy tenant objects and ID lists; retain adapter and AbortSignal identity.
|
|
11
11
|
tenant: structuredClone(context.runtime.tenant),
|
|
12
|
+
...(context.runtime.constraints === undefined
|
|
13
|
+
? {}
|
|
14
|
+
: { constraints: structuredClone(context.runtime.constraints) }),
|
|
12
15
|
},
|
|
13
16
|
}),
|
|
14
17
|
...(context.cache && { cache: { ...context.cache } }),
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { DatasetSqlDialectRules, DatasetSqlParameterType } from '../dataset-sql-dialect.js';
|
|
2
|
+
/** A compiled builder statement: SQL with positional `?` markers and their values. */
|
|
3
|
+
export interface BuilderStatement {
|
|
4
|
+
readonly sql: string;
|
|
5
|
+
readonly parameters: readonly unknown[];
|
|
6
|
+
}
|
|
7
|
+
/** A query builder, as far as embedding its compiled statement is concerned. */
|
|
8
|
+
export interface EmbeddableBuilder {
|
|
9
|
+
toSQLWithParams(): BuilderStatement;
|
|
10
|
+
toSQLWithPlaceholders?(placeholder: (value: unknown) => string): string;
|
|
11
|
+
}
|
|
12
|
+
/** An executable statement, rendered for its dialect. */
|
|
13
|
+
export interface RenderedStatement {
|
|
14
|
+
sql: string;
|
|
15
|
+
parameters: unknown[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Planner output that still carries markers. Not executable: only
|
|
19
|
+
* {@link renderStatement} turns it into SQL, so markers cannot reach callers.
|
|
20
|
+
*/
|
|
21
|
+
export interface PlannedStatement {
|
|
22
|
+
readonly text: string;
|
|
23
|
+
readonly parameters: StatementParameters;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Owns every value bound into one statement family (a statement and its
|
|
27
|
+
* preflight statements). Values are bound behind opaque markers; the dialect
|
|
28
|
+
* spells placeholders once, at render time, in the order the markers appear
|
|
29
|
+
* in the final text. See specs/datasets/0001-statement-parameters.md.
|
|
30
|
+
*/
|
|
31
|
+
export declare class StatementParameters {
|
|
32
|
+
readonly dialect: DatasetSqlDialectRules;
|
|
33
|
+
private readonly nonce;
|
|
34
|
+
private readonly values;
|
|
35
|
+
private readonly pieces;
|
|
36
|
+
constructor(dialect: DatasetSqlDialectRules);
|
|
37
|
+
/** Bind one value; place the returned marker where the value belongs. */
|
|
38
|
+
bind(value: unknown, type?: DatasetSqlParameterType): string;
|
|
39
|
+
/** Embed a builder statement whose SQL carries its own positional `?` markers. */
|
|
40
|
+
embed(piece: BuilderStatement): string;
|
|
41
|
+
/**
|
|
42
|
+
* Embed a query builder's statement.
|
|
43
|
+
*
|
|
44
|
+
* On positional `?` dialects the builder's own statement is embedded as one
|
|
45
|
+
* block, exactly as before: `toSQLWithPlaceholders` is not called, so a
|
|
46
|
+
* duck-typed builder that answers any method name keeps working. Dialects
|
|
47
|
+
* that number placeholders need each value bound here, so they require the
|
|
48
|
+
* builder to render through `toSQLWithPlaceholders`. A caller that already
|
|
49
|
+
* compiled the builder positionally can pass that statement to reuse it.
|
|
50
|
+
*/
|
|
51
|
+
embedBuilder(builder: EmbeddableBuilder, compiled?: BuilderStatement): string;
|
|
52
|
+
/** Replace every marker in text order. Fails closed on foreign or malformed markers. */
|
|
53
|
+
render(text: string): RenderedStatement;
|
|
54
|
+
private marker;
|
|
55
|
+
}
|
|
56
|
+
/** Render planner output for execution. The only exit from a {@link PlannedStatement}. */
|
|
57
|
+
export declare function renderStatement(statement: PlannedStatement): RenderedStatement;
|
|
58
|
+
//# sourceMappingURL=statement-parameters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statement-parameters.d.ts","sourceRoot":"","sources":["../../src/utils/statement-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAE3H,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;CACzC;AAED,gFAAgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,eAAe,IAAI,gBAAgB,CAAC;IACpC,qBAAqB,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,MAAM,CAAC;CACzE;AAED,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,EAAE,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;CAC1C;AAaD;;;;;GAKG;AACH,qBAAa,mBAAmB;IAKlB,QAAQ,CAAC,OAAO,EAAE,sBAAsB;IAJpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAE5B,OAAO,EAAE,sBAAsB;IAEpD,yEAAyE;IACzE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,uBAAuB,GAAG,MAAM;IAK5D,kFAAkF;IAClF,KAAK,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM;IActC;;;;;;;;;OASG;IACH,YAAY,CAAC,OAAO,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,MAAM;IAa7E,wFAAwF;IACxF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB;IA2BvC,OAAO,CAAC,MAAM;CAGf;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,SAAS,EAAE,gBAAgB,GAAG,iBAAiB,CAE9E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Private-use code points never appear in generated SQL, and the nonce makes
|
|
2
|
+
// a marker unforgeable by any text that reaches a statement.
|
|
3
|
+
const OPEN = '\uE000';
|
|
4
|
+
const CLOSE = '\uE001';
|
|
5
|
+
const MARKER = /\uE000([0-9a-f]+):([vb]):(\d+)\uE001/g;
|
|
6
|
+
function createNonce() {
|
|
7
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(8));
|
|
8
|
+
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Owns every value bound into one statement family (a statement and its
|
|
12
|
+
* preflight statements). Values are bound behind opaque markers; the dialect
|
|
13
|
+
* spells placeholders once, at render time, in the order the markers appear
|
|
14
|
+
* in the final text. See specs/datasets/0001-statement-parameters.md.
|
|
15
|
+
*/
|
|
16
|
+
export class StatementParameters {
|
|
17
|
+
dialect;
|
|
18
|
+
nonce = createNonce();
|
|
19
|
+
values = [];
|
|
20
|
+
pieces = [];
|
|
21
|
+
constructor(dialect) {
|
|
22
|
+
this.dialect = dialect;
|
|
23
|
+
}
|
|
24
|
+
/** Bind one value; place the returned marker where the value belongs. */
|
|
25
|
+
bind(value, type) {
|
|
26
|
+
this.values.push(type === undefined ? { value } : { value, type });
|
|
27
|
+
return this.marker('v', this.values.length - 1);
|
|
28
|
+
}
|
|
29
|
+
/** Embed a builder statement whose SQL carries its own positional `?` markers. */
|
|
30
|
+
embed(piece) {
|
|
31
|
+
if (!this.dialect.embedsPositionalPieces) {
|
|
32
|
+
throw new Error(`The "${this.dialect.name}" datasets dialect cannot embed positional query builder SQL; `
|
|
33
|
+
+ 'the query builder must render placeholders for the datasets planner.');
|
|
34
|
+
}
|
|
35
|
+
if (piece.sql.includes(OPEN) || piece.sql.includes(CLOSE)) {
|
|
36
|
+
throw new Error('Query builder SQL cannot contain datasets statement markers.');
|
|
37
|
+
}
|
|
38
|
+
this.pieces.push({ sql: piece.sql, parameters: [...piece.parameters] });
|
|
39
|
+
return this.marker('b', this.pieces.length - 1);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Embed a query builder's statement.
|
|
43
|
+
*
|
|
44
|
+
* On positional `?` dialects the builder's own statement is embedded as one
|
|
45
|
+
* block, exactly as before: `toSQLWithPlaceholders` is not called, so a
|
|
46
|
+
* duck-typed builder that answers any method name keeps working. Dialects
|
|
47
|
+
* that number placeholders need each value bound here, so they require the
|
|
48
|
+
* builder to render through `toSQLWithPlaceholders`. A caller that already
|
|
49
|
+
* compiled the builder positionally can pass that statement to reuse it.
|
|
50
|
+
*/
|
|
51
|
+
embedBuilder(builder, compiled) {
|
|
52
|
+
if (this.dialect.embedsPositionalPieces)
|
|
53
|
+
return this.embed(compiled ?? builder.toSQLWithParams());
|
|
54
|
+
if (typeof builder.toSQLWithPlaceholders !== 'function') {
|
|
55
|
+
throw new Error(`The "${this.dialect.name}" datasets dialect numbers placeholders; `
|
|
56
|
+
+ 'the query builder must implement toSQLWithPlaceholders.');
|
|
57
|
+
}
|
|
58
|
+
const sql = builder.toSQLWithPlaceholders(value => this.bind(value));
|
|
59
|
+
if (typeof sql !== 'string')
|
|
60
|
+
throw new Error('Query builder toSQLWithPlaceholders must return SQL text.');
|
|
61
|
+
return sql;
|
|
62
|
+
}
|
|
63
|
+
/** Replace every marker in text order. Fails closed on foreign or malformed markers. */
|
|
64
|
+
render(text) {
|
|
65
|
+
const parameters = [];
|
|
66
|
+
const reused = new Map();
|
|
67
|
+
const sql = text.replace(MARKER, (_match, nonce, kind, position) => {
|
|
68
|
+
if (nonce !== this.nonce)
|
|
69
|
+
throw new Error('Statement contains a marker from another compilation.');
|
|
70
|
+
const index = Number(position);
|
|
71
|
+
if (kind === 'b') {
|
|
72
|
+
const piece = this.pieces[index];
|
|
73
|
+
if (!piece)
|
|
74
|
+
throw new Error('Statement contains an unknown builder marker.');
|
|
75
|
+
parameters.push(...piece.parameters);
|
|
76
|
+
return piece.sql;
|
|
77
|
+
}
|
|
78
|
+
const bound = this.values[index];
|
|
79
|
+
if (!bound)
|
|
80
|
+
throw new Error('Statement contains an unknown parameter marker.');
|
|
81
|
+
const existing = this.dialect.reusesPlaceholders ? reused.get(index) : undefined;
|
|
82
|
+
if (existing !== undefined)
|
|
83
|
+
return existing;
|
|
84
|
+
const placeholder = this.dialect.placeholder(parameters.length, bound);
|
|
85
|
+
parameters.push(bound.value);
|
|
86
|
+
reused.set(index, placeholder);
|
|
87
|
+
return placeholder;
|
|
88
|
+
});
|
|
89
|
+
if (sql.includes(OPEN) || sql.includes(CLOSE)) {
|
|
90
|
+
throw new Error('Statement contains a malformed parameter marker.');
|
|
91
|
+
}
|
|
92
|
+
return { sql, parameters };
|
|
93
|
+
}
|
|
94
|
+
marker(kind, index) {
|
|
95
|
+
return `${OPEN}${this.nonce}:${kind}:${index}${CLOSE}`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Render planner output for execution. The only exit from a {@link PlannedStatement}. */
|
|
99
|
+
export function renderStatement(statement) {
|
|
100
|
+
return statement.parameters.render(statement.text);
|
|
101
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DatasetSqlDialectRules } from '../dataset-sql-dialect.js';
|
|
1
2
|
import type { TimeGrain } from '../types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Calendar arithmetic can clamp a nonexistent date onto the previous bucket
|
|
@@ -5,5 +6,5 @@ import type { TimeGrain } from '../types.js';
|
|
|
5
6
|
* repeating them would duplicate aggregates and cumulative contributions.
|
|
6
7
|
* `count` must already include the series/fanout guards, bounding enumeration.
|
|
7
8
|
*/
|
|
8
|
-
export declare function calendarBucketGuardSql(start: string, count: string, grain: TimeGrain): string;
|
|
9
|
+
export declare function calendarBucketGuardSql(dialect: DatasetSqlDialectRules, start: string, count: string, grain: TimeGrain): string;
|
|
9
10
|
//# sourceMappingURL=time-axis-calendar-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-axis-calendar-guard.d.ts","sourceRoot":"","sources":["../../src/utils/time-axis-calendar-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"time-axis-calendar-guard.d.ts","sourceRoot":"","sources":["../../src/utils/time-axis-calendar-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAU9H"}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import { addTimeSql } from './time-arithmetic-sql.js';
|
|
2
1
|
/**
|
|
3
2
|
* Calendar arithmetic can clamp a nonexistent date onto the previous bucket
|
|
4
3
|
* (for example Pacific/Apia, 2011-12-30). Reject non-increasing bucket starts:
|
|
5
4
|
* repeating them would duplicate aggregates and cumulative contributions.
|
|
6
5
|
* `count` must already include the series/fanout guards, bounding enumeration.
|
|
7
6
|
*/
|
|
8
|
-
export function calendarBucketGuardSql(start, count, grain) {
|
|
7
|
+
export function calendarBucketGuardSql(dialect, start, count, grain) {
|
|
9
8
|
if (grain === 'minute' || grain === 'hour')
|
|
10
9
|
return '0';
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
const index = '_hq_calendar_index';
|
|
11
|
+
const current = dialect.addTime(start, index, grain);
|
|
12
|
+
const next = dialect.addTime(start, `${index} + 1`, grain);
|
|
13
13
|
// Include the end boundary, which also bounds the source-row scan.
|
|
14
|
-
|
|
15
|
-
return `throwIf(arrayExists(_hq_calendar_index -> ${next} <= ${current}, ${indices}), `
|
|
16
|
-
+ "'Time range crosses a skipped local calendar bucket; use a UTC time key for this range.')";
|
|
14
|
+
return dialect.guard(dialect.anyIndex(index, dialect.greatest('1', count), `${next} <= ${current}`), 'Time range crosses a skipped local calendar bucket; use a UTC time key for this range.');
|
|
17
15
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { StatementParameters } from './statement-parameters.js';
|
|
1
2
|
import type { TimeMeasureAxis } from './time-measure-axis.js';
|
|
2
|
-
import type
|
|
3
|
+
import { type TimeMeasureSqlSource } from './time-measure-source-sql.js';
|
|
3
4
|
import type { ShiftMeasureDefinition } from '../types.js';
|
|
4
5
|
export interface TimeMeasureSqlAxis {
|
|
5
6
|
ctes: string[];
|
|
@@ -9,5 +10,5 @@ export interface TimeMeasureSqlAxis {
|
|
|
9
10
|
postSeriesGuard: string;
|
|
10
11
|
}
|
|
11
12
|
/** Build bounded output buckets using the query timezone. */
|
|
12
|
-
export declare function buildTimeMeasureAxisSql(source: TimeMeasureSqlSource, axis: TimeMeasureAxis, shifts?: readonly ShiftMeasureDefinition[]): TimeMeasureSqlAxis;
|
|
13
|
+
export declare function buildTimeMeasureAxisSql(statement: StatementParameters, source: TimeMeasureSqlSource, axis: TimeMeasureAxis, shifts?: readonly ShiftMeasureDefinition[]): TimeMeasureSqlAxis;
|
|
13
14
|
//# sourceMappingURL=time-measure-axis-sql.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time-measure-axis-sql.d.ts","sourceRoot":"","sources":["../../src/utils/time-measure-axis-sql.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"time-measure-axis-sql.d.ts","sourceRoot":"","sources":["../../src/utils/time-measure-axis-sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAqB,KAAK,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAE5F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,6DAA6D;AAC7D,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,eAAe,EACrB,MAAM,GAAE,SAAS,sBAAsB,EAAO,GAC7C,kBAAkB,CA2CpB"}
|