@hypequery/datasets 0.26.0 → 0.28.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 (78) hide show
  1. package/dist/cache/protocol-cache-keys.d.ts.map +1 -1
  2. package/dist/cache/protocol-cache-keys.js +6 -1
  3. package/dist/client-contract/build-from-deployment.d.ts +26 -0
  4. package/dist/client-contract/build-from-deployment.d.ts.map +1 -0
  5. package/dist/client-contract/build-from-deployment.js +76 -0
  6. package/dist/client-contract/deployment-annotations.d.ts +6 -0
  7. package/dist/client-contract/deployment-annotations.d.ts.map +1 -0
  8. package/dist/client-contract/deployment-annotations.js +32 -0
  9. package/dist/client-contract/deployment-fields.d.ts +19 -0
  10. package/dist/client-contract/deployment-fields.d.ts.map +1 -0
  11. package/dist/client-contract/deployment-fields.js +103 -0
  12. package/dist/client-contract/deployment-profile.d.ts +22 -0
  13. package/dist/client-contract/deployment-profile.d.ts.map +1 -0
  14. package/dist/client-contract/deployment-profile.js +29 -0
  15. package/dist/client-contract/query-schema.d.ts.map +1 -1
  16. package/dist/client-contract/query-schema.js +9 -3
  17. package/dist/constants.d.ts +13 -2
  18. package/dist/constants.d.ts.map +1 -1
  19. package/dist/constants.js +18 -2
  20. package/dist/in-memory-backend.d.ts.map +1 -1
  21. package/dist/in-memory-backend.js +4 -0
  22. package/dist/index.d.ts +6 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -2
  25. package/dist/query-helpers.d.ts +6 -0
  26. package/dist/query-helpers.d.ts.map +1 -1
  27. package/dist/query-helpers.js +10 -0
  28. package/dist/query-planner.js +1 -1
  29. package/dist/relationship-check.d.ts.map +1 -1
  30. package/dist/relationship-check.js +11 -6
  31. package/dist/semantic-query-schema.d.ts.map +1 -1
  32. package/dist/semantic-query-schema.js +17 -8
  33. package/dist/sql-portability.d.ts.map +1 -1
  34. package/dist/sql-portability.js +3 -1
  35. package/dist/types.d.ts +19 -5
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/utils/clickhouse-dataset-sql-dialect.d.ts.map +1 -1
  38. package/dist/utils/clickhouse-dataset-sql-dialect.js +5 -0
  39. package/dist/utils/dataset-definition-validation.js +2 -2
  40. package/dist/utils/dataset-filter-types.d.ts +7 -3
  41. package/dist/utils/dataset-filter-types.d.ts.map +1 -1
  42. package/dist/utils/dataset-query-validation.d.ts.map +1 -1
  43. package/dist/utils/dataset-query-validation.js +4 -2
  44. package/dist/utils/enforced-constraints.d.ts.map +1 -1
  45. package/dist/utils/enforced-constraints.js +2 -1
  46. package/dist/utils/filter-definition.d.ts +2 -2
  47. package/dist/utils/filter-definition.d.ts.map +1 -1
  48. package/dist/utils/filter-operator-policy.d.ts +11 -0
  49. package/dist/utils/filter-operator-policy.d.ts.map +1 -0
  50. package/dist/utils/filter-operator-policy.js +13 -0
  51. package/dist/utils/filtered-aggregation-sql.d.ts.map +1 -1
  52. package/dist/utils/filtered-aggregation-sql.js +4 -0
  53. package/dist/utils/json-pointer-segments.d.ts +7 -0
  54. package/dist/utils/json-pointer-segments.d.ts.map +1 -0
  55. package/dist/utils/json-pointer-segments.js +9 -0
  56. package/dist/utils/metric-query-validation.d.ts.map +1 -1
  57. package/dist/utils/metric-query-validation.js +4 -2
  58. package/dist/utils/protocol-metric-expressions.d.ts.map +1 -1
  59. package/dist/utils/protocol-metric-expressions.js +4 -0
  60. package/dist/utils/protocol-rehydrate-filters.d.ts +1 -1
  61. package/dist/utils/protocol-rehydrate-filters.d.ts.map +1 -1
  62. package/dist/utils/protocol-rehydrate-filters.js +7 -1
  63. package/dist/utils/query-timezone.d.ts.map +1 -1
  64. package/dist/utils/query-timezone.js +3 -1
  65. package/dist/utils/relationship-builder-plan.d.ts +7 -2
  66. package/dist/utils/relationship-builder-plan.d.ts.map +1 -1
  67. package/dist/utils/relationship-builder-plan.js +14 -4
  68. package/dist/utils/relationship-validation.d.ts.map +1 -1
  69. package/dist/utils/relationship-validation.js +2 -1
  70. package/dist/utils/scoped-dataset-source.js +1 -1
  71. package/dist/utils/segments.d.ts.map +1 -1
  72. package/dist/utils/segments.js +6 -4
  73. package/dist/utils/tenant-runtime.d.ts +7 -0
  74. package/dist/utils/tenant-runtime.d.ts.map +1 -1
  75. package/dist/utils/tenant-runtime.js +16 -0
  76. package/dist/validation.d.ts.map +1 -1
  77. package/dist/validation.js +9 -0
  78. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"protocol-cache-keys.d.ts","sourceRoot":"","sources":["../../src/cache/protocol-cache-keys.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAMrB,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAInD,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAChC,WAAW,EAAE,OAAO,GACnB,wBAAwB,CAqC1B;AAwID;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,wBAAwB,EAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAkBpB;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAgBpB"}
