@hypequery/protocol 0.15.0 → 0.17.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/dist/cache-preimages/cache-preimages.d.ts +21 -0
- package/dist/cache-preimages/cache-preimages.d.ts.map +1 -0
- package/dist/cache-preimages/cache-preimages.js +143 -0
- package/dist/cache-preimages/index.d.ts +3 -0
- package/dist/cache-preimages/index.d.ts.map +1 -0
- package/dist/cache-preimages/index.js +1 -0
- package/dist/cache-preimages/types.d.ts +29 -0
- package/dist/cache-preimages/types.d.ts.map +1 -0
- package/dist/cache-preimages/types.js +1 -0
- package/dist/deployments/codec.d.ts +8 -1
- package/dist/deployments/codec.d.ts.map +1 -1
- package/dist/deployments/codec.js +12 -4
- package/dist/deployments/index.d.ts +4 -4
- package/dist/deployments/index.d.ts.map +1 -1
- package/dist/deployments/index.js +2 -2
- package/dist/deployments/segments.d.ts +21 -0
- package/dist/deployments/segments.d.ts.map +1 -0
- package/dist/deployments/segments.js +57 -0
- package/dist/deployments/types.d.ts +71 -1
- package/dist/deployments/types.d.ts.map +1 -1
- package/dist/deployments/validate.d.ts +11 -1
- package/dist/deployments/validate.d.ts.map +1 -1
- package/dist/deployments/validate.js +205 -22
- package/dist/expressions/index.d.ts +1 -1
- package/dist/expressions/index.d.ts.map +1 -1
- package/dist/expressions/types.d.ts +29 -3
- package/dist/expressions/types.d.ts.map +1 -1
- package/dist/expressions/validate.d.ts.map +1 -1
- package/dist/expressions/validate.js +38 -9
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/invocations/index.d.ts +2 -2
- package/dist/invocations/index.d.ts.map +1 -1
- package/dist/invocations/index.js +1 -1
- package/dist/invocations/types.d.ts +8 -0
- package/dist/invocations/types.d.ts.map +1 -1
- package/dist/invocations/validate.d.ts +10 -1
- package/dist/invocations/validate.d.ts.map +1 -1
- package/dist/invocations/validate.js +32 -7
- package/package.json +1 -1
|
@@ -2,16 +2,23 @@ import { ProtocolExpressionError, validateProtocolExpression } from '../expressi
|
|
|
2
2
|
import { ProtocolIdentifierError, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, } from '../identifiers/index.js';
|
|
3
3
|
import { validateProtocolSqlExpression } from '../sql-expressions/validate.js';
|
|
4
4
|
import { deploymentError } from './errors.js';
|
|
5
|
+
import { expressionReferences, isSegmentPredicate, isSegmentReference } from './segments.js';
|
|
5
6
|
import { resolveDeploymentLimits } from './limits.js';
|
|
6
7
|
const textEncoder = new TextEncoder();
|
|
7
8
|
const AGGREGATIONS = new Set([
|
|
8
9
|
'sum', 'count', 'countDistinct', 'avg', 'min', 'max',
|
|
9
10
|
'argMax', 'argMin', 'percentile', 'stddev', 'variance',
|
|
10
11
|
]);
|
|
12
|
+
const AGGREGATIONS_V3 = new Set([...AGGREGATIONS, 'approxCountDistinct']);
|
|
13
|
+
const APPROXIMATE_AGGREGATIONS = new Set(['approxCountDistinct']);
|
|
11
14
|
const OPERATORS = new Set([
|
|
12
15
|
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like',
|
|
13
16
|
]);
|
|
14
17
|
const GRAINS = new Set(['day', 'week', 'month', 'quarter', 'year']);
|
|
18
|
+
const GRAINS_V3 = new Set(['minute', 'hour', ...GRAINS]);
|
|
19
|
+
const SUB_DAY_GRAINS = new Set(['minute', 'hour']);
|
|
20
|
+
/** Aggregations a `cumulative` window may wrap: a running total of bucket partials. */
|
|
21
|
+
const CUMULATIVE_AGGREGATIONS = new Set(['sum', 'count', 'min', 'max']);
|
|
15
22
|
const SENSITIVITIES = new Set(['public', 'internal', 'confidential', 'restricted']);
|
|
16
23
|
const SEMANTIC_METADATA_FIELDS = [
|
|
17
24
|
'examples', 'synonyms', 'format', 'unit', 'currency', 'timezone', 'sensitivity',
|
|
@@ -259,12 +266,24 @@ function validateDimension(input, path, limits) {
|
|
|
259
266
|
validateSemanticMetadata(value, result, path, limits);
|
|
260
267
|
return freezeRecord(result);
|
|
261
268
|
}
|
|
262
|
-
function validateMeasure(input, path, limits) {
|
|
269
|
+
function validateMeasure(input, path, limits, version = 2) {
|
|
263
270
|
const value = requireRecord(input, path);
|
|
264
|
-
exactFields(value, ['name', 'aggregation', 'field', 'filters'], [
|
|
265
|
-
|
|
271
|
+
exactFields(value, ['name', 'aggregation', 'field', 'filters'], [
|
|
272
|
+
'argField', 'level', 'sql', 'label', 'description', ...SEMANTIC_METADATA_FIELDS,
|
|
273
|
+
...(version === 3 ? ['approximate'] : []),
|
|
274
|
+
], path);
|
|
275
|
+
if (typeof value.aggregation !== 'string'
|
|
276
|
+
|| !(version === 3 ? AGGREGATIONS_V3 : AGGREGATIONS).has(value.aggregation)) {
|
|
266
277
|
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.aggregation`);
|
|
267
278
|
}
|
|
279
|
+
// The marker is not free: present, as `true`, exactly for an approximate aggregation.
|
|
280
|
+
const approximate = APPROXIMATE_AGGREGATIONS.has(value.aggregation);
|
|
281
|
+
if (value.approximate !== undefined && value.approximate !== true) {
|
|
282
|
+
deploymentError('HQ_DEPLOYMENT_TYPE', `${path}.approximate`);
|
|
283
|
+
}
|
|
284
|
+
if (approximate !== (value.approximate === true)) {
|
|
285
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.approximate`);
|
|
286
|
+
}
|
|
268
287
|
const needsArg = value.aggregation === 'argMax' || value.aggregation === 'argMin';
|
|
269
288
|
if (needsArg !== (value.argField !== undefined)) {
|
|
270
289
|
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.argField`);
|
|
@@ -282,8 +301,10 @@ function validateMeasure(input, path, limits) {
|
|
|
282
301
|
aggregation: value.aggregation,
|
|
283
302
|
field: identifier(value.field, `${path}.field`, true),
|
|
284
303
|
filters: Object.freeze(requireArray(value.filters, `${path}.filters`, limits.maxDatasetItems)
|
|
285
|
-
.map((filter, index) => nested(() => validateProtocolExpression(filter), `${path}.filters[${index}]`))),
|
|
304
|
+
.map((filter, index) => nested(() => validateProtocolExpression(filter, { extension: version === 3 ? 2 : 1 }), `${path}.filters[${index}]`))),
|
|
286
305
|
};
|
|
306
|
+
if (approximate)
|
|
307
|
+
result.approximate = true;
|
|
287
308
|
if (value.argField !== undefined)
|
|
288
309
|
result.argField = identifier(value.argField, `${path}.argField`, true);
|
|
289
310
|
if (value.level !== undefined)
|
|
@@ -545,7 +566,7 @@ function validateFreshness(input, path) {
|
|
|
545
566
|
maxAgeSeconds: positiveInteger(value.maxAgeSeconds, `${path}.maxAgeSeconds`),
|
|
546
567
|
});
|
|
547
568
|
}
|
|
548
|
-
function validateDefaults(input, path, limits) {
|
|
569
|
+
function validateDefaults(input, path, limits, version) {
|
|
549
570
|
const value = requireRecord(input, path);
|
|
550
571
|
exactFields(value, [], ['dimensions', 'timeGrain'], path);
|
|
551
572
|
const result = {};
|
|
@@ -553,7 +574,7 @@ function validateDefaults(input, path, limits) {
|
|
|
553
574
|
result.dimensions = uniqueStrings(value.dimensions, `${path}.dimensions`, limits.maxSemanticMetadataItems, (dimension, dimensionPath) => identifier(dimension, dimensionPath));
|
|
554
575
|
}
|
|
555
576
|
if (value.timeGrain !== undefined) {
|
|
556
|
-
if (typeof value.timeGrain !== 'string' || !GRAINS.has(value.timeGrain)) {
|
|
577
|
+
if (typeof value.timeGrain !== 'string' || !(version === 3 ? GRAINS_V3 : GRAINS).has(value.timeGrain)) {
|
|
557
578
|
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.timeGrain`);
|
|
558
579
|
}
|
|
559
580
|
result.timeGrain = value.timeGrain;
|
|
@@ -570,23 +591,46 @@ function namedItems(input, path, maxItems, validate) {
|
|
|
570
591
|
}
|
|
571
592
|
return Object.freeze(items);
|
|
572
593
|
}
|
|
573
|
-
function
|
|
594
|
+
function validateSegment(input, path, limits, dimensions, tenant) {
|
|
595
|
+
const value = requireRecord(input, path);
|
|
596
|
+
exactFields(value, ['name', 'predicate'], ['label', 'description', ...SEMANTIC_METADATA_FIELDS], path);
|
|
597
|
+
const name = identifier(value.name, `${path}.name`);
|
|
598
|
+
const predicate = nested(() => validateProtocolExpression(value.predicate, { extension: 2 }), `${path}.predicate`);
|
|
599
|
+
if (!isSegmentPredicate(predicate)
|
|
600
|
+
|| expressionReferences(predicate).some(reference => !isSegmentReference(reference, dimensions, tenant))) {
|
|
601
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.predicate`);
|
|
602
|
+
}
|
|
603
|
+
const result = { name, predicate };
|
|
604
|
+
optionalText(value.label, 'label', result, path, limits);
|
|
605
|
+
optionalText(value.description, 'description', result, path, limits);
|
|
606
|
+
validateSemanticMetadata(value, result, path, limits);
|
|
607
|
+
return freezeRecord(result);
|
|
608
|
+
}
|
|
609
|
+
function validateDataset(input, path, limits, measureIndices, version = 2) {
|
|
574
610
|
const value = requireRecord(input, path);
|
|
575
|
-
|
|
611
|
+
// Contract 3 renames the allow-list; the old name is then an unknown field.
|
|
612
|
+
const filtersKey = version === 3 ? 'allowedFilters' : 'filters';
|
|
613
|
+
exactFields(value, [
|
|
614
|
+
'name', 'source', 'tenant', 'dimensions', 'measures', filtersKey, 'metrics', 'relationships',
|
|
615
|
+
], [
|
|
576
616
|
'description', 'freshness', 'owner', 'defaults',
|
|
577
617
|
...SEMANTIC_METADATA_FIELDS,
|
|
578
618
|
'timeField', 'limits', 'endpoint',
|
|
619
|
+
...(version === 3 ? ['segments'] : []),
|
|
579
620
|
], path);
|
|
580
621
|
const result = {
|
|
581
622
|
name: identifier(value.name, `${path}.name`),
|
|
582
623
|
source: boundedText(value.source, `${path}.source`, limits.maxSourceBytes),
|
|
583
624
|
tenant: validateTenant(value.tenant, `${path}.tenant`, limits),
|
|
584
625
|
dimensions: namedItems(value.dimensions, `${path}.dimensions`, limits.maxDatasetItems, (item, itemPath) => validateDimension(item, itemPath, limits)),
|
|
585
|
-
measures: namedItems(value.measures, `${path}.measures`, limits.maxDatasetItems, (item, itemPath, index) => validateMeasure(item, measureIndices === undefined ? itemPath : `${path}.measures[${measureIndices[index]}]`, limits)),
|
|
586
|
-
|
|
626
|
+
measures: namedItems(value.measures, `${path}.measures`, limits.maxDatasetItems, (item, itemPath, index) => validateMeasure(item, measureIndices === undefined ? itemPath : `${path}.measures[${measureIndices[index]}]`, limits, version)),
|
|
627
|
+
[filtersKey]: namedItems(value[filtersKey], `${path}.${filtersKey}`, limits.maxDatasetItems, (item, itemPath) => validateFilter(item, itemPath, limits)),
|
|
587
628
|
metrics: namedItems(value.metrics, `${path}.metrics`, limits.maxDatasetItems, (item, itemPath) => validateMetric(item, itemPath, limits)),
|
|
588
629
|
relationships: namedItems(value.relationships, `${path}.relationships`, limits.maxDatasetItems, (item, itemPath) => validateRelationship(item, itemPath)),
|
|
589
630
|
};
|
|
631
|
+
if (version === 3 && value.segments !== undefined) {
|
|
632
|
+
result.segments = namedItems(value.segments, `${path}.segments`, limits.maxDatasetItems, (item, itemPath) => validateSegment(item, itemPath, limits, result.dimensions, result.tenant));
|
|
633
|
+
}
|
|
590
634
|
if (value.timeField !== undefined)
|
|
591
635
|
result.timeField = identifier(value.timeField, `${path}.timeField`, true);
|
|
592
636
|
optionalText(value.description, 'description', result, path, limits);
|
|
@@ -596,7 +640,7 @@ function validateDataset(input, path, limits, measureIndices) {
|
|
|
596
640
|
result.freshness = validateFreshness(value.freshness, `${path}.freshness`);
|
|
597
641
|
}
|
|
598
642
|
if (value.defaults !== undefined) {
|
|
599
|
-
result.defaults = validateDefaults(value.defaults, `${path}.defaults`, limits);
|
|
643
|
+
result.defaults = validateDefaults(value.defaults, `${path}.defaults`, limits, version);
|
|
600
644
|
}
|
|
601
645
|
if (value.limits !== undefined)
|
|
602
646
|
result.limits = validateLimits(value.limits, `${path}.limits`);
|
|
@@ -644,11 +688,15 @@ function formulaReferences(expression, names) {
|
|
|
644
688
|
return;
|
|
645
689
|
}
|
|
646
690
|
}
|
|
647
|
-
function validateDatasetDerivedMeasure(input, path, limits) {
|
|
691
|
+
function validateDatasetDerivedMeasure(input, path, limits, version) {
|
|
648
692
|
const value = requireRecord(input, path);
|
|
649
693
|
exactFields(value, ['kind', 'name', 'uses', 'expression'], [
|
|
650
694
|
'label', 'description', ...SEMANTIC_METADATA_FIELDS,
|
|
695
|
+
...(version === 3 ? ['approximate'] : []),
|
|
651
696
|
], path);
|
|
697
|
+
if (value.approximate !== undefined && value.approximate !== true) {
|
|
698
|
+
deploymentError('HQ_DEPLOYMENT_TYPE', `${path}.approximate`);
|
|
699
|
+
}
|
|
652
700
|
if (value.kind !== 'derived')
|
|
653
701
|
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.kind`);
|
|
654
702
|
const uses = requireArray(value.uses, `${path}.uses`, limits.maxDatasetItems)
|
|
@@ -680,40 +728,144 @@ function validateDatasetDerivedMeasure(input, path, limits) {
|
|
|
680
728
|
uses: Object.freeze(uses),
|
|
681
729
|
expression,
|
|
682
730
|
};
|
|
731
|
+
// Checked against the base measures by the dataset, once they are known.
|
|
732
|
+
if (value.approximate === true)
|
|
733
|
+
result.approximate = true;
|
|
683
734
|
optionalText(value.label, 'label', result, path, limits);
|
|
684
735
|
optionalText(value.description, 'description', result, path, limits);
|
|
685
736
|
validateSemanticMetadata(value, result, path, limits);
|
|
686
737
|
return freezeRecord(result);
|
|
687
738
|
}
|
|
688
|
-
function
|
|
739
|
+
function validateInterval(input, path) {
|
|
689
740
|
const value = requireRecord(input, path);
|
|
690
|
-
exactFields(value, ['
|
|
741
|
+
exactFields(value, ['amount', 'unit'], [], path);
|
|
742
|
+
const amount = positiveInteger(value.amount, `${path}.amount`);
|
|
743
|
+
if (typeof value.unit !== 'string' || !GRAINS_V3.has(value.unit)) {
|
|
744
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.unit`);
|
|
745
|
+
}
|
|
746
|
+
return freezeRecord({ amount, unit: value.unit });
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Validates the shape of a contract 3 `window` or `shift` measure. Rules that
|
|
750
|
+
* need the rest of the dataset (the wrapped base measure, the time field, and
|
|
751
|
+
* approximation) are checked by the dataset. Rules that need the query grain
|
|
752
|
+
* (whole-bucket intervals, the bucket bound) are enforced at query time.
|
|
753
|
+
*/
|
|
754
|
+
function validateTimeMeasure(value, path, limits) {
|
|
755
|
+
const window = value.kind === 'window';
|
|
756
|
+
exactFields(value, window
|
|
757
|
+
? ['kind', 'name', 'measure', 'requiresTimeRange']
|
|
758
|
+
: ['kind', 'name', 'measure', 'interval', 'requiresTimeRange'], [
|
|
759
|
+
...(window ? ['trailing', 'toDate', 'cumulative'] : []),
|
|
760
|
+
'approximate', 'label', 'description', ...SEMANTIC_METADATA_FIELDS,
|
|
761
|
+
], path);
|
|
762
|
+
if (value.approximate !== undefined && value.approximate !== true) {
|
|
763
|
+
deploymentError('HQ_DEPLOYMENT_TYPE', `${path}.approximate`);
|
|
764
|
+
}
|
|
765
|
+
if (value.requiresTimeRange !== true) {
|
|
766
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.requiresTimeRange`);
|
|
767
|
+
}
|
|
768
|
+
const result = {
|
|
769
|
+
kind: value.kind,
|
|
770
|
+
name: identifier(value.name, `${path}.name`),
|
|
771
|
+
measure: identifier(value.measure, `${path}.measure`),
|
|
772
|
+
requiresTimeRange: true,
|
|
773
|
+
};
|
|
774
|
+
if (window) {
|
|
775
|
+
const frames = ['trailing', 'toDate', 'cumulative'].filter(key => value[key] !== undefined);
|
|
776
|
+
if (frames.length !== 1)
|
|
777
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', path);
|
|
778
|
+
if (value.trailing !== undefined)
|
|
779
|
+
result.trailing = validateInterval(value.trailing, `${path}.trailing`);
|
|
780
|
+
if (value.toDate !== undefined) {
|
|
781
|
+
// A to-date period must be coarser than some bucket, so `minute` has none.
|
|
782
|
+
if (typeof value.toDate !== 'string' || !GRAINS_V3.has(value.toDate) || value.toDate === 'minute') {
|
|
783
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.toDate`);
|
|
784
|
+
}
|
|
785
|
+
result.toDate = value.toDate;
|
|
786
|
+
}
|
|
787
|
+
if (value.cumulative !== undefined) {
|
|
788
|
+
if (value.cumulative !== true)
|
|
789
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.cumulative`);
|
|
790
|
+
result.cumulative = true;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
result.interval = validateInterval(value.interval, `${path}.interval`);
|
|
795
|
+
}
|
|
796
|
+
if (value.approximate === true)
|
|
797
|
+
result.approximate = true;
|
|
798
|
+
optionalText(value.label, 'label', result, path, limits);
|
|
799
|
+
optionalText(value.description, 'description', result, path, limits);
|
|
800
|
+
validateSemanticMetadata(value, result, path, limits);
|
|
801
|
+
return freezeRecord(result);
|
|
802
|
+
}
|
|
803
|
+
function validateDeploymentDataset(input, path, limits, version = 2) {
|
|
804
|
+
const value = requireRecord(input, path);
|
|
805
|
+
exactFields(value, [
|
|
806
|
+
'name', 'source', 'tenant', 'dimensions', 'measures',
|
|
807
|
+
version === 3 ? 'allowedFilters' : 'filters', 'relationships',
|
|
808
|
+
], [
|
|
691
809
|
'description', 'freshness', 'owner', 'defaults',
|
|
692
810
|
...SEMANTIC_METADATA_FIELDS, 'timeField', 'limits', 'endpoint',
|
|
811
|
+
...(version === 3 ? ['segments'] : []),
|
|
693
812
|
], path);
|
|
694
813
|
const measures = requireArray(value.measures, `${path}.measures`, limits.maxDatasetItems)
|
|
695
814
|
.map((measure, index) => requireRecord(measure, `${path}.measures[${index}]`));
|
|
815
|
+
// Base measures are validated by the dataset; composite ones (derived, and in
|
|
816
|
+
// contract 3 window and shift) reference them and are validated here.
|
|
817
|
+
const isComposite = (measure) => measure.kind === 'derived'
|
|
818
|
+
|| (version === 3 && (measure.kind === 'window' || measure.kind === 'shift'));
|
|
696
819
|
// Preserve original indices when validating base measures separately.
|
|
697
|
-
const baseEntries = measures.flatMap((measure, index) => (measure
|
|
698
|
-
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
820
|
+
const baseEntries = measures.flatMap((measure, index) => (isComposite(measure) ? [] : [{ measure, index }]));
|
|
821
|
+
const validated = validateDataset({ ...value, measures: baseEntries.map(entry => entry.measure), metrics: [] }, path, limits, baseEntries.map(entry => entry.index), version);
|
|
822
|
+
const composite = measures.map((measure, index) => {
|
|
823
|
+
const measurePath = `${path}.measures[${index}]`;
|
|
824
|
+
if (measure.kind === 'derived') {
|
|
825
|
+
return validateDatasetDerivedMeasure(measure, measurePath, limits, version);
|
|
826
|
+
}
|
|
827
|
+
return isComposite(measure) ? validateTimeMeasure(measure, measurePath, limits) : undefined;
|
|
828
|
+
});
|
|
829
|
+
const derived = composite.map(item => (item?.kind === 'derived' ? item : undefined));
|
|
703
830
|
const baseByName = new Map(validated.measures.map(measure => [measure.name, measure]));
|
|
704
831
|
let baseIndex = 0;
|
|
705
|
-
const ordered = measures.map((_, index) => (
|
|
832
|
+
const ordered = measures.map((_, index) => (composite[index] ?? validated.measures[baseIndex++]));
|
|
706
833
|
if (new Set(ordered.map(measure => measure.name)).size !== measures.length) {
|
|
707
834
|
deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `${path}.measures`);
|
|
708
835
|
}
|
|
836
|
+
const isApproximate = (measure) => measure?.approximate === true;
|
|
837
|
+
// A time measure wraps exactly one base measure and needs the dataset's time axis.
|
|
838
|
+
const timeByName = new Map();
|
|
839
|
+
for (const [index, item] of composite.entries()) {
|
|
840
|
+
if (!item || item.kind === 'derived')
|
|
841
|
+
continue;
|
|
842
|
+
const timeMeasure = item;
|
|
843
|
+
const measurePath = `${path}.measures[${index}]`;
|
|
844
|
+
const wrapped = baseByName.get(timeMeasure.measure);
|
|
845
|
+
if (!wrapped)
|
|
846
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `${measurePath}.measure`);
|
|
847
|
+
if (validated.timeField === undefined)
|
|
848
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `${measurePath}.kind`);
|
|
849
|
+
if (timeMeasure.cumulative === true && !CUMULATIVE_AGGREGATIONS.has(wrapped.aggregation)) {
|
|
850
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${measurePath}.cumulative`);
|
|
851
|
+
}
|
|
852
|
+
if (isApproximate(wrapped) !== isApproximate(timeMeasure)) {
|
|
853
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${measurePath}.approximate`);
|
|
854
|
+
}
|
|
855
|
+
timeByName.set(timeMeasure.name, timeMeasure);
|
|
856
|
+
}
|
|
709
857
|
for (const [index, item] of derived.entries()) {
|
|
710
858
|
if (!item)
|
|
711
859
|
continue;
|
|
712
860
|
for (const [useIndex, use] of item.uses.entries()) {
|
|
713
|
-
if (!baseByName.has(use.measure)) {
|
|
861
|
+
if (!baseByName.has(use.measure) && !timeByName.has(use.measure)) {
|
|
714
862
|
deploymentError('HQ_DEPLOYMENT_INVALID_REFERENCE', `${path}.measures[${index}].uses[${useIndex}].measure`);
|
|
715
863
|
}
|
|
716
864
|
}
|
|
865
|
+
const approximate = item.uses.some(use => (isApproximate(baseByName.get(use.measure) ?? timeByName.get(use.measure))));
|
|
866
|
+
if (approximate !== isApproximate(item)) {
|
|
867
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', `${path}.measures[${index}].approximate`);
|
|
868
|
+
}
|
|
717
869
|
}
|
|
718
870
|
const { metrics: _metrics, ...dataset } = validated;
|
|
719
871
|
return freezeRecord({ ...dataset, measures: Object.freeze(ordered) });
|
|
@@ -731,3 +883,34 @@ export function validateProtocolDeploymentContract(input, options = {}) {
|
|
|
731
883
|
validateDatasetReferences(datasets);
|
|
732
884
|
return freezeRecord({ kind: 'hypequery-deployment', version: 2, datasets });
|
|
733
885
|
}
|
|
886
|
+
/** True when a contract 3 dataset uses anything contract 2 cannot express. */
|
|
887
|
+
function usesContract3Feature(dataset) {
|
|
888
|
+
return (dataset.segments?.length ?? 0) > 0
|
|
889
|
+
|| dataset.measures.some(measure => (('aggregation' in measure && APPROXIMATE_AGGREGATIONS.has(measure.aggregation))
|
|
890
|
+
|| ('kind' in measure && (measure.kind === 'window' || measure.kind === 'shift'))))
|
|
891
|
+
|| (dataset.defaults?.timeGrain !== undefined && SUB_DAY_GRAINS.has(dataset.defaults.timeGrain));
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Validate a deployment contract 3 (RFC 0015). Contract 3 renames the dataset
|
|
895
|
+
* filter allow-list to `allowedFilters` and adds segments, `approxCountDistinct`,
|
|
896
|
+
* window and shift measures, and sub-day default grains.
|
|
897
|
+
*
|
|
898
|
+
* Under the lowest-version rule, a contract that uses none of those is only
|
|
899
|
+
* valid as contract 2. Rejecting it here keeps a deployment's identity a
|
|
900
|
+
* function of its content rather than of which producer emitted it.
|
|
901
|
+
*/
|
|
902
|
+
export function validateProtocolDeploymentContractV3(input, options = {}) {
|
|
903
|
+
const limits = resolveDeploymentLimits(options);
|
|
904
|
+
const value = requireRecord(input, '$');
|
|
905
|
+
exactFields(value, ['kind', 'version', 'datasets'], [], '$');
|
|
906
|
+
if (value.kind !== 'hypequery-deployment')
|
|
907
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VALUE', '$.kind');
|
|
908
|
+
if (value.version !== 3)
|
|
909
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VERSION', '$.version');
|
|
910
|
+
const datasets = namedItems(value.datasets, '$.datasets', limits.maxDatasets, (item, path) => validateDeploymentDataset(item, path, limits, 3));
|
|
911
|
+
validateDatasetReferences(datasets);
|
|
912
|
+
if (!datasets.some(usesContract3Feature)) {
|
|
913
|
+
deploymentError('HQ_DEPLOYMENT_INVALID_VERSION', '$.version');
|
|
914
|
+
}
|
|
915
|
+
return freezeRecord({ kind: 'hypequery-deployment', version: 3, datasets });
|
|
916
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ProtocolExpressionError } from './errors.js';
|
|
2
2
|
export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS } from './limits.js';
|
|
3
3
|
export { validateProtocolExpression, validateProtocolSemanticQuery } from './validate.js';
|
|
4
|
-
export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolTimeGrain, } from './types.js';
|
|
4
|
+
export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionExtension, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolQueryTimeGrain, ProtocolTimeGrain, } from './types.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/expressions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/expressions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,kCAAkC,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAC1F,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
@@ -3,7 +3,12 @@ import type { CanonicalValue } from '../values/index.js';
|
|
|
3
3
|
export type ProtocolBinaryOperator = 'add' | 'subtract' | 'multiply' | 'divide';
|
|
4
4
|
export type ProtocolFunctionName = 'nullIfZero' | 'coalesce' | 'round' | 'floor' | 'ceil';
|
|
5
5
|
export type ProtocolComparisonOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'between' | 'like';
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Every aggregation any supported expression extension accepts.
|
|
8
|
+
* `approxCountDistinct` is extension 2 (RFC 0015); the validator rejects it
|
|
9
|
+
* under extension 1.
|
|
10
|
+
*/
|
|
11
|
+
export type ProtocolAggregation = 'sum' | 'count' | 'countDistinct' | 'avg' | 'min' | 'max' | 'argMax' | 'argMin' | 'percentile' | 'stddev' | 'variance' | 'approxCountDistinct';
|
|
7
12
|
export type ProtocolExpression = {
|
|
8
13
|
readonly kind: 'reference';
|
|
9
14
|
readonly name: ProtocolQualifiedIdentifier;
|
|
@@ -40,7 +45,16 @@ export type ProtocolExpression = {
|
|
|
40
45
|
readonly level?: number;
|
|
41
46
|
readonly filters?: readonly ProtocolExpression[];
|
|
42
47
|
};
|
|
48
|
+
/** Expression extension 1 grains, also the deployment contract 2 grain set. */
|
|
43
49
|
export type ProtocolTimeGrain = 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
50
|
+
/**
|
|
51
|
+
* Every grain a semantic query may carry under any supported extension.
|
|
52
|
+
* `minute` and `hour` are extension 2 (RFC 0015); the validator rejects them
|
|
53
|
+
* under extension 1.
|
|
54
|
+
*/
|
|
55
|
+
export type ProtocolQueryTimeGrain = 'minute' | 'hour' | ProtocolTimeGrain;
|
|
56
|
+
/** Expression extension versions this implementation validates. */
|
|
57
|
+
export type ProtocolExpressionExtension = 1 | 2;
|
|
44
58
|
export interface ProtocolOrderBy {
|
|
45
59
|
readonly field: ProtocolQualifiedIdentifier;
|
|
46
60
|
readonly direction: 'asc' | 'desc';
|
|
@@ -49,15 +63,21 @@ interface ProtocolQueryCommon {
|
|
|
49
63
|
readonly dataset: ProtocolIdentifier;
|
|
50
64
|
readonly dimensions?: readonly ProtocolQualifiedIdentifier[];
|
|
51
65
|
readonly filters?: readonly ProtocolExpression[];
|
|
66
|
+
/** Named segments, AND-combined with `filters`. Extension 2 only. */
|
|
67
|
+
readonly segments?: readonly ProtocolIdentifier[];
|
|
52
68
|
readonly orderBy?: readonly ProtocolOrderBy[];
|
|
53
69
|
readonly limit?: number;
|
|
54
70
|
readonly offset?: number;
|
|
55
|
-
readonly by?:
|
|
71
|
+
readonly by?: ProtocolQueryTimeGrain;
|
|
56
72
|
readonly includeMeta?: boolean;
|
|
57
73
|
}
|
|
58
74
|
export interface ProtocolDatasetQuery extends ProtocolQueryCommon {
|
|
59
75
|
readonly kind: 'dataset';
|
|
60
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Simple measure names. Extension 2 also accepts one-hop relationship
|
|
78
|
+
* measures such as `customer.customerCount`.
|
|
79
|
+
*/
|
|
80
|
+
readonly measures?: readonly ProtocolQualifiedIdentifier[];
|
|
61
81
|
}
|
|
62
82
|
export interface ProtocolMetricQuery extends ProtocolQueryCommon {
|
|
63
83
|
readonly kind: 'metric';
|
|
@@ -71,6 +91,12 @@ export interface ProtocolExpressionLimits {
|
|
|
71
91
|
}
|
|
72
92
|
export interface ProtocolExpressionOptions {
|
|
73
93
|
readonly limits?: Partial<ProtocolExpressionLimits>;
|
|
94
|
+
/**
|
|
95
|
+
* Expression extension to validate against. Defaults to 1. The containing
|
|
96
|
+
* artifact selects it (RFC 0015): deployment contract 3 and semantic
|
|
97
|
+
* invocation 2 use extension 2.
|
|
98
|
+
*/
|
|
99
|
+
readonly extension?: ProtocolExpressionExtension;
|
|
74
100
|
}
|
|
75
101
|
export type ProtocolExpressionErrorCode = 'HQ_EXPRESSION_TYPE' | 'HQ_EXPRESSION_UNKNOWN_FIELD' | 'HQ_EXPRESSION_UNKNOWN_KIND' | 'HQ_EXPRESSION_INVALID_IDENTIFIER' | 'HQ_EXPRESSION_INVALID_VALUE' | 'HQ_EXPRESSION_INVALID_OPERATOR' | 'HQ_EXPRESSION_INVALID_ARITY' | 'HQ_EXPRESSION_INVALID_AGGREGATION' | 'HQ_EXPRESSION_INVALID_QUERY' | 'HQ_EXPRESSION_TOO_DEEP' | 'HQ_EXPRESSION_TOO_MANY_NODES' | 'HQ_EXPRESSION_TOO_MANY_ITEMS' | 'HQ_EXPRESSION_UNSAFE_OBJECT';
|
|
76
102
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/expressions/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;AAChF,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAC1F,MAAM,MAAM,0BAA0B,GAClC,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AACrF,MAAM,MAAM,mBAAmB,GAC3B,KAAK,GAAG,OAAO,GAAG,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GACzD,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/expressions/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/expressions/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/expressions/validate.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,kBAAkB,EAGlB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAsQpB,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,kBAAkB,CAEpB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,yBAA8B,GACtC,qBAAqB,CAwDvB"}
|
|
@@ -4,11 +4,15 @@ import { expressionError } from './errors.js';
|
|
|
4
4
|
import { resolveExpressionLimits } from './limits.js';
|
|
5
5
|
const BINARY = new Set(['add', 'subtract', 'multiply', 'divide']);
|
|
6
6
|
const COMPARISONS = new Set(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'between', 'like']);
|
|
7
|
-
const
|
|
7
|
+
const AGGREGATIONS_V1 = new Set([
|
|
8
8
|
'sum', 'count', 'countDistinct', 'avg', 'min', 'max',
|
|
9
9
|
'argMax', 'argMin', 'percentile', 'stddev', 'variance',
|
|
10
10
|
]);
|
|
11
|
-
const
|
|
11
|
+
const AGGREGATIONS_V2 = new Set([
|
|
12
|
+
...AGGREGATIONS_V1, 'approxCountDistinct',
|
|
13
|
+
]);
|
|
14
|
+
const GRAINS_V1 = new Set(['day', 'week', 'month', 'quarter', 'year']);
|
|
15
|
+
const GRAINS_V2 = new Set(['minute', 'hour', ...GRAINS_V1]);
|
|
12
16
|
const CALL_ARITY = Object.freeze({
|
|
13
17
|
nullIfZero: [1, 1],
|
|
14
18
|
coalesce: [2, 2],
|
|
@@ -218,7 +222,8 @@ function validateComparisonOperands(operator, right, path) {
|
|
|
218
222
|
function validateAggregate(value, path, depth, state) {
|
|
219
223
|
exactFields(value, ['kind', 'aggregation', 'field'], ['argField', 'level', 'filters'], path);
|
|
220
224
|
const aggregation = stringValue(value.aggregation, `${path}.aggregation`);
|
|
221
|
-
|
|
225
|
+
const aggregations = state.extension === 2 ? AGGREGATIONS_V2 : AGGREGATIONS_V1;
|
|
226
|
+
if (!aggregations.has(aggregation))
|
|
222
227
|
expressionError('HQ_EXPRESSION_INVALID_AGGREGATION', `${path}.aggregation`);
|
|
223
228
|
const isArg = aggregation === 'argMax' || aggregation === 'argMin';
|
|
224
229
|
const isPercentile = aggregation === 'percentile';
|
|
@@ -244,7 +249,11 @@ function validateAggregate(value, path, depth, state) {
|
|
|
244
249
|
});
|
|
245
250
|
}
|
|
246
251
|
function newState(options) {
|
|
247
|
-
|
|
252
|
+
const extension = options.extension ?? 1;
|
|
253
|
+
if (extension !== 1 && extension !== 2) {
|
|
254
|
+
throw new RangeError('extension must be 1 or 2');
|
|
255
|
+
}
|
|
256
|
+
return { limits: resolveExpressionLimits(options), extension, active: new WeakSet(), nodes: 0 };
|
|
248
257
|
}
|
|
249
258
|
export function validateProtocolExpression(input, options = {}) {
|
|
250
259
|
return validateExpression(input, '$', 1, newState(options));
|
|
@@ -256,30 +265,38 @@ export function validateProtocolSemanticQuery(input, options = {}) {
|
|
|
256
265
|
try {
|
|
257
266
|
const kind = stringValue(value.kind, '$.kind');
|
|
258
267
|
const metric = kind === 'metric';
|
|
268
|
+
const v2 = state.extension === 2;
|
|
259
269
|
if (!metric && kind !== 'dataset')
|
|
260
270
|
expressionError('HQ_EXPRESSION_INVALID_QUERY', '$.kind');
|
|
261
|
-
exactFields(value, metric ? ['kind', 'dataset', 'metric'] : ['kind', 'dataset'],
|
|
262
|
-
|
|
263
|
-
: ['
|
|
271
|
+
exactFields(value, metric ? ['kind', 'dataset', 'metric'] : ['kind', 'dataset'], [
|
|
272
|
+
'dimensions',
|
|
273
|
+
...(metric ? [] : ['measures']),
|
|
274
|
+
'filters',
|
|
275
|
+
...(v2 ? ['segments'] : []),
|
|
276
|
+
'orderBy', 'limit', 'offset', 'by', 'includeMeta',
|
|
277
|
+
], '$');
|
|
264
278
|
const result = {
|
|
265
279
|
kind,
|
|
266
280
|
dataset: identifier(value.dataset, '$.dataset', false),
|
|
267
281
|
...(metric ? { metric: identifier(value.metric, '$.metric', false) } : {}),
|
|
268
282
|
};
|
|
269
283
|
copyIdentifierArray(value, result, 'dimensions', true, state);
|
|
284
|
+
// Extension 2 admits one-hop relationship measures (`customer.count`).
|
|
270
285
|
if (!metric)
|
|
271
|
-
copyIdentifierArray(value, result, 'measures',
|
|
286
|
+
copyIdentifierArray(value, result, 'measures', v2, state);
|
|
272
287
|
if (value.filters !== undefined) {
|
|
273
288
|
const filters = arrayValue(value.filters, '$.filters', state);
|
|
274
289
|
result.filters = Object.freeze(filters.map((filter, index) => validatePredicate(filter, `$.filters[${index}]`, 1, state, 'HQ_EXPRESSION_INVALID_QUERY')));
|
|
275
290
|
}
|
|
291
|
+
if (value.segments !== undefined)
|
|
292
|
+
result.segments = validateSegments(value.segments, state);
|
|
276
293
|
if (value.orderBy !== undefined)
|
|
277
294
|
result.orderBy = validateOrderBy(value.orderBy, state);
|
|
278
295
|
copyInteger(value, result, 'limit', 0);
|
|
279
296
|
copyInteger(value, result, 'offset', 0);
|
|
280
297
|
if (value.by !== undefined) {
|
|
281
298
|
const grain = stringValue(value.by, '$.by');
|
|
282
|
-
if (!
|
|
299
|
+
if (!(v2 ? GRAINS_V2 : GRAINS_V1).has(grain))
|
|
283
300
|
expressionError('HQ_EXPRESSION_INVALID_QUERY', '$.by');
|
|
284
301
|
result.by = grain;
|
|
285
302
|
}
|
|
@@ -336,3 +353,15 @@ function validateOrderBy(input, state) {
|
|
|
336
353
|
return freezeRecord({ field: identifier(value.field, `${path}.field`), direction });
|
|
337
354
|
}));
|
|
338
355
|
}
|
|
356
|
+
function validateSegments(input, state) {
|
|
357
|
+
const values = arrayValue(input, '$.segments', state);
|
|
358
|
+
const seen = new Set();
|
|
359
|
+
return Object.freeze(values.map((item, index) => {
|
|
360
|
+
const path = `$.segments[${index}]`;
|
|
361
|
+
const name = identifier(item, path, false);
|
|
362
|
+
if (seen.has(name))
|
|
363
|
+
expressionError('HQ_EXPRESSION_INVALID_QUERY', path);
|
|
364
|
+
seen.add(name);
|
|
365
|
+
return name;
|
|
366
|
+
}));
|
|
367
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,23 +2,25 @@ export { DEFAULT_CANONICAL_VALUE_LIMITS, ProtocolValueError, decodeCanonicalValu
|
|
|
2
2
|
export type { ArrayTaggedValue, BytesTaggedValue, CanonicalValue, CanonicalValueLimits, CanonicalValueOptions, DateTaggedValue, DatetimeTaggedValue, DecimalTaggedValue, EnumTaggedValue, IntegerTaggedValue, MapTaggedValue, ProtocolValueErrorCode, TaggedValue, TupleTaggedValue, UuidTaggedValue, } from './values/index.js';
|
|
3
3
|
export { PROTOCOL_IDENTIFIER_LIMITS, ProtocolIdentifierError, isProtocolIdentifier, isProtocolQualifiedIdentifier, joinProtocolQualifiedIdentifier, parseProtocolIdentifier, parseProtocolQualifiedIdentifier, splitProtocolQualifiedIdentifier, } from './identifiers/index.js';
|
|
4
4
|
export { PROTOCOL_CACHE_KEY_LIMITS, ProtocolCacheKeyError, deriveProtocolCacheKey, deriveProtocolCacheNamespaceToken, } from './cache-keys/index.js';
|
|
5
|
+
export { ProtocolCachePreimageError, buildProtocolCachePreimage, deriveProtocolTenantFingerprint, } from './cache-preimages/index.js';
|
|
5
6
|
export { DEFAULT_PROTOCOL_EXPRESSION_LIMITS, ProtocolExpressionError, validateProtocolExpression, validateProtocolSemanticQuery, } from './expressions/index.js';
|
|
6
7
|
export { DEFAULT_PROTOCOL_SCHEMA_LIMITS, DEFAULT_PROTOCOL_SCHEMA_VALUE_LIMITS, ProtocolSchemaError, ProtocolSchemaValueError, applyProtocolSchemaValue, createProtocolSchemaValueParser, resolveProtocolSchemaValueLimits, validateProtocolSchema, } from './schemas/index.js';
|
|
7
8
|
export type { ProtocolSchema, ProtocolSchemaErrorCode, ProtocolSchemaLimits, ProtocolSchemaOptions, ProtocolSchemaValueLimits, ProtocolSchemaValueOptions, ProtocolSchemaValueParser, } from './schemas/index.js';
|
|
8
|
-
export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolTimeGrain, } from './expressions/index.js';
|
|
9
|
+
export type { ProtocolAggregation, ProtocolBinaryOperator, ProtocolComparisonOperator, ProtocolDatasetQuery, ProtocolExpression, ProtocolExpressionErrorCode, ProtocolExpressionExtension, ProtocolExpressionLimits, ProtocolExpressionOptions, ProtocolFunctionName, ProtocolMetricQuery, ProtocolOrderBy, ProtocolSemanticQuery, ProtocolQueryTimeGrain, ProtocolTimeGrain, } from './expressions/index.js';
|
|
9
10
|
export type { DeriveProtocolCacheKeyOptions, ProtocolCacheKeyErrorCode, ProtocolCacheKeyNamespace, } from './cache-keys/index.js';
|
|
11
|
+
export type { BuildProtocolCachePreimageOptions, ProtocolCachePreimageErrorCode, ProtocolCacheTenantScope, } from './cache-preimages/index.js';
|
|
10
12
|
export type { ProtocolIdentifier, ProtocolIdentifierErrorCode, ProtocolQualifiedIdentifier, } from './identifiers/index.js';
|
|
11
13
|
export { DEFAULT_PROTOCOL_QUERY_IMPLEMENTATION_LIMITS, ProtocolQueryImplementationError, validateProtocolQueryImplementation, validateProtocolSqlExpression, } from './query-implementations/index.js';
|
|
12
14
|
export { DEFAULT_PROTOCOL_QUERY_EVENT_LIMITS, ProtocolQueryDiagnosticsError, ProtocolQueryEventError, validateProtocolQueryDiagnostics, validateProtocolQueryEvent, } from './events/index.js';
|
|
13
15
|
export type { ProtocolQueryDiagnostics, ProtocolQueryDiagnosticsErrorCode, ProtocolQueryErrorCategory, ProtocolQueryEvent, ProtocolQueryEventErrorCode, ProtocolQueryEventLimits, ProtocolQueryEventOptions, ProtocolQueryEventOutcome, ProtocolQueryEventTarget, ProtocolQueryOperation, ProtocolQueryTerminalReason, } from './events/index.js';
|
|
14
|
-
export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS, ProtocolSemanticInvocationError, validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, } from './invocations/index.js';
|
|
15
|
-
export type { ProtocolSemanticInvocation, ProtocolSemanticInvocationBudget, ProtocolSemanticInvocationErrorCode, ProtocolSemanticInvocationFailure, ProtocolSemanticInvocationFailureCategory, ProtocolSemanticInvocationLimits, ProtocolSemanticInvocationMeta, ProtocolSemanticInvocationOptions, ProtocolSemanticInvocationPagination, ProtocolSemanticInvocationResult, ProtocolSemanticInvocationRow, ProtocolSemanticInvocationTarget, ProtocolSemanticInvocationValue, } from './invocations/index.js';
|
|
16
|
+
export { DEFAULT_PROTOCOL_SEMANTIC_INVOCATION_LIMITS, ProtocolSemanticInvocationError, validateProtocolSemanticInvocation, validateProtocolSemanticInvocationFailure, validateProtocolSemanticInvocationResult, validateProtocolSemanticInvocationV2, } from './invocations/index.js';
|
|
17
|
+
export type { ProtocolSemanticInvocation, ProtocolSemanticInvocationV2, ProtocolSemanticInvocationBudget, ProtocolSemanticInvocationErrorCode, ProtocolSemanticInvocationFailure, ProtocolSemanticInvocationFailureCategory, ProtocolSemanticInvocationLimits, ProtocolSemanticInvocationMeta, ProtocolSemanticInvocationOptions, ProtocolSemanticInvocationPagination, ProtocolSemanticInvocationResult, ProtocolSemanticInvocationRow, ProtocolSemanticInvocationTarget, ProtocolSemanticInvocationValue, } from './invocations/index.js';
|
|
16
18
|
export { DEFAULT_PROTOCOL_DEPLOYMENT_BUNDLE_LIMITS, PROTOCOL_DEPLOYMENT_BUNDLE_IDENTITY_DOMAIN, ProtocolDeploymentBundleError, encodeProtocolDeploymentBundleManifest, encodeProtocolDeploymentBundleManifestToString, hashProtocolDeploymentBundleManifest, prepareProtocolDeploymentBundleManifest, validateProtocolDeploymentBundleManifest, } from './bundles/index.js';
|
|
17
19
|
export { DEFAULT_PROTOCOL_DEPLOYMENT_RELEASE_LIMITS, PROTOCOL_DEPLOYMENT_RELEASE_IDENTITY_DOMAIN, ProtocolDeploymentReleaseError, encodeProtocolDeploymentReleaseEnvelope, encodeProtocolDeploymentReleaseEnvelopeToString, hashProtocolDeploymentReleaseEnvelope, prepareProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseEnvelope, validateProtocolDeploymentReleaseTarget, } from './releases/index.js';
|
|
18
20
|
export type { PreparedProtocolDeploymentReleaseEnvelope, ProtocolDeploymentReleaseEnvelope, ProtocolDeploymentReleaseErrorCode, ProtocolDeploymentReleaseLimits, ProtocolDeploymentReleaseOptions, ProtocolDeploymentReleaseTarget, } from './releases/index.js';
|
|
19
21
|
export type { PreparedProtocolDeploymentBundleManifest, ProtocolDeploymentBundleArtifact, ProtocolDeploymentBundleDeployment, ProtocolDeploymentBundleErrorCode, ProtocolDeploymentBundleFile, ProtocolDeploymentBundleLimits, ProtocolDeploymentBundleManifest, ProtocolDeploymentBundleOptions, } from './bundles/index.js';
|
|
20
|
-
export { DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS, PROTOCOL_DEPLOYMENT_IDENTITY_DOMAIN, ProtocolDeploymentError, encodeProtocolDeploymentContract, encodeProtocolDeploymentContractToString, hashProtocolDeploymentContract, prepareProtocolDeploymentContract, validateProtocolDatasetContract, validateProtocolDeploymentContract, } from './deployments/index.js';
|
|
21
|
-
export type { ProtocolDatasetDerivedMeasure, ProtocolDeploymentDataset, ProtocolDeploymentMeasure, PreparedProtocolDeploymentContract, ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDefaults, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetFreshness, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolSemanticMetadata, ProtocolSemanticSensitivity, ProtocolDeploymentContract, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolMetricDerivation, ProtocolMetricInput, } from './deployments/index.js';
|
|
22
|
+
export { DEFAULT_PROTOCOL_DEPLOYMENT_LIMITS, PROTOCOL_DEPLOYMENT_IDENTITY_DOMAIN, PROTOCOL_DEPLOYMENT_V3_IDENTITY_DOMAIN, ProtocolDeploymentError, encodeProtocolDeploymentContract, encodeProtocolDeploymentContractToString, hashProtocolDeploymentContract, prepareProtocolDeploymentContract, prepareProtocolDeploymentContractV3, validateProtocolDatasetContract, validateProtocolDeploymentContract, validateProtocolDeploymentContractV3, } from './deployments/index.js';
|
|
23
|
+
export type { ProtocolDatasetDerivedMeasure, ProtocolDeploymentDataset, ProtocolDeploymentMeasure, PreparedProtocolDeploymentContract, PreparedProtocolDeploymentContractV3, ProtocolAccessPolicy, ProtocolDatasetContract, ProtocolDatasetDefaults, ProtocolDatasetDimension, ProtocolDatasetFieldSource, ProtocolDatasetFieldType, ProtocolDatasetFilter, ProtocolDatasetFreshness, ProtocolDatasetLimits, ProtocolDatasetMeasure, ProtocolDatasetMetric, ProtocolDatasetRelationship, ProtocolDatasetTenantPolicy, ProtocolSemanticMetadata, ProtocolSemanticSensitivity, ProtocolDeploymentContract, ProtocolDeploymentContractV3, ProtocolDeploymentDatasetV3, ProtocolDeploymentMeasureV3, ProtocolDatasetDerivedMeasureV3, ProtocolDatasetMeasureV3, ProtocolDatasetSegment, ProtocolDatasetShiftMeasure, ProtocolDatasetWindowMeasure, ProtocolTimeInterval, ProtocolDeploymentErrorCode, ProtocolDeploymentLimits, ProtocolDeploymentOptions, ProtocolEndpointPolicy, ProtocolEndpointTenantPolicy, ProtocolMetricDerivation, ProtocolMetricInput, } from './deployments/index.js';
|
|
22
24
|
export type { ProtocolQueryImplementation, ProtocolQueryImplementationErrorCode, ProtocolQueryImplementationLimits, ProtocolQueryImplementationOptions, ProtocolSqlDialect, ProtocolSqlExpression, ProtocolSqlParameter, ProtocolSqlParameterSource, ProtocolSqlTenantPolicy, } from './query-implementations/index.js';
|
|
23
25
|
export { PROTOCOL_SEMANTIC_FAILURE_MESSAGES } from './invocations/failure-messages.js';
|
|
24
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,sBAAsB,EACtB,WAAW,EACX,gBAAgB,EAChB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAC7B,+BAA+B,EAC/B,uBAAuB,EACvB,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,iCAAiC,GAClC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kCAAkC,EAClC,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,8BAA8B,EAC9B,oCAAoC,EACpC,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,+BAA+B,EAC/B,gCAAgC,EAChC,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,kBAAkB,EAClB,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,4CAA4C,EAC5C,gCAAgC,EAChC,mCAAmC,EACnC,6BAA6B,GAC9B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,mCAAmC,EACnC,6BAA6B,EAC7B,uBAAuB,EACvB,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,wBAAwB,EACxB,iCAAiC,EACjC,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,2CAA2C,EAC3C,+BAA+B,EAC/B,kCAAkC,EAClC,yCAAyC,EACzC,wCAAwC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|