1
+ {"version":3,"file":"protocol-cache-keys.d.ts","sourceRoot":"","sources":["../../src/cache/protocol-cache-keys.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,aAAa,CAAC;AAMrB,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AACjD,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAInD,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAChC,WAAW,EAAE,OAAO,GACnB,wBAAwB,CAqC1B;AA6ID;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,wBAAwB,EAClC,EAAE,EAAE,kBAAkB,EACtB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAkBpB;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,SAAS,GAAG,gBAAgB,EACpC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAgBpB"}
@@ -76,6 +76,11 @@ function canonicalLiteral(value) {
76
76
  return validateCanonicalValue(value);
77
77
  }
78
78
  function filterNode(filter) {
79
+ const left = { kind: 'reference', name: filter.field };
80
+ // A null check has no value, so its node has no right operand (RFC 0023).
81
+ if (filter.operator === 'isNull' || filter.operator === 'isNotNull') {
82
+ return { kind: 'comparison', operator: filter.operator, left };
83
+ }
79
84
  let literal;
80
85
  if (filter.operator === 'between' && Array.isArray(filter.value)) {
81
86
  // RFC 0003 bounds are a two-item tuple; in/notIn take an array.
@@ -89,7 +94,7 @@ function filterNode(filter) {
89
94
  return {
90
95
  kind: 'comparison',
91
96
  operator: filter.operator,
92
- left: { kind: 'reference', name: filter.field },
97
+ left,
93
98
  right: { kind: 'literal', value: literal },
94
99
  };
95
100
  }
@@ -0,0 +1,26 @@
1
+ import { type PreparedProtocolClientContract, type ProtocolDeploymentContract, type ProtocolDeploymentDataset } from '@hypequery/protocol';
2
+ import { type ClientContractProfile } from './deployment-profile.js';
3
+ export interface BuildClientContractOptions {
4
+ /** Ceilings the host enforces; defaults mirror Python's ClientQueryProfile. */
5
+ readonly profile?: ClientContractProfile;
6
+ /**
7
+ * Trusted mount prefix, such as `/v1`: absolute, no trailing slash. Never a
8
+ * proxy or request header; the host knows how it is mounted.
9
+ */
10
+ readonly mountPath?: string;
11
+ /** Final route per published dataset, when the host serves it somewhere other than `endpoint.path`. */
12
+ readonly paths?: Readonly<Record<string, string>>;
13
+ /** `authorized` is a caller's view, narrowed by `include`. */
14
+ readonly view?: 'build' | 'authorized';
15
+ /** Which published datasets to advertise; every one by default. */
16
+ readonly include?: (dataset: ProtocolDeploymentDataset) => boolean;
17
+ }
18
+ /**
19
+ * The client contract for a deployment's published datasets: typed fields,
20
+ * routes and schema hashes `hypequery generate:client` turns into React types
21
+ * and a route manifest. Pure: no network, no execution. Datasets without an
22
+ * endpoint policy (relationship targets) are not advertised, and neither are
23
+ * relationship fields yet.
24
+ */
25
+ export declare function buildClientContract(contract: ProtocolDeploymentContract, options?: BuildClientContractOptions): PreparedProtocolClientContract;
26
+ //# sourceMappingURL=build-from-deployment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-from-deployment.d.ts","sourceRoot":"","sources":["../../src/client-contract/build-from-deployment.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,8BAA8B,EACnC,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC/B,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAmD,KAAK,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEtH,MAAM,WAAW,0BAA0B;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,uGAAuG;IACvG,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IACvC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC;CACpE;AA2DD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,0BAA0B,EACpC,OAAO,GAAE,0BAA+B,GACvC,8BAA8B,CAchC"}
@@ -0,0 +1,76 @@
1
+ import { prepareProtocolClientContract, } from '@hypequery/protocol';
2
+ import { PORTABLE_TIME_GRAINS } from '../utils/portable-grains.js';
3
+ import { endpointAnnotations } from './deployment-annotations.js';
4
+ import { publicFields } from './deployment-fields.js';
5
+ import { clientQueryLimits, resolveClientContractProfile } from './deployment-profile.js';
6
+ function endpointPath(dataset, options) {
7
+ const path = options.paths?.[dataset.name] ?? dataset.endpoint?.path;
8
+ if (path === undefined || !path.startsWith('/')) {
9
+ throw new Error(`Client export: dataset "${dataset.name}" needs an absolute endpoint path.`);
10
+ }
11
+ return (options.mountPath ?? '') + path;
12
+ }
13
+ function endpointDescriptor(dataset, options, profile) {
14
+ const { dimensions, measures, filters } = publicFields(dataset);
15
+ // Rows carry the time bucket as `period`, so a field of that name would collide.
16
+ if (dataset.timeField !== undefined && (Object.hasOwn(dimensions, 'period') || Object.hasOwn(measures, 'period'))) {
17
+ throw new Error(`Client export: dataset "${dataset.name}" has a field named "period", which its time bucket uses. Rename it.`);
18
+ }
19
+ const limits = clientQueryLimits(dataset, profile);
20
+ // An endpoint's default selection is the base measures it can serve, capped
21
+ // at the dataset's own measure limit so a dataset with more base measures
22
+ // than it may select at once still exports. The selection is hashed, so a
23
+ // host budget never trims it: a budget-only change must not move the schema
24
+ // hash a generated client pins. A budget too small for it is refused.
25
+ const defaultMeasures = dataset.measures
26
+ .filter(measure => !('kind' in measure) && Object.hasOwn(measures, measure.name))
27
+ .map(measure => measure.name)
28
+ .slice(0, dataset.limits?.maxMeasures);
29
+ if (defaultMeasures.length > limits.maxMeasures) {
30
+ throw new Error(`Client export: dataset "${dataset.name}" selects ${defaultMeasures.length} measures by default, `
31
+ + `more than the host's measure budget of ${limits.maxMeasures}. Raise the budget, or set the dataset's limits.maxMeasures.`);
32
+ }
33
+ const annotations = endpointAnnotations(dataset, Object.keys(dimensions), Object.keys(measures));
34
+ return {
35
+ id: dataset.name,
36
+ kind: 'dataset',
37
+ dataset: dataset.name,
38
+ path: endpointPath(dataset, options),
39
+ dimensions,
40
+ measures,
41
+ filters,
42
+ metadata: true,
43
+ limits,
44
+ // Deployment contract 2 carries day-and-longer grains only.
45
+ time: dataset.timeField === undefined ? null : {
46
+ grains: [...PORTABLE_TIME_GRAINS],
47
+ defaultTimezone: profile.defaultTimezone,
48
+ timezone: true,
49
+ periodFormat: 'calendar-date-or-local-datetime-v1',
50
+ },
51
+ defaultMeasures,
52
+ ...(annotations ? { annotations } : {}),
53
+ };
54
+ }
55
+ /**
56
+ * The client contract for a deployment's published datasets: typed fields,
57
+ * routes and schema hashes `hypequery generate:client` turns into React types
58
+ * and a route manifest. Pure: no network, no execution. Datasets without an
59
+ * endpoint policy (relationship targets) are not advertised, and neither are
60
+ * relationship fields yet.
61
+ */
62
+ export function buildClientContract(contract, options = {}) {
63
+ const { mountPath } = options;
64
+ if (mountPath && (!mountPath.startsWith('/') || mountPath.endsWith('/'))) {
65
+ throw new Error('Client export: mountPath must be empty or an absolute path without a trailing slash.');
66
+ }
67
+ const profile = resolveClientContractProfile(options.profile);
68
+ const published = contract.datasets
69
+ .filter(dataset => dataset.endpoint !== undefined && (options.include?.(dataset) ?? true));
70
+ return prepareProtocolClientContract({
71
+ kind: 'hypequery-client-contract',
72
+ version: 1,
73
+ view: options.view ?? 'build',
74
+ endpoints: published.map(dataset => endpointDescriptor(dataset, options, profile)),
75
+ });
76
+ }
@@ -0,0 +1,6 @@
1
+ import type { ClientEndpointAnnotations, ProtocolDeploymentDataset } from '@hypequery/protocol';
2
+ /** Fold whitespace runs so multi-line definitions stay advertisable; omit blank text. */
3
+ export declare function annotationText(value: string | undefined): string | undefined;
4
+ /** Group text from the dataset; field text for each advertised dimension and measure. */
5
+ export declare function endpointAnnotations(dataset: ProtocolDeploymentDataset, dimensions: readonly string[], measures: readonly string[]): ClientEndpointAnnotations | undefined;
6
+ //# sourceMappingURL=deployment-annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-annotations.d.ts","sourceRoot":"","sources":["../../src/client-contract/deployment-annotations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EAEzB,yBAAyB,EAC1B,MAAM,qBAAqB,CAAC;AAE7B,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI5E;AASD,yFAAyF;AACzF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,yBAAyB,EAClC,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,yBAAyB,GAAG,SAAS,CAgBvC"}
@@ -0,0 +1,32 @@
1
+ /** Fold whitespace runs so multi-line definitions stay advertisable; omit blank text. */
2
+ export function annotationText(value) {
3
+ if (value === undefined)
4
+ return undefined;
5
+ const folded = value.split(/\s+/).filter(Boolean).join(' ');
6
+ return folded.trim() ? folded : undefined;
7
+ }
8
+ function fieldAnnotation(definition) {
9
+ const label = annotationText(definition.label);
10
+ const description = annotationText(definition.description);
11
+ if (label === undefined && description === undefined)
12
+ return undefined;
13
+ return { ...(label !== undefined ? { label } : {}), ...(description !== undefined ? { description } : {}) };
14
+ }
15
+ /** Group text from the dataset; field text for each advertised dimension and measure. */
16
+ export function endpointAnnotations(dataset, dimensions, measures) {
17
+ const advertised = [
18
+ ...dataset.dimensions.filter(item => dimensions.includes(item.name)),
19
+ ...dataset.measures.filter(item => measures.includes(item.name)),
20
+ ];
21
+ // Object.fromEntries defines each name as an own key, `__proto__` included.
22
+ const fields = Object.fromEntries(advertised.flatMap(definition => {
23
+ const node = fieldAnnotation(definition);
24
+ return node ? [[definition.name, node]] : [];
25
+ }));
26
+ const description = annotationText(dataset.description);
27
+ const result = {
28
+ ...(description !== undefined ? { description } : {}),
29
+ ...(Object.keys(fields).length ? { fields } : {}),
30
+ };
31
+ return Object.keys(result).length ? result : undefined;
32
+ }
@@ -0,0 +1,19 @@
1
+ import type { ClientDimension, ClientFilter, ClientMeasure, ProtocolDatasetDimension, ProtocolDatasetFilter, ProtocolDeploymentDataset, ProtocolDeploymentMeasure } from '@hypequery/protocol';
2
+ /** Local fields have unknown nullability; the client contract says so rather than guess. */
3
+ export declare function dimensionDescriptor(dimension: ProtocolDatasetDimension): ClientDimension;
4
+ /** `having` compares numbers, so ordered aggregations over non-numeric fields can't take it. */
5
+ export declare function measureDescriptor(dataset: ProtocolDeploymentDataset, measure: ProtocolDeploymentMeasure): ClientMeasure;
6
+ export declare function filterDescriptor(dimension: ProtocolDatasetDimension, filter: ProtocolDatasetFilter): ClientFilter | null;
7
+ /** Tenant identities come from the caller's credential, never from request predicates. */
8
+ export declare function requestFilter(dataset: ProtocolDeploymentDataset, dimension: ProtocolDatasetDimension): boolean;
9
+ /**
10
+ * The fields one dataset endpoint advertises. Relationship fields are not
11
+ * exported yet, matching Python's default (`related=()`), so a measure whose
12
+ * fixed filters cross a relationship is left out rather than advertised.
13
+ */
14
+ export declare function publicFields(dataset: ProtocolDeploymentDataset): {
15
+ dimensions: Record<string, ClientDimension>;
16
+ measures: Record<string, ClientMeasure>;
17
+ filters: Record<string, ClientFilter>;
18
+ };
19
+ //# sourceMappingURL=deployment-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-fields.d.ts","sourceRoot":"","sources":["../../src/client-contract/deployment-fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACb,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,yBAAyB,EAE1B,MAAM,qBAAqB,CAAC;AAQ7B,4FAA4F;AAC5F,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,wBAAwB,GAAG,eAAe,CAQxF;AAED,gGAAgG;AAChG,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,yBAAyB,GAAG,aAAa,CAUvH;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,wBAAwB,EAAE,MAAM,EAAE,qBAAqB,GAAG,YAAY,GAAG,IAAI,CAKxH;AAED,0FAA0F;AAC1F,wBAAgB,aAAa,CAAC,OAAO,EAAE,yBAAyB,EAAE,SAAS,EAAE,wBAAwB,GAAG,OAAO,CAI9G;AAmCD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,yBAAyB,GAAG;IAChE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACvC,CAkBA"}
@@ -0,0 +1,103 @@
1
+ // As Python's builder: booleans compare by equality and membership only.
2
+ const BOOLEAN_OPERATORS = new Set(['eq', 'neq', 'in', 'notIn']);
3
+ const ORDERED_AGGREGATIONS = new Set(['min', 'max', 'argMin', 'argMax']);
4
+ /** Stored states whose merged value is the stored value itself, which may not be a number. */
5
+ const ORDERED_STATES = new Set(['min', 'max', 'any', 'anyLast']);
6
+ /** Local fields have unknown nullability; the client contract says so rather than guess. */
7
+ export function dimensionDescriptor(dimension) {
8
+ return {
9
+ type: dimension.type,
10
+ wireType: dimension.type === 'number' ? 'number-or-string' : dimension.type === 'boolean' ? 'boolean' : 'string',
11
+ nullable: 'unknown',
12
+ groupable: dimension.groupable,
13
+ orderable: dimension.groupable,
14
+ };
15
+ }
16
+ /** `having` compares numbers, so ordered aggregations over non-numeric fields can't take it. */
17
+ export function measureDescriptor(dataset, measure) {
18
+ if ('kind' in measure)
19
+ return { wireType: 'string', nullable: true, having: true };
20
+ if (measure.aggregation === 'merge') {
21
+ return { wireType: 'string', nullable: true, having: !ORDERED_STATES.has(String(measure.stateFunction)) };
22
+ }
23
+ if (!ORDERED_AGGREGATIONS.has(measure.aggregation)) {
24
+ return { wireType: 'string', nullable: true, having: true };
25
+ }
26
+ const dimension = dataset.dimensions.find(item => item.name === measure.field);
27
+ return { wireType: 'string', nullable: true, having: dimension?.type === 'number' };
28
+ }
29
+ export function filterDescriptor(dimension, filter) {
30
+ const operators = [...new Set(filter.operators.filter(operator => dimension.type === 'boolean'
31
+ ? BOOLEAN_OPERATORS.has(operator)
32
+ : dimension.type !== 'number' || operator !== 'like'))].sort();
33
+ return operators.length ? { type: dimension.type, operators } : null;
34
+ }
35
+ /** Tenant identities come from the caller's credential, never from request predicates. */
36
+ export function requestFilter(dataset, dimension) {
37
+ if (dataset.tenant.kind !== 'required')
38
+ return true;
39
+ const column = dimension.source.kind === 'column' ? dimension.source.column : dimension.name;
40
+ return column !== dataset.tenant.field;
41
+ }
42
+ function expressionFields(expression) {
43
+ switch (expression.kind) {
44
+ case 'reference': return [expression.name];
45
+ case 'aggregate': return [expression.field];
46
+ case 'binary': return [...expressionFields(expression.left), ...expressionFields(expression.right)];
47
+ case 'call': return expression.args.flatMap(expressionFields);
48
+ case 'comparison': return 'right' in expression
49
+ ? [...expressionFields(expression.left), ...expressionFields(expression.right)]
50
+ : expressionFields(expression.left);
51
+ case 'logical': return 'operands' in expression ? expression.operands.flatMap(expressionFields) : expressionFields(expression.operand);
52
+ default: return [];
53
+ }
54
+ }
55
+ /** The fields a measure's fixed filters read, through any derived dependencies. */
56
+ function measureFilterFields(dataset, name) {
57
+ const filters = new Map(dataset.filters.map(filter => [filter.name, filter.field]));
58
+ const measures = new Map(dataset.measures.map(measure => [measure.name, measure]));
59
+ const pending = [name];
60
+ const seen = new Set();
61
+ const fields = [];
62
+ while (pending.length) {
63
+ const current = pending.pop();
64
+ if (seen.has(current))
65
+ continue;
66
+ seen.add(current);
67
+ const measure = measures.get(current);
68
+ if (measure === undefined)
69
+ continue;
70
+ if ('kind' in measure)
71
+ pending.push(...measure.uses.map(use => use.measure));
72
+ else
73
+ for (const field of measure.filters.flatMap(expressionFields))
74
+ fields.push(filters.get(field) ?? field);
75
+ }
76
+ return fields;
77
+ }
78
+ /**
79
+ * The fields one dataset endpoint advertises. Relationship fields are not
80
+ * exported yet, matching Python's default (`related=()`), so a measure whose
81
+ * fixed filters cross a relationship is left out rather than advertised.
82
+ */
83
+ export function publicFields(dataset) {
84
+ const dimensions = Object.fromEntries(dataset.dimensions.map(dimension => [dimension.name, dimensionDescriptor(dimension)]));
85
+ const measures = Object.fromEntries(dataset.measures
86
+ .filter(measure => measureFilterFields(dataset, measure.name).every(field => !field.includes('.')))
87
+ .map(measure => [measure.name, measureDescriptor(dataset, measure)]));
88
+ // Built with Object.fromEntries, as above: assigning a key such as
89
+ // `__proto__` would set the prototype instead of adding an entry.
90
+ const filters = Object.fromEntries(dataset.filters.flatMap((filter) => {
91
+ if (filter.field.includes('.'))
92
+ return [];
93
+ const dimension = dataset.dimensions.find(item => item.name === filter.field);
94
+ if (dimension === undefined) {
95
+ throw new Error(`Client export: filter "${dataset.name}.${filter.name}" references unknown dimension "${filter.field}".`);
96
+ }
97
+ if (!requestFilter(dataset, dimension))
98
+ return [];
99
+ const descriptor = filterDescriptor(dimension, filter);
100
+ return descriptor ? [[filter.name, descriptor]] : [];
101
+ }));
102
+ return { dimensions, measures, filters };
103
+ }
@@ -0,0 +1,22 @@
1
+ import type { ClientQueryLimits, ProtocolDeploymentDataset } from '@hypequery/protocol';
2
+ /**
3
+ * Trusted host ceilings for an exported client contract. The host must enforce
4
+ * at least these bounds; the export only ever narrows them by each dataset's
5
+ * own limits and endpoint `maxLimit`. Defaults mirror Python's ClientQueryProfile.
6
+ */
7
+ export interface ClientContractProfile {
8
+ readonly defaultLimit?: number;
9
+ readonly maxLimit?: number;
10
+ readonly maxOffset?: number;
11
+ readonly maxDimensions?: number;
12
+ readonly maxMeasures?: number;
13
+ readonly maxPredicates?: number;
14
+ readonly maxOrderBy?: number;
15
+ readonly maxFilterValues?: number;
16
+ /** IANA zone used when a request names none. */
17
+ readonly defaultTimezone?: string;
18
+ }
19
+ export declare function resolveClientContractProfile(profile?: ClientContractProfile): Required<ClientContractProfile>;
20
+ /** Intersect the profile with the dataset's own ceilings; never widen them. */
21
+ export declare function clientQueryLimits(dataset: ProtocolDeploymentDataset, profile: Required<ClientContractProfile>): ClientQueryLimits;
22
+ //# sourceMappingURL=deployment-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-profile.d.ts","sourceRoot":"","sources":["../../src/client-contract/deployment-profile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAExF;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAcD,wBAAgB,4BAA4B,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,CAAC,qBAAqB,CAAC,CAEjH;AAID,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,iBAAiB,CAYjI"}
@@ -0,0 +1,29 @@
1
+ const DEFAULT_PROFILE = {
2
+ defaultLimit: 1000,
3
+ maxLimit: 1000,
4
+ maxOffset: 1_000_000,
5
+ maxDimensions: 100,
6
+ maxMeasures: 100,
7
+ maxPredicates: 100,
8
+ maxOrderBy: 100,
9
+ maxFilterValues: 10_000,
10
+ defaultTimezone: 'UTC',
11
+ };
12
+ export function resolveClientContractProfile(profile = {}) {
13
+ return { ...DEFAULT_PROFILE, ...Object.fromEntries(Object.entries(profile).filter(([, value]) => value !== undefined)) };
14
+ }
15
+ const narrower = (ceiling, value) => value === undefined ? ceiling : Math.min(ceiling, value);
16
+ /** Intersect the profile with the dataset's own ceilings; never widen them. */
17
+ export function clientQueryLimits(dataset, profile) {
18
+ const maxLimit = narrower(narrower(profile.maxLimit, dataset.limits?.maxResultSize), dataset.endpoint?.maxLimit);
19
+ return {
20
+ defaultLimit: Math.min(profile.defaultLimit, maxLimit),
21
+ maxLimit,
22
+ maxOffset: profile.maxOffset,
23
+ maxDimensions: narrower(profile.maxDimensions, dataset.limits?.maxDimensions),
24
+ maxMeasures: narrower(profile.maxMeasures, dataset.limits?.maxMeasures),
25
+ maxPredicates: narrower(profile.maxPredicates, dataset.limits?.maxFilters),
26
+ maxOrderBy: profile.maxOrderBy,
27
+ maxFilterValues: profile.maxFilterValues,
28
+ };
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"query-schema.d.ts","sourceRoot":"","sources":["../../src/client-contract/query-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,sBAAsB,EACzD,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAwB,KAAK,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC;CACrC;AACD,MAAM,WAAW,0BAA2B,SAAQ,6BAA6B;IAC/E,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;CACpE;AA4DD;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAe1F"}
1
+ {"version":3,"file":"query-schema.d.ts","sourceRoot":"","sources":["../../src/client-contract/query-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,sBAAsB,EACzD,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAK,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AACzC,OAAO,EAAwB,KAAK,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC;CACrC;AACD,MAAM,WAAW,0BAA2B,SAAQ,6BAA6B;IAC/E,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;CACpE;AAiED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAe1F"}
@@ -1,6 +1,7 @@
1
- import { validateProtocolClientContract, validateProtocolClientQuery, } from '@hypequery/protocol';
1
+ import { ProtocolClientContractError, validateProtocolClientContract, validateProtocolClientQuery, } from '@hypequery/protocol';
2
2
  import { z } from 'zod';
3
3
  import { toSemanticJsonSchema } from '../semantic-query-schema.js';
4
+ import { pointerSegments } from '../utils/json-pointer-segments.js';
4
5
  function union(schemas) {
5
6
  return schemas.length === 0 ? z.never() : schemas.length === 1 ? schemas[0]
6
7
  : z.union(schemas);
@@ -15,6 +16,10 @@ function predicates(endpoint, having) {
15
16
  return union(definitions.flatMap(([key, field]) => field.operators.map(operator => {
16
17
  const scalar = field.type === 'number' ? z.number().finite()
17
18
  : field.type === 'boolean' ? z.boolean() : z.string();
19
+ // A null check names no value (RFC 0023).
20
+ if (operator === 'isNull' || operator === 'isNotNull') {
21
+ return z.object({ [having ? 'measure' : 'field']: z.literal(key), operator: z.literal(operator) }).strict();
22
+ }
18
23
  const value = operator === 'between' ? z.tuple([scalar, scalar])
19
24
  : operator === 'in' || operator === 'notIn' ? z.array(scalar).min(1).max(endpoint.limits.maxFilterValues)
20
25
  : scalar;
@@ -56,8 +61,9 @@ function endpointSchema(contract, endpoint, transport) {
56
61
  try {
57
62
  validateProtocolClientQuery(contract, endpoint.id, input, transport);
58
63
  }
59
- catch {
60
- context.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid client query.' });
64
+ catch (error) {
65
+ context.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid client query.',
66
+ path: error instanceof ProtocolClientContractError ? pointerSegments(error.path) : [] });
61
67
  return z.NEVER;
62
68
  }
63
69
  return input;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared constants for semantic layer implementation.
3
3
  */
4
- import type { MetricFilter, TimeGrain } from './types.js';
4
+ import type { MetricFilter, MetricNullCheckOperator, TimeGrain } from './types.js';
5
5
  /**
6
6
  * Maps time grain to ClickHouse date truncation functions.
7
7
  *
@@ -13,9 +13,20 @@ export declare const GRAIN_FUNCTIONS: Record<TimeGrain, string>;
13
13
  /** The set of time grains supported by the planner, finest first. */
14
14
  export declare const SUPPORTED_TIME_GRAINS: TimeGrain[];
15
15
  /**
16
- * The filter operators accepted by semantic dataset and metric inputs.
16
+ * The filter operators accepted by semantic dataset and metric inputs, and the
17
+ * operators a filter allows when its definition lists none. The null checks in
18
+ * {@link SEMANTIC_NULL_CHECK_OPERATORS} are accepted too, but a caller filter
19
+ * may use one only when its definition lists it (RFC 0023).
17
20
  */
18
21
  export declare const SEMANTIC_FILTER_OPERATORS: readonly ["eq", "neq", "gt", "gte", "lt", "lte", "in", "notIn", "between", "like"];
22
+ /**
23
+ * Operators that test a field for NULL and take no value (RFC 0023). Measure
24
+ * and segment filters may use them freely; a caller filter only when its
25
+ * definition's `operators` list names them.
26
+ */
27
+ export declare const SEMANTIC_NULL_CHECK_OPERATORS: readonly ["isNull", "isNotNull"];
28
+ /** True for `isNull` and `isNotNull`, the filter operators without a value. */
29
+ export declare function isNullCheckFilterOperator(operator: unknown): operator is MetricNullCheckOperator;
19
30
  /**
20
31
  * Narrowing guard for a runtime-provided filter operator. Query builders accept
21
32
  * operators that splice raw SQL (`inSubquery`, `inTable`), so anything outside
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAyB,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQrD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,EAAE,SAAS,EAAkE,CAAC;AAEhH;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAWkB,CAAC;AAIzD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,YAAY,CAAC,UAAU,CAAC,CAEhG;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,4EAUe,CAAC;AAEtD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAEvE"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAyB,YAAY,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1G;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAQrD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,EAAE,SAAS,EAAkE,CAAC;AAEhH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,oFAWkB,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,kCAGa,CAAC;AAIxD,+EAA+E;AAC/E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,uBAAuB,CAEhG;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,YAAY,CAAC,UAAU,CAAC,CAEhG;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,4EAUe,CAAC;AAEtD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAEvE"}
package/dist/constants.js CHANGED
@@ -20,7 +20,10 @@ export const GRAIN_FUNCTIONS = {
20
20
  /** The set of time grains supported by the planner, finest first. */
21
21
  export const SUPPORTED_TIME_GRAINS = ['minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'];
22
22
  /**
23
- * The filter operators accepted by semantic dataset and metric inputs.
23
+ * The filter operators accepted by semantic dataset and metric inputs, and the
24
+ * operators a filter allows when its definition lists none. The null checks in
25
+ * {@link SEMANTIC_NULL_CHECK_OPERATORS} are accepted too, but a caller filter
26
+ * may use one only when its definition lists it (RFC 0023).
24
27
  */
25
28
  export const SEMANTIC_FILTER_OPERATORS = [
26
29
  'eq',
@@ -34,7 +37,20 @@ export const SEMANTIC_FILTER_OPERATORS = [
34
37
  'between',
35
38
  'like',
36
39
  ];
37
- const FILTER_OPERATORS = new Set(SEMANTIC_FILTER_OPERATORS);
40
+ /**
41
+ * Operators that test a field for NULL and take no value (RFC 0023). Measure
42
+ * and segment filters may use them freely; a caller filter only when its
43
+ * definition's `operators` list names them.
44
+ */
45
+ export const SEMANTIC_NULL_CHECK_OPERATORS = [
46
+ 'isNull',
47
+ 'isNotNull',
48
+ ];
49
+ const FILTER_OPERATORS = new Set([...SEMANTIC_FILTER_OPERATORS, ...SEMANTIC_NULL_CHECK_OPERATORS]);
50
+ /** True for `isNull` and `isNotNull`, the filter operators without a value. */
51
+ export function isNullCheckFilterOperator(operator) {
52
+ return operator === 'isNull' || operator === 'isNotNull';
53
+ }
38
54
  /**
39
55
  * Narrowing guard for a runtime-provided filter operator. Query builders accept
40
56
  * operators that splice raw SQL (`inSubquery`, `inTable`), so anything outside
@@ -1 +1 @@
1
- {"version":3,"file":"in-memory-backend.d.ts","sourceRoot":"","sources":["../src/in-memory-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AA2V3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAwE7E"}
1
+ {"version":3,"file":"in-memory-backend.d.ts","sourceRoot":"","sources":["../src/in-memory-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,eAAe,EAKhB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AA+V3D;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAwE7E"}
@@ -29,6 +29,10 @@ function compareFilter(actual, filter) {
29
29
  return typeof actual === 'string'
30
30
  && typeof filter.value === 'string'
31
31
  && actual.includes(filter.value.replaceAll('%', ''));
32
+ case 'isNull':
33
+ return actual === null || actual === undefined;
34
+ case 'isNotNull':
35
+ return actual !== null && actual !== undefined;
32
36
  default:
33
37
  return false;
34
38
  }
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export type { CheckRelationshipsOptions, CheckRelationshipsResult, RelationshipK
8
8
  export { sum, count, countDistinct, approxCountDistinct, avg, min, max, percentile, median, argMax, argMin, stddev, variance, merge, } from './aggregations.js';
9
9
  export { AGGREGATE_STATE_FUNCTIONS, type AggregateStateFunction } from './utils/aggregate-state-functions.js';
10
10
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
11
- export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
11
+ export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, isNull, isNotNull, asc, desc, filter, order, } from './query-helpers.js';
12
12
  export { createDatasetRegistry } from './registry.js';
13
13
  export { publishDatasets } from './publishing/publisher.js';
14
14
  export type { DatasetPublisher } from './publishing/publisher.js';
@@ -28,6 +28,9 @@ export type { BuildProtocolDeploymentContractOptions } from './protocol-deployme
28
28
  export { rehydrateProtocolDeploymentContract } from './protocol-rehydrate.js';
29
29
  export type { BuildProtocolDatasetContractOptions } from './protocol-adapter.js';
30
30
  export { publishToCloud } from './cloud-publishing.js';
31
+ export { buildClientContract } from './client-contract/build-from-deployment.js';
32
+ export type { BuildClientContractOptions } from './client-contract/build-from-deployment.js';
33
+ export type { ClientContractProfile } from './client-contract/deployment-profile.js';
31
34
  export type { CloudPublishingOptions } from './cloud-publishing.js';
32
35
  export { createPortableSemanticExecutor, createPortableSemanticRuntime, PortableExecutionBudgetError, PortableExecutionTenantError, PortableExecutionUnsupportedError, } from './portable-executor.js';
33
36
  export type { PortableSemanticBudget, PortableSemanticRuntime, PortableDatasetCompilation, PortableSemanticExecutionInput, PortableSemanticExecutorOptions, } from './portable-executor.js';
@@ -93,8 +96,8 @@ export { validateFilterValue, matchesFieldType } from './validation.js';
93
96
  export type { QueryBuilderLike, QueryBuilderFactoryLike, QueryBuilderFactoryCompatible, QueryBuilderFactoryInput, } from './query-builder-protocol.js';
94
97
  export { toQueryBuilderFactory } from './query-builder-protocol.js';
95
98
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
96
- export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SEMANTIC_HAVING_OPERATORS, SUPPORTED_TIME_GRAINS } from './constants.js';
97
- export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, MeasureTimeInterval, WindowMeasureDefinition, ShiftMeasureDefinition, DatasetMeasureDefinition, DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, InferDimensionType, RelationshipKind, RelationshipDefinition, RelationshipKey, RelationshipJoin, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricFilterOperator, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SegmentDefinition, SemanticFiltersDefinition, DatasetConfig, RowResolution, DatasetDefaults, DatasetFreshness, DatasetLimits, DatasetCachePolicy, SemanticMetadata, SemanticSensitivity, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetQueryableDimensions, DatasetQueryableMeasures, DatasetMeasureNames, DatasetSegmentNames, DatasetTimeKeyNames, DatasetOrderableNames, DatasetQueryFor, DatasetHavingCondition, DatasetHavingFor, DatasetHavingOperator, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
99
+ export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SEMANTIC_HAVING_OPERATORS, SEMANTIC_NULL_CHECK_OPERATORS, SUPPORTED_TIME_GRAINS, } from './constants.js';
100
+ export type { FieldType, DimensionType, DimensionOptions, DimensionDefinition, MeasureOptions, MeasureDefinition, MeasureTimeInterval, WindowMeasureDefinition, ShiftMeasureDefinition, DatasetMeasureDefinition, DerivedMeasureDefinition, DerivedMeasureOptions, DerivedMeasureUses, InferDimensionType, RelationshipKind, RelationshipDefinition, RelationshipKey, RelationshipJoin, AggregationType, MeasureAggregation, AggregationSpec, FormulaExpr, DerivedMetricSpec, TimeGrain, MetricRef, BaseMetricRef, DerivedMetricRef, GrainedMetricRef, MetricContract, MetricFilter, MetricFilterOperator, MetricNullCheckOperator, MetricValueFilterOperator, MetricOrderBy, MetricQuery, DatasetQuery, MetricResultMeta, MetricResult, DatasetQueryResult, MetricHandle, ExecutionContext, SemanticExecutionRuntime, SemanticTenantRuntime, SemanticFilterDefinition, SegmentDefinition, SemanticFiltersDefinition, DatasetConfig, RowResolution, DatasetDefaults, DatasetFreshness, DatasetLimits, DatasetCachePolicy, SemanticMetadata, SemanticSensitivity, DatasetInstance, AnyDatasetInstance, BaseMetricConfig, DerivedMetricConfig, DatasetRegistryInstance, DatasetFieldNames, DatasetDimensionNames, DatasetQueryableDimensions, DatasetQueryableMeasures, DatasetMeasureNames, DatasetSegmentNames, DatasetTimeKeyNames, DatasetOrderableNames, DatasetQueryFor, DatasetHavingCondition, DatasetHavingFor, DatasetHavingOperator, DatasetRow, DatasetRowFor, DatasetQueryResultFor, MetricQueryFor, MetricRow, MetricRowFor, MetricResultFor, KnownStringKeys, } from './types.js';
98
101
  export type { DatasetCompilation, DatasetCompiledStatement, DatasetCompilationDescription, } from './dataset-compilation.js';
99
102
  export { DATASET_EXECUTION_CAPABILITIES } from './execution-capabilities.js';
100
103
  export type { DatasetFeature, DatasetFeatureSupport, DatasetExecutionCapabilities } from './execution-capabilities.js';
@@ -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":"AAAA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAC7D,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,GAC5D,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,KAAK,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAG9G,OAAO,EACL,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAC/B,UAAU,EAAE,QAAQ,EACpB,KAAK,EAAE,KAAK,EAAE,IAAI,GACnB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EACzB,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,KAAK,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,gCAAgC,EAAE,MAAM,cAAc,CAAC;AACvI,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACjF,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,6BAA6B,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,gCAAgC,GACjC,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,YAAY,EACZ,yBAAyB,GAC1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,iBAAiB,EACjB,gCAAgC,EAChC,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,YAAY,EAAE,sCAAsC,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,EAAE,mCAAmC,EAAE,MAAM,yBAAyB,CAAC;AAC9E,YAAY,EAAE,mCAAmC,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACjF,YAAY,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,EAC5B,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,8BAA8B,EAC9B,+BAA+B,GAChC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,gBAAgB,EAChB,gCAAgC,EAChC,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAKvB,uGAAuG;AACvG,eAAO,MAAM,oBAAoB,qCAA+B,CAAC;AACjE,uGAAuG;AACvG,eAAO,MAAM,aAAa,8BAAwB,CAAC;AACnD,uGAAuG;AACvG,eAAO,MAAM,YAAY,6BAAuB,CAAC;AACjD,uGAAuG;AACvG,eAAO,MAAM,UAAU,2BAAqB,CAAC;AAC7C,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,wCAAkC,CAAC;AACvE,uGAAuG;AACvG,eAAO,MAAM,sBAAsB,uCAAiC,CAAC;AACrE,uGAAuG;AACvG,eAAO,MAAM,kCAAkC,mDAA6C,CAAC;AAC7F,uGAAuG;AACvG,eAAO,MAAM,oBAAoB,qCAA+B,CAAC;AACjE,uGAAuG;AACvG,eAAO,MAAM,oCAAoC;;;;;;;EAA+C,CAAC;AACjG,uGAAuG;AACvG,eAAO,MAAM,+BAA+B,gDAA0C,CAAC;AACvF,uGAAuG;AACvG,eAAO,MAAM,8BAA8B,+CAAyC,CAAC;AACrF,uGAAuG;AACvG,eAAO,MAAM,mBAAmB,oCAA8B,CAAC;AAC/D,uGAAuG;AACvG,eAAO,MAAM,0BAA0B,2CAAqC,CAAC;AAC7E,uGAAuG;AACvG,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;AAC5E,uGAAuG;AACvG,eAAO,MAAM,+BAA+B,gDAA0C,CAAC;AACvF,uGAAuG;AACvG,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAC,6BAA6B,CAAC;AAClF,uGAAuG;AACvG,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;AAC5E,uGAAuG;AACvG,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC;AAI1E,YAAY,EACV,2BAA2B,EAC3B,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,2BAA2B,EAC3B,UAAU,EACV,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAG/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGhG,OAAO,EACL,eAAe,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,qBAAqB,GAC5H,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,kBAAkB,EAAE,wBAAwB,EAAE,6BAA6B,GAC5E,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAC7E,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AACvH,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC"}
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ export { AGGREGATE_STATE_FUNCTIONS } from './utils/aggregate-state-functions.js'
14
14
  // Formula helpers
15
15
  export { divide, multiply, subtract, add, nullIfZero, coalesce, round, floor, ceil, } from './formulas.js';
16
16
  // Semantic query helpers
17
- export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, asc, desc, filter, order, } from './query-helpers.js';
17
+ export { eq, neq, gt, gte, lt, lte, inList, notInList, between, like, isNull, isNotNull, asc, desc, filter, order, } from './query-helpers.js';
18
18
  // Registry
19
19
  export { createDatasetRegistry } from './registry.js';
20
20
  // First-class publication builder for Serve, MCP, and agent consumers.
@@ -33,6 +33,7 @@ export { buildProtocolDeploymentContract } from './protocol-deployment-adapter.j
33
33
  export { assertDeployable } from './utils/deployable-formulas.js';
34
34
  export { rehydrateProtocolDeploymentContract } from './protocol-rehydrate.js';
35
35
  export { publishToCloud } from './cloud-publishing.js';
36
+ export { buildClientContract } from './client-contract/build-from-deployment.js';
36
37
  // Portable native execution of a semantic invocation (decision 0005).
37
38
  export { createPortableSemanticExecutor, createPortableSemanticRuntime, PortableExecutionBudgetError, PortableExecutionTenantError, PortableExecutionUnsupportedError, } from './portable-executor.js';
38
39
  // SQL portability compiler (R1A-07)
@@ -81,5 +82,5 @@ export { toQueryBuilderFactory } from './query-builder-protocol.js';
81
82
  // SQL utilities
82
83
  export { validateSQLIdentifier, isSafeSQLIdentifier, quoteSQLIdentifier } from './sql-utils.js';
83
84
  // Constants
84
- export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SEMANTIC_HAVING_OPERATORS, SUPPORTED_TIME_GRAINS } from './constants.js';
85
+ export { GRAIN_FUNCTIONS, SEMANTIC_FILTER_OPERATORS, SEMANTIC_HAVING_OPERATORS, SEMANTIC_NULL_CHECK_OPERATORS, SUPPORTED_TIME_GRAINS, } from './constants.js';
85
86
  export { DATASET_EXECUTION_CAPABILITIES } from './execution-capabilities.js';
@@ -9,6 +9,10 @@ export declare function inList<const TField extends string, const TValue>(field:
9
9
  export declare function notInList<const TField extends string, const TValue>(field: TField, value: TValue[]): MetricFilter<TField, TValue[], 'notIn'>;
10
10
  export declare function between<const TField extends string, const TLower, const TUpper>(field: TField, lower: TLower, upper: TUpper): MetricFilter<TField, [TLower, TUpper], 'between'>;
11
11
  export declare function like<const TField extends string>(field: TField, value: string): MetricFilter<TField, string, 'like'>;
12
+ /** Rows where `field` is NULL (RFC 0023); takes no value. */
13
+ export declare function isNull<const TField extends string>(field: TField): MetricFilter<TField, never, 'isNull'>;
14
+ /** Rows where `field` is not NULL (RFC 0023); takes no value. */
15
+ export declare function isNotNull<const TField extends string>(field: TField): MetricFilter<TField, never, 'isNotNull'>;
12
16
  export declare function asc<const TField extends string>(field: TField): MetricOrderBy<TField>;
13
17
  export declare function desc<const TField extends string>(field: TField): MetricOrderBy<TField>;
14
18
  export declare const filter: {
@@ -22,6 +26,8 @@ export declare const filter: {
22
26
  readonly notInList: typeof notInList;
23
27
  readonly between: typeof between;
24
28
  readonly like: typeof like;
29
+ readonly isNull: typeof isNull;
30
+ readonly isNotNull: typeof isNotNull;
25
31
  };
26
32
  export declare const order: {
27
33
  readonly asc: typeof asc;