@malloydata/malloy 0.0.390 → 0.0.392
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/api/asynchronous.js +0 -3
- package/dist/api/foundation/compile.d.ts +1 -1
- package/dist/api/foundation/config.d.ts +80 -8
- package/dist/api/foundation/config.js +151 -69
- package/dist/api/foundation/config_compile.js +27 -35
- package/dist/api/foundation/config_discover.js +5 -9
- package/dist/api/foundation/config_overlays.d.ts +6 -0
- package/dist/api/foundation/config_overlays.js +12 -0
- package/dist/api/foundation/config_resolve.d.ts +4 -1
- package/dist/api/foundation/config_resolve.js +64 -4
- package/dist/api/foundation/core.d.ts +75 -2
- package/dist/api/foundation/core.js +104 -6
- package/dist/api/foundation/index.d.ts +2 -0
- package/dist/api/foundation/readers.js +1 -1
- package/dist/api/foundation/runtime.d.ts +68 -2
- package/dist/api/foundation/runtime.js +212 -10
- package/dist/api/foundation/types.d.ts +2 -1
- package/dist/index.d.ts +3 -1
- package/dist/lang/ast/ast-utils.js +0 -1
- package/dist/lang/ast/expressions/expr-aggregate-function.d.ts +1 -1
- package/dist/lang/ast/expressions/expr-aggregate-function.js +9 -8
- package/dist/lang/ast/expressions/expr-coalesce.d.ts +1 -1
- package/dist/lang/ast/expressions/expr-coalesce.js +2 -3
- package/dist/lang/ast/expressions/expr-count-distinct.js +1 -1
- package/dist/lang/ast/expressions/expr-count.js +6 -4
- package/dist/lang/ast/expressions/expr-filter-expr.js +0 -1
- package/dist/lang/ast/expressions/expr-func.js +9 -4
- package/dist/lang/ast/expressions/expr-given.d.ts +18 -0
- package/dist/lang/ast/expressions/expr-given.js +69 -0
- package/dist/lang/ast/expressions/expr-granular-time.d.ts +1 -1
- package/dist/lang/ast/expressions/expr-id-reference.js +3 -2
- package/dist/lang/ast/expressions/expr-now.js +0 -1
- package/dist/lang/ast/expressions/expr-props.d.ts +132 -132
- package/dist/lang/ast/expressions/expr-props.js +2 -2
- package/dist/lang/ast/expressions/expr-ungroup.d.ts +1 -1
- package/dist/lang/ast/expressions/expr-ungroup.js +4 -4
- package/dist/lang/ast/expressions/for-range.d.ts +1 -1
- package/dist/lang/ast/expressions/function-ordering.d.ts +1 -1
- package/dist/lang/ast/expressions/function-ordering.js +2 -2
- package/dist/lang/ast/expressions/time-literal.d.ts +3 -3
- package/dist/lang/ast/field-space/include-utils.js +2 -2
- package/dist/lang/ast/field-space/index-field-space.js +18 -23
- package/dist/lang/ast/field-space/passthrough-space.d.ts +1 -1
- package/dist/lang/ast/field-space/query-spaces.d.ts +6 -2
- package/dist/lang/ast/field-space/query-spaces.js +29 -19
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/field-space/rename-space-field.d.ts +1 -1
- package/dist/lang/ast/field-space/rename-space-field.js +2 -2
- package/dist/lang/ast/field-space/struct-space-field-base.js +2 -3
- package/dist/lang/ast/index.d.ts +2 -0
- package/dist/lang/ast/index.js +2 -0
- package/dist/lang/ast/query-builders/index-builder.d.ts +1 -1
- package/dist/lang/ast/query-builders/index-builder.js +4 -3
- package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -2
- package/dist/lang/ast/query-builders/reduce-builder.js +4 -5
- package/dist/lang/ast/query-elements/query-arrow.js +3 -2
- package/dist/lang/ast/query-elements/query-base.d.ts +1 -1
- package/dist/lang/ast/query-elements/query-base.js +1 -1
- package/dist/lang/ast/query-elements/query-refine.js +3 -1
- package/dist/lang/ast/query-items/field-declaration.js +2 -2
- package/dist/lang/ast/query-properties/drill.js +6 -6
- package/dist/lang/ast/query-properties/filters.js +2 -2
- package/dist/lang/ast/query-properties/nest.js +3 -3
- package/dist/lang/ast/source-elements/composite-source.js +5 -3
- package/dist/lang/ast/source-elements/named-source.js +4 -0
- package/dist/lang/ast/source-elements/sql-source.js +2 -2
- package/dist/lang/ast/source-elements/table-source.js +3 -1
- package/dist/lang/ast/source-properties/join.js +4 -4
- package/dist/lang/ast/source-query-elements/sq-reference.js +2 -1
- package/dist/lang/ast/statements/define-given.d.ts +29 -0
- package/dist/lang/ast/statements/define-given.js +163 -0
- package/dist/lang/ast/statements/import-statement.js +72 -9
- package/dist/lang/ast/typedesc-utils.d.ts +3 -1
- package/dist/lang/ast/typedesc-utils.js +4 -47
- package/dist/lang/ast/types/expr-value.js +2 -3
- package/dist/lang/ast/types/expression-def.d.ts +2 -2
- package/dist/lang/ast/types/expression-def.js +2 -2
- package/dist/lang/ast/types/malloy-element.d.ts +5 -15
- package/dist/lang/ast/types/malloy-element.js +113 -1
- package/dist/lang/ast/types/space-field.js +7 -9
- package/dist/lang/ast/view-elements/reference-view.js +6 -5
- package/dist/lang/ast/view-elements/refine-utils.js +1 -1
- package/dist/lang/composite-source-utils.d.ts +30 -15
- package/dist/lang/composite-source-utils.js +234 -64
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +171 -169
- package/dist/lang/lib/Malloy/MalloyLexer.js +1194 -1178
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +408 -334
- package/dist/lang/lib/Malloy/MalloyParser.js +3062 -2561
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +68 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +43 -0
- package/dist/lang/malloy-to-ast.d.ts +13 -1
- package/dist/lang/malloy-to-ast.js +90 -11
- package/dist/lang/parse-log.d.ts +8 -0
- package/dist/lang/prettify/filter-type.d.ts +3 -0
- package/dist/lang/prettify/filter-type.js +38 -0
- package/dist/lang/prettify/formatter.js +6 -0
- package/dist/lang/prettify/inline-renderer.js +20 -0
- package/dist/lang/prettify/rules.d.ts +1 -1
- package/dist/lang/prettify/rules.js +1 -0
- package/dist/lang/prettify/sections.js +2 -0
- package/dist/lang/prettify/tokens.js +2 -0
- package/dist/lang/test/expr-to-str.js +2 -0
- package/dist/lang/test/parse-expects.d.ts +1 -0
- package/dist/lang/test/parse-expects.js +27 -10
- package/dist/model/constant_expression_compiler.js +1 -0
- package/dist/model/expression_compiler.d.ts +2 -1
- package/dist/model/expression_compiler.js +41 -1
- package/dist/model/given_binding.d.ts +2 -0
- package/dist/model/given_binding.js +204 -0
- package/dist/model/index.d.ts +1 -1
- package/dist/model/index.js +2 -1
- package/dist/model/malloy_types.d.ts +163 -36
- package/dist/model/malloy_types.js +97 -0
- package/dist/model/query_model_contract.d.ts +2 -1
- package/dist/model/query_model_impl.d.ts +2 -1
- package/dist/model/query_model_impl.js +7 -0
- package/dist/model/query_node.d.ts +2 -1
- package/dist/model/source_def_utils.d.ts +2 -1
- package/dist/model/source_def_utils.js +4 -0
- package/dist/model/utils.d.ts +14 -1
- package/dist/model/utils.js +41 -0
- package/dist/to_stable.js +1 -1
- package/dist/util/closest_match.d.ts +9 -0
- package/dist/util/closest_match.js +47 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -36,25 +36,23 @@ class SpaceField extends space_entry_1.SpaceEntry {
|
|
|
36
36
|
...def,
|
|
37
37
|
expressionType,
|
|
38
38
|
evalSpace: 'input',
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
// field
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
: []),
|
|
39
|
+
// Use the composite field usage in the def if it exists, otherwise, if
|
|
40
|
+
// the field has an e which is a composite field, then the composite
|
|
41
|
+
// field usage should be just the name of the field.
|
|
42
|
+
refSummary: (_a = def.refSummary) !== null && _a !== void 0 ? _a : (((_b = def.e) === null || _b === void 0 ? void 0 : _b.node) === 'compositeField'
|
|
43
|
+
? { fieldUsage: [{ path: [def.name], at: def.location }] }
|
|
44
|
+
: undefined),
|
|
46
45
|
};
|
|
47
46
|
return ref;
|
|
48
47
|
}
|
|
49
48
|
turtleTypeFromTurtleDef(def) {
|
|
50
|
-
var _a;
|
|
51
49
|
const turtleTypeDef = {
|
|
52
50
|
type: 'turtle',
|
|
53
51
|
pipeline: def.pipeline,
|
|
54
52
|
};
|
|
55
53
|
return {
|
|
56
54
|
...turtleTypeDef,
|
|
57
|
-
|
|
55
|
+
refSummary: def.refSummary,
|
|
58
56
|
// TODO these are sorta weird for a turtle...
|
|
59
57
|
expressionType: 'scalar',
|
|
60
58
|
evalSpace: 'constant',
|
|
@@ -83,9 +83,11 @@ class ReferenceView extends view_1.View {
|
|
|
83
83
|
const newSegment = {
|
|
84
84
|
type: 'reduce',
|
|
85
85
|
queryFields: [this.reference.refToField],
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
refSummary: (0, composite_source_utils_1.mergeRefSummaries)(fieldDef.refSummary, {
|
|
87
|
+
fieldUsage: [
|
|
88
|
+
{ path: this.reference.refToField.path, at: this.reference.location },
|
|
89
|
+
],
|
|
90
|
+
}),
|
|
89
91
|
outputStruct,
|
|
90
92
|
// An atomic lens results in a array segment if it is a scalar
|
|
91
93
|
isRepeated: (0, malloy_types_1.expressionIsScalar)(fieldDef.expressionType),
|
|
@@ -136,7 +138,6 @@ class ReferenceView extends view_1.View {
|
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
getRefinement(inputFS) {
|
|
139
|
-
var _a;
|
|
140
141
|
const { pipeline, error } = this._pipelineComp(inputFS, {
|
|
141
142
|
forRefinement: true,
|
|
142
143
|
});
|
|
@@ -151,7 +152,7 @@ class ReferenceView extends view_1.View {
|
|
|
151
152
|
return segment;
|
|
152
153
|
return {
|
|
153
154
|
...segment,
|
|
154
|
-
|
|
155
|
+
refSummary: (0, malloy_types_1.mapFieldUsage)(segment.refSummary, u => ({
|
|
155
156
|
...u,
|
|
156
157
|
at: this.reference.location,
|
|
157
158
|
})),
|
|
@@ -102,7 +102,7 @@ function refine(logTo, refineTo, refineFrom) {
|
|
|
102
102
|
if (missingOut.length > 0) {
|
|
103
103
|
logTo.logError('name-conflict-in-refinement', `missing output fields in refinement: ${missingOut.join(', ')}`);
|
|
104
104
|
}
|
|
105
|
-
to.
|
|
105
|
+
to.refSummary = (0, composite_source_utils_1.mergeRefSummaries)(to.refSummary, from.refSummary);
|
|
106
106
|
}
|
|
107
107
|
else if (from.type === 'index' && to.type === 'index') {
|
|
108
108
|
to.indexFields = [...from.indexFields, ...to.indexFields];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { MalloyElement } from './ast';
|
|
2
|
-
import type { FieldUsage, PipeSegment, SourceDef, RequiredGroupBy, Annotation, PartitionCompositeDesc, StructDef } from '../model/malloy_types';
|
|
2
|
+
import type { FieldUsage, FieldUsageEntry, GivenUsage, PipeSegment, RefSummary, SourceDef, RequiredGroupBy, Annotation, PartitionCompositeDesc, StructDef } from '../model/malloy_types';
|
|
3
3
|
type CompositeCouldNotFindFieldError = {
|
|
4
4
|
code: 'could_not_find_field';
|
|
5
5
|
data: {
|
|
6
|
-
field:
|
|
6
|
+
field: FieldUsageEntry;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
type CompositeError = {
|
|
@@ -31,17 +31,17 @@ type CompositeError = {
|
|
|
31
31
|
data: {
|
|
32
32
|
failures: CompositeFailure[];
|
|
33
33
|
path: string[];
|
|
34
|
-
usage: FieldUsage
|
|
34
|
+
usage: FieldUsage;
|
|
35
35
|
};
|
|
36
36
|
};
|
|
37
37
|
type CompositeIssue = {
|
|
38
38
|
type: 'join-failed';
|
|
39
39
|
failures: CompositeFailure[];
|
|
40
40
|
path: string[];
|
|
41
|
-
firstUsage:
|
|
41
|
+
firstUsage: FieldUsageEntry;
|
|
42
42
|
} | {
|
|
43
43
|
type: 'missing-field';
|
|
44
|
-
field:
|
|
44
|
+
field: FieldUsageEntry;
|
|
45
45
|
} | {
|
|
46
46
|
type: 'missing-required-group-by';
|
|
47
47
|
requiredGroupBy: RequiredGroupBy;
|
|
@@ -70,18 +70,33 @@ export declare function resolveCompositeSources(source: SourceDef, segment: Pipe
|
|
|
70
70
|
error: CompositeError;
|
|
71
71
|
sourceDef: undefined;
|
|
72
72
|
};
|
|
73
|
-
export declare function fieldUsagePaths(fieldUsage: FieldUsage
|
|
74
|
-
export declare function formatFieldUsages(fieldUsage: FieldUsage
|
|
75
|
-
export declare function isEmptyFieldUsage(fieldUsage: FieldUsage
|
|
76
|
-
export declare function fieldUsageIsPlural(fieldUsage: FieldUsage
|
|
73
|
+
export declare function fieldUsagePaths(fieldUsage: FieldUsage): string[][];
|
|
74
|
+
export declare function formatFieldUsages(fieldUsage: FieldUsage): string;
|
|
75
|
+
export declare function isEmptyFieldUsage(fieldUsage: FieldUsage): boolean;
|
|
76
|
+
export declare function fieldUsageIsPlural(fieldUsage: FieldUsage): boolean;
|
|
77
77
|
export declare function formatFieldUsage(fieldUsage: string[]): string;
|
|
78
78
|
export declare function unique<T>(values: T[]): T[];
|
|
79
|
-
export declare function mergeFieldUsage(...usages: FieldUsage[]
|
|
80
|
-
export declare function mergeFieldUsage(...usages: (FieldUsage
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
export declare function mergeFieldUsage(...usages: FieldUsage[]): FieldUsage;
|
|
80
|
+
export declare function mergeFieldUsage(...usages: (FieldUsage | undefined)[]): FieldUsage | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Concat-merge of `GivenUsage` arrays. Same shape as `mergeFieldUsage`:
|
|
83
|
+
* undefined inputs are skipped, all-empty result returns undefined,
|
|
84
|
+
* duplicates by id are kept (each carries its own `at` for diagnostics).
|
|
85
|
+
*/
|
|
86
|
+
export declare function mergeGivenUsage(...usages: (GivenUsage | undefined)[]): GivenUsage | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Combine N `RefSummary` values into one. Merges both `fieldUsage` and
|
|
89
|
+
* `givenUsage`; when more reference-tracking slots land on `RefSummary`,
|
|
90
|
+
* their merge logic lands here instead of being duplicated at every call
|
|
91
|
+
* site.
|
|
92
|
+
*/
|
|
93
|
+
export declare function mergeRefSummaries(...rss: (RefSummary | undefined)[]): RefSummary | undefined;
|
|
94
|
+
export declare function fieldUsageDifference(a: FieldUsage, b: FieldUsage): FieldUsageEntry[];
|
|
95
|
+
export declare function emptyFieldUsage(): FieldUsage;
|
|
96
|
+
export declare function joinedFieldUsage(joinPath: string[], fieldUsage: FieldUsage): FieldUsage;
|
|
97
|
+
export declare function fieldUsageJoinPaths(fieldUsage: FieldUsage): string[][];
|
|
98
|
+
export declare function computeQueryGivenUsage(pipeline: PipeSegment[]): GivenUsage;
|
|
99
|
+
export declare function givenUsageOfSource(sd: SourceDef): GivenUsage;
|
|
85
100
|
export declare function checkRequiredGroupBys(compositeResolvedSourceDef: SourceDef, segment: PipeSegment): RequiredGroupBy[];
|
|
86
101
|
export declare function pathEq(a: string[], b: string[]): boolean;
|
|
87
102
|
export declare function pathBegins(path: string[], prefix: string[]): boolean;
|
|
@@ -16,10 +16,14 @@ exports.fieldUsageIsPlural = fieldUsageIsPlural;
|
|
|
16
16
|
exports.formatFieldUsage = formatFieldUsage;
|
|
17
17
|
exports.unique = unique;
|
|
18
18
|
exports.mergeFieldUsage = mergeFieldUsage;
|
|
19
|
+
exports.mergeGivenUsage = mergeGivenUsage;
|
|
20
|
+
exports.mergeRefSummaries = mergeRefSummaries;
|
|
19
21
|
exports.fieldUsageDifference = fieldUsageDifference;
|
|
20
22
|
exports.emptyFieldUsage = emptyFieldUsage;
|
|
21
23
|
exports.joinedFieldUsage = joinedFieldUsage;
|
|
22
24
|
exports.fieldUsageJoinPaths = fieldUsageJoinPaths;
|
|
25
|
+
exports.computeQueryGivenUsage = computeQueryGivenUsage;
|
|
26
|
+
exports.givenUsageOfSource = givenUsageOfSource;
|
|
23
27
|
exports.checkRequiredGroupBys = checkRequiredGroupBys;
|
|
24
28
|
exports.pathEq = pathEq;
|
|
25
29
|
exports.pathBegins = pathBegins;
|
|
@@ -39,7 +43,7 @@ sources) {
|
|
|
39
43
|
let anyComposites = false;
|
|
40
44
|
let joinsProcessed = false;
|
|
41
45
|
const nonCompositeFields = getNonCompositeFields(source);
|
|
42
|
-
const expandedForError = onlyCompositeUsage(
|
|
46
|
+
const expandedForError = onlyCompositeUsage(expandRefUsage({ fieldUsage }, rootFields).fieldUsage, source.fields);
|
|
43
47
|
if (source.type === 'composite') {
|
|
44
48
|
let found = false;
|
|
45
49
|
anyComposites = true;
|
|
@@ -66,7 +70,7 @@ sources) {
|
|
|
66
70
|
}
|
|
67
71
|
const fieldUsageWithWheres = (_b = mergeFieldUsage(getFieldUsageFromFilterList(inputSource), fieldUsage)) !== null && _b !== void 0 ? _b : [];
|
|
68
72
|
const fieldsForLookup = [...nonCompositeFields, ...inputSource.fields];
|
|
69
|
-
const expanded =
|
|
73
|
+
const expanded = expandRefUsage({ fieldUsage: fieldUsageWithWheres }, fieldsForLookup);
|
|
70
74
|
if (expanded.missingFields.length > 0) {
|
|
71
75
|
// A lookup failed while expanding, which means this source certainly won't work
|
|
72
76
|
for (const missingField of expanded.missingFields) {
|
|
@@ -81,7 +85,7 @@ sources) {
|
|
|
81
85
|
abort();
|
|
82
86
|
continue overSources;
|
|
83
87
|
}
|
|
84
|
-
const expandedCategorized = categorizeFieldUsage(expanded.
|
|
88
|
+
const expandedCategorized = categorizeFieldUsage(expanded.fieldUsage);
|
|
85
89
|
const compositeUsageInThisSource = onlyCompositeUsage(expandedCategorized.sourceUsage, source.fields);
|
|
86
90
|
for (const usage of compositeUsageInThisSource) {
|
|
87
91
|
if (usage.path.length > 0 && !fieldNames.has(usage.path[0])) {
|
|
@@ -177,7 +181,7 @@ sources) {
|
|
|
177
181
|
}
|
|
178
182
|
else if (source.partitionComposite !== undefined) {
|
|
179
183
|
anyComposites = true;
|
|
180
|
-
const expanded =
|
|
184
|
+
const expanded = expandRefUsage({ fieldUsage }, rootFields).fieldUsage;
|
|
181
185
|
// TODO possibly abort if expanded has missing fields...
|
|
182
186
|
const expandedCategorized = categorizeFieldUsage(expanded);
|
|
183
187
|
const { partitionFilter, issues } = getPartitionCompositeFilter(source.partitionComposite, expandedCategorized.sourceUsage);
|
|
@@ -199,7 +203,7 @@ sources) {
|
|
|
199
203
|
};
|
|
200
204
|
}
|
|
201
205
|
if (!joinsProcessed) {
|
|
202
|
-
const expanded =
|
|
206
|
+
const expanded = expandRefUsage({ fieldUsage }, getJoinFields(rootFields, path));
|
|
203
207
|
if (expanded.missingFields.length > 0) {
|
|
204
208
|
return {
|
|
205
209
|
error: {
|
|
@@ -208,7 +212,7 @@ sources) {
|
|
|
208
212
|
},
|
|
209
213
|
};
|
|
210
214
|
}
|
|
211
|
-
const joinResult = processJoins(path, base, rootFields, nests, categorizeFieldUsage(expanded.
|
|
215
|
+
const joinResult = processJoins(path, base, rootFields, nests, categorizeFieldUsage(expanded.fieldUsage));
|
|
212
216
|
if (joinResult.errors.length > 0) {
|
|
213
217
|
return { error: joinResult.errors[0].error };
|
|
214
218
|
}
|
|
@@ -230,11 +234,11 @@ function onlyCompositeUsage(fieldUsage, fields) {
|
|
|
230
234
|
});
|
|
231
235
|
}
|
|
232
236
|
function getExpandedSegment(segment, inputSource) {
|
|
233
|
-
var _a;
|
|
237
|
+
var _a, _b;
|
|
234
238
|
if (segment.type === 'raw')
|
|
235
239
|
return segment;
|
|
236
240
|
const sourceExtensions = (0, malloy_types_1.isQuerySegment)(segment)
|
|
237
|
-
? (_a = segment.extendSource) !== null && _a !== void 0 ? _a : []
|
|
241
|
+
? ((_a = segment.extendSource) !== null && _a !== void 0 ? _a : [])
|
|
238
242
|
: [];
|
|
239
243
|
const fields = mergeFields(inputSource.fields, sourceExtensions);
|
|
240
244
|
const collectedUngroupings = [];
|
|
@@ -277,13 +281,30 @@ function getExpandedSegment(segment, inputSource) {
|
|
|
277
281
|
});
|
|
278
282
|
updatedSegment = { ...segment, queryFields: updatedQueryFields };
|
|
279
283
|
}
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
// Seed for the walker:
|
|
285
|
+
// - segment.refSummary: everything the segment names directly.
|
|
286
|
+
// - getFieldUsageFromFilterList(inputSource): field paths in the input
|
|
287
|
+
// source's `where:` clauses, so the walker can expand them through joins.
|
|
288
|
+
// - givenUsageOfSource(inputSource): every given the input source needs,
|
|
289
|
+
// including any hiding inside an embedded Query / SQL segments /
|
|
290
|
+
// composite branches.
|
|
291
|
+
// Plus segment.alwaysJoins for the walker to unconditionally activate
|
|
292
|
+
// (segment-level direct `join_one:` etc., where activation isn't driven
|
|
293
|
+
// by any field reference).
|
|
294
|
+
const seed = mergeRefSummaries(segment.refSummary, {
|
|
295
|
+
fieldUsage: getFieldUsageFromFilterList(inputSource),
|
|
296
|
+
givenUsage: givenUsageOfSource(inputSource),
|
|
297
|
+
});
|
|
298
|
+
const alwaysJoinNames = (0, malloy_types_1.isQuerySegment)(segment) || (0, malloy_types_1.isIndexSegment)(segment)
|
|
299
|
+
? ((_b = segment.alwaysJoins) !== null && _b !== void 0 ? _b : [])
|
|
300
|
+
: [];
|
|
301
|
+
const expanded = expandRefUsage(seed, fields, alwaysJoinNames);
|
|
282
302
|
// Merge ungroupings from direct collection and field expansion
|
|
283
303
|
const allUngroupings = [...collectedUngroupings, ...expanded.ungroupings];
|
|
284
304
|
return {
|
|
285
305
|
...updatedSegment,
|
|
286
|
-
expandedFieldUsage: expanded.
|
|
306
|
+
expandedFieldUsage: expanded.fieldUsage,
|
|
307
|
+
expandedGivenUsage: expanded.givenUsage,
|
|
287
308
|
activeJoins: expanded.activeJoins,
|
|
288
309
|
expandedUngroupings: allUngroupings,
|
|
289
310
|
};
|
|
@@ -326,21 +347,37 @@ function findActiveJoins(dependencies) {
|
|
|
326
347
|
return sorted;
|
|
327
348
|
}
|
|
328
349
|
/**
|
|
329
|
-
* Given a
|
|
330
|
-
*
|
|
350
|
+
* Given a seed `RefSummary` (field usage + given usage referenced directly by
|
|
351
|
+
* the caller), expand to include everything reachable through the join graph:
|
|
352
|
+
*
|
|
353
|
+
* - field usage: the seed fields plus any field usage on `on:` and `where:`
|
|
354
|
+
* clauses of joins activated to reach them, recursively.
|
|
355
|
+
* - given usage: the seed given usage plus the given usage of every
|
|
356
|
+
* atomic-field def the walker dequeues and every join it activates.
|
|
331
357
|
*
|
|
332
358
|
* @returns An object containing:
|
|
333
|
-
* - `
|
|
359
|
+
* - `fieldUsage`: The expanded field usage, including usages from necessary joins
|
|
360
|
+
* - `givenUsage`: The expanded given usage, seed plus every traversed def/join
|
|
334
361
|
* - `missingFields`: References to fields which could not be resolved
|
|
335
362
|
* - `activeJoins`: Topologically sorted list of joins needed to resolve these uses
|
|
336
363
|
*/
|
|
337
|
-
function
|
|
338
|
-
var _a;
|
|
364
|
+
function expandRefUsage(seed, fields, alwaysJoinNames = []) {
|
|
339
365
|
const seen = {};
|
|
340
366
|
const missingFields = [];
|
|
341
367
|
const toProcess = [];
|
|
342
368
|
const activeJoinGraph = {};
|
|
343
369
|
const ungroupings = [];
|
|
370
|
+
const givenUsage = [];
|
|
371
|
+
const seenGivens = new Set();
|
|
372
|
+
function addGivens(items) {
|
|
373
|
+
for (const g of items) {
|
|
374
|
+
if (seenGivens.has(g.id))
|
|
375
|
+
continue;
|
|
376
|
+
seenGivens.add(g.id);
|
|
377
|
+
givenUsage.push(g);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
addGivens((0, malloy_types_1.givenUsageFrom)(seed));
|
|
344
381
|
function mergeIntoSeen(usage) {
|
|
345
382
|
var _a;
|
|
346
383
|
const key = (0, utils_2.pathToKey)('field', usage.path);
|
|
@@ -361,12 +398,49 @@ function expandFieldUsage(fieldUsage, fields) {
|
|
|
361
398
|
return false;
|
|
362
399
|
}
|
|
363
400
|
// Initialize: mark original inputs and add them to processing queue
|
|
364
|
-
for (const usage of
|
|
401
|
+
for (const usage of (0, malloy_types_1.fieldUsageFrom)(seed)) {
|
|
365
402
|
mergeIntoSeen(usage);
|
|
366
403
|
toProcess.push(usage);
|
|
367
404
|
}
|
|
368
405
|
// Process the expanding queue
|
|
369
406
|
const fieldNameSpace = buildNamespace(fields);
|
|
407
|
+
// Mark `joinDef` as activated and harvest everything it brings in: its
|
|
408
|
+
// on-clause field usage onto the queue, and its on-clause + filterList
|
|
409
|
+
// given usage into the accumulator. Used both in-loop (joins reached
|
|
410
|
+
// via reference paths) and upfront (always-on segment-level joins).
|
|
411
|
+
function activateJoin(joinDef, joinPath) {
|
|
412
|
+
const joinKey = (0, utils_2.pathToKey)('join', joinPath);
|
|
413
|
+
const thisDep = getJoin(activeJoinGraph, joinKey, joinPath);
|
|
414
|
+
if (!(0, malloy_types_1.isJoined)(joinDef) || thisDep.checked)
|
|
415
|
+
return;
|
|
416
|
+
thisDep.checked = true;
|
|
417
|
+
const joinFieldUsage = getJoinFieldUsage(joinDef, joinPath);
|
|
418
|
+
addGivens(getJoinGivenUsage(joinDef));
|
|
419
|
+
for (const usage of joinFieldUsage) {
|
|
420
|
+
const key = (0, utils_2.pathToKey)('field', usage.path);
|
|
421
|
+
if (!seen[key]) {
|
|
422
|
+
seen[key] = usage;
|
|
423
|
+
toProcess.push(usage);
|
|
424
|
+
}
|
|
425
|
+
const isInternalReference = usage.path.length === joinPath.length + 1 &&
|
|
426
|
+
pathBegins(usage.path, joinPath);
|
|
427
|
+
if (!isInternalReference && usage.path.length > 1) {
|
|
428
|
+
const dependencyPath = usage.path.slice(0, -1);
|
|
429
|
+
const dependencyKey = (0, utils_2.pathToKey)('join', dependencyPath);
|
|
430
|
+
getJoin(activeJoinGraph, dependencyKey, dependencyPath);
|
|
431
|
+
thisDep.dependsOn.add(dependencyKey);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// Always-on joins (segment-level direct `join_one:` etc.) are activated
|
|
436
|
+
// unconditionally — no field reference is needed. Compiler-side activation
|
|
437
|
+
// happens via `addAlwaysJoins` in query_query.ts; here we ensure their
|
|
438
|
+
// on-clause field/given usage flows into the expanded summaries.
|
|
439
|
+
for (const joinName of alwaysJoinNames) {
|
|
440
|
+
const joinDef = inNamespace([joinName], fieldNameSpace);
|
|
441
|
+
if (joinDef)
|
|
442
|
+
activateJoin(joinDef, [joinName]);
|
|
443
|
+
}
|
|
370
444
|
for (let i = 0; i < toProcess.length; i++) {
|
|
371
445
|
const reference = toProcess[i];
|
|
372
446
|
if (reference.path.length === 0)
|
|
@@ -377,7 +451,8 @@ function expandFieldUsage(fieldUsage, fields) {
|
|
|
377
451
|
continue;
|
|
378
452
|
}
|
|
379
453
|
if ((0, malloy_types_1.isAtomic)(def)) {
|
|
380
|
-
const fieldUsage = (
|
|
454
|
+
const fieldUsage = (0, malloy_types_1.fieldUsageFrom)(def.refSummary);
|
|
455
|
+
addGivens((0, malloy_types_1.givenUsageFrom)(def.refSummary));
|
|
381
456
|
// Add the atomic field's dependencies to the queue
|
|
382
457
|
const refPath = reference.path.slice(0, -1);
|
|
383
458
|
for (const usage of joinedFieldUsage(refPath, fieldUsage)) {
|
|
@@ -395,33 +470,12 @@ function expandFieldUsage(fieldUsage, fields) {
|
|
|
395
470
|
const joinDef = inNamespace(joinPath, fieldNameSpace);
|
|
396
471
|
if (!joinDef)
|
|
397
472
|
break;
|
|
398
|
-
|
|
399
|
-
const thisDep = getJoin(activeJoinGraph, joinKey, joinPath);
|
|
400
|
-
if ((0, malloy_types_1.isJoined)(joinDef) && !thisDep.checked) {
|
|
401
|
-
thisDep.checked = true;
|
|
402
|
-
const joinFieldUsage = getJoinFieldUsage(joinDef, joinPath);
|
|
403
|
-
// Add join's field dependencies to the queue
|
|
404
|
-
for (const usage of joinFieldUsage) {
|
|
405
|
-
const key = (0, utils_2.pathToKey)('field', usage.path);
|
|
406
|
-
if (!seen[key]) {
|
|
407
|
-
seen[key] = usage;
|
|
408
|
-
toProcess.push(usage);
|
|
409
|
-
}
|
|
410
|
-
// Track join-to-join dependencies
|
|
411
|
-
const isInternalReference = usage.path.length === joinPath.length + 1 &&
|
|
412
|
-
pathBegins(usage.path, joinPath);
|
|
413
|
-
if (!isInternalReference && usage.path.length > 1) {
|
|
414
|
-
const dependencyPath = usage.path.slice(0, -1);
|
|
415
|
-
const dependencyKey = (0, utils_2.pathToKey)('join', dependencyPath);
|
|
416
|
-
getJoin(activeJoinGraph, dependencyKey, dependencyPath);
|
|
417
|
-
thisDep.dependsOn.add(dependencyKey);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
473
|
+
activateJoin(joinDef, joinPath);
|
|
421
474
|
}
|
|
422
475
|
}
|
|
423
476
|
return {
|
|
424
|
-
|
|
477
|
+
fieldUsage: Object.values(seen),
|
|
478
|
+
givenUsage,
|
|
425
479
|
missingFields,
|
|
426
480
|
activeJoins: findActiveJoins(activeJoinGraph),
|
|
427
481
|
ungroupings,
|
|
@@ -662,20 +716,19 @@ function processJoins(path, base, rootFields, nests, categorizedFieldUsage) {
|
|
|
662
716
|
return { anyComposites, errors };
|
|
663
717
|
}
|
|
664
718
|
function segmentFieldUsage(segment) {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
: undefined)) !== null && _a !== void 0 ? _a : emptyFieldUsage());
|
|
719
|
+
return (0, malloy_types_1.isQuerySegment)(segment) || (0, malloy_types_1.isIndexSegment)(segment)
|
|
720
|
+
? (0, malloy_types_1.fieldUsageFrom)(segment.refSummary)
|
|
721
|
+
: emptyFieldUsage();
|
|
669
722
|
}
|
|
670
723
|
function getFieldUsageFromFilterList(source) {
|
|
671
724
|
var _a;
|
|
672
|
-
return ((_a = source.filterList) !== null && _a !== void 0 ? _a : []).flatMap(filter =>
|
|
725
|
+
return ((_a = source.filterList) !== null && _a !== void 0 ? _a : []).flatMap(filter => (0, malloy_types_1.fieldUsageFrom)(filter.refSummary));
|
|
673
726
|
}
|
|
674
727
|
function resolveCompositeSources(source, segment) {
|
|
675
728
|
var _a, _b;
|
|
676
729
|
const fieldUsage = segmentFieldUsage(segment);
|
|
677
730
|
const sourceExtensions = (0, malloy_types_1.isQuerySegment)(segment)
|
|
678
|
-
? (_a = segment.extendSource) !== null && _a !== void 0 ? _a : []
|
|
731
|
+
? ((_a = segment.extendSource) !== null && _a !== void 0 ? _a : [])
|
|
679
732
|
: [];
|
|
680
733
|
const nestLevels = extractNestLevels(segment);
|
|
681
734
|
const fields = mergeFields(source.fields, sourceExtensions);
|
|
@@ -758,6 +811,34 @@ function mergeFieldUsage(...usages) {
|
|
|
758
811
|
return undefined;
|
|
759
812
|
return usage;
|
|
760
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* Concat-merge of `GivenUsage` arrays. Same shape as `mergeFieldUsage`:
|
|
816
|
+
* undefined inputs are skipped, all-empty result returns undefined,
|
|
817
|
+
* duplicates by id are kept (each carries its own `at` for diagnostics).
|
|
818
|
+
*/
|
|
819
|
+
function mergeGivenUsage(...usages) {
|
|
820
|
+
const usage = [];
|
|
821
|
+
for (const oneUsage of usages) {
|
|
822
|
+
if (oneUsage === undefined)
|
|
823
|
+
continue;
|
|
824
|
+
usage.push(...oneUsage);
|
|
825
|
+
}
|
|
826
|
+
if (usage.length === 0)
|
|
827
|
+
return undefined;
|
|
828
|
+
return usage;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Combine N `RefSummary` values into one. Merges both `fieldUsage` and
|
|
832
|
+
* `givenUsage`; when more reference-tracking slots land on `RefSummary`,
|
|
833
|
+
* their merge logic lands here instead of being duplicated at every call
|
|
834
|
+
* site.
|
|
835
|
+
*/
|
|
836
|
+
function mergeRefSummaries(...rss) {
|
|
837
|
+
return (0, malloy_types_1.mkRefSummary)({
|
|
838
|
+
fieldUsage: mergeFieldUsage(...rss.map(rs => (0, malloy_types_1.fieldUsageFrom)(rs))),
|
|
839
|
+
givenUsage: mergeGivenUsage(...rss.map(rs => (0, malloy_types_1.givenUsageFrom)(rs))),
|
|
840
|
+
});
|
|
841
|
+
}
|
|
761
842
|
function fieldUsageDifference(a, b) {
|
|
762
843
|
return a.filter(u1 => !b.some(u2 => pathEq(u1.path, u2.path)));
|
|
763
844
|
}
|
|
@@ -839,7 +920,7 @@ function joinedUngroupings(joinPath, ungroupings) {
|
|
|
839
920
|
}));
|
|
840
921
|
}
|
|
841
922
|
function extractNestLevels(segment) {
|
|
842
|
-
var _a, _b, _c
|
|
923
|
+
var _a, _b, _c;
|
|
843
924
|
const fieldsReferencedDirectly = [];
|
|
844
925
|
const fieldsReferenced = [];
|
|
845
926
|
const nested = [];
|
|
@@ -864,8 +945,9 @@ function extractNestLevels(segment) {
|
|
|
864
945
|
// Check if the nested query has ANY unique key requirements
|
|
865
946
|
let hasNestedUniqueKeyReqs = nestedLevels.fieldsReferenced.some(usage => usage.uniqueKeyRequirement);
|
|
866
947
|
// Also check the head segment's fieldUsage directly
|
|
867
|
-
if ((0, malloy_types_1.isQuerySegment)(head)
|
|
868
|
-
const
|
|
948
|
+
if ((0, malloy_types_1.isQuerySegment)(head)) {
|
|
949
|
+
const headFieldUsages = (0, malloy_types_1.fieldUsageFrom)(head.refSummary);
|
|
950
|
+
const hasDirectUniqueKeyReqs = headFieldUsages.some(usage => usage.uniqueKeyRequirement);
|
|
869
951
|
if (hasDirectUniqueKeyReqs) {
|
|
870
952
|
hasNestedUniqueKeyReqs = true;
|
|
871
953
|
}
|
|
@@ -888,13 +970,13 @@ function extractNestLevels(segment) {
|
|
|
888
970
|
}, head.referencedAt));
|
|
889
971
|
}
|
|
890
972
|
else {
|
|
891
|
-
const fieldUsage = (
|
|
973
|
+
const fieldUsage = (0, malloy_types_1.fieldUsageFrom)(field.refSummary);
|
|
892
974
|
fieldsReferenced.push(...fieldUsage);
|
|
893
|
-
ungroupings.push(...((
|
|
894
|
-
requiredGroupBys.push(...((
|
|
975
|
+
ungroupings.push(...((_a = field.ungroupings) !== null && _a !== void 0 ? _a : []));
|
|
976
|
+
requiredGroupBys.push(...((_b = field.requiresGroupBy) !== null && _b !== void 0 ? _b : []));
|
|
895
977
|
}
|
|
896
978
|
}
|
|
897
|
-
for (const filter of (
|
|
979
|
+
for (const filter of (_c = segment.filterList) !== null && _c !== void 0 ? _c : []) {
|
|
898
980
|
if (!(0, malloy_types_1.expressionIsScalar)(filter.expressionType))
|
|
899
981
|
continue;
|
|
900
982
|
const fields = getSingleValueFilterFields(filter.e);
|
|
@@ -972,7 +1054,7 @@ function isSingleValueFilterNode(e) {
|
|
|
972
1054
|
}
|
|
973
1055
|
}
|
|
974
1056
|
function expandRefs(nests, fields) {
|
|
975
|
-
var _a, _b, _c
|
|
1057
|
+
var _a, _b, _c;
|
|
976
1058
|
const newNests = [];
|
|
977
1059
|
const requiredGroupBys = [...nests.requiredGroupBys];
|
|
978
1060
|
const allUngroupings = [...nests.ungroupings];
|
|
@@ -1025,7 +1107,7 @@ function expandRefs(nests, fields) {
|
|
|
1025
1107
|
if (def.ungroupings) {
|
|
1026
1108
|
allUngroupings.push(...joinedUngroupings(joinPath, ungroupingsAt(def.ungroupings, field.at)));
|
|
1027
1109
|
}
|
|
1028
|
-
const fieldUsage = (
|
|
1110
|
+
const fieldUsage = (0, malloy_types_1.fieldUsageFrom)(def.refSummary);
|
|
1029
1111
|
const moreReferences = fieldUsageAt(joinedFieldUsage(joinPath, fieldUsage), field.at).filter(u1 => !references.some(u2 => pathEq(u1.path, u2.path)));
|
|
1030
1112
|
references.push(...moreReferences);
|
|
1031
1113
|
}
|
|
@@ -1045,10 +1127,10 @@ function expandRefs(nests, fields) {
|
|
|
1045
1127
|
fieldsReferencedDirectly: [],
|
|
1046
1128
|
ungroupings: [],
|
|
1047
1129
|
nested: [],
|
|
1048
|
-
requiredGroupBys: (
|
|
1130
|
+
requiredGroupBys: (_a = ungrouping.requiresGroupBy) !== null && _a !== void 0 ? _a : [],
|
|
1049
1131
|
singleValueFilters: [],
|
|
1050
1132
|
}, fields);
|
|
1051
|
-
missingFields.push(...((
|
|
1133
|
+
missingFields.push(...((_b = expanded.missingFields) !== null && _b !== void 0 ? _b : []));
|
|
1052
1134
|
for (const field of expanded.result.requiredGroupBys) {
|
|
1053
1135
|
if (isUngroupedBy(ungrouping, field.path)) {
|
|
1054
1136
|
unsatisfiableGroupBys.push(field);
|
|
@@ -1058,7 +1140,7 @@ function expandRefs(nests, fields) {
|
|
|
1058
1140
|
const nested = [];
|
|
1059
1141
|
for (const level of [...nests.nested, ...newNests]) {
|
|
1060
1142
|
const expanded = expandRefs(level, fields);
|
|
1061
|
-
missingFields.push(...((
|
|
1143
|
+
missingFields.push(...((_c = expanded.missingFields) !== null && _c !== void 0 ? _c : []));
|
|
1062
1144
|
nested.push(expanded.result);
|
|
1063
1145
|
unsatisfiableGroupBys.push(...expanded.result.unsatisfiableGroupBys);
|
|
1064
1146
|
allUngroupings.push(...expanded.result.ungroupings);
|
|
@@ -1076,13 +1158,101 @@ function expandRefs(nests, fields) {
|
|
|
1076
1158
|
};
|
|
1077
1159
|
}
|
|
1078
1160
|
function getJoinFieldUsage(join, joinPath) {
|
|
1079
|
-
var _a
|
|
1080
|
-
return ((
|
|
1161
|
+
var _a;
|
|
1162
|
+
return ((_a = mergeFieldUsage(
|
|
1081
1163
|
// For `fieldUsage` from join `where`s, we need the path including the join name
|
|
1082
1164
|
joinedFieldUsage(joinPath, (0, malloy_types_1.isSourceDef)(join) ? getFieldUsageFromFilterList(join) : []),
|
|
1083
1165
|
// For `fieldUsage` from join `on`, we need the path excluding the join name, since it's
|
|
1084
1166
|
// already rooted at the parent
|
|
1085
|
-
joinedFieldUsage(joinPath.slice(0, -1), (
|
|
1167
|
+
joinedFieldUsage(joinPath.slice(0, -1), (0, malloy_types_1.fieldUsageFrom)(join.refSummary)))) !== null && _a !== void 0 ? _a : []);
|
|
1168
|
+
}
|
|
1169
|
+
// Givens have no path — `joinedFieldUsage`'s path-rerooting has no analog here.
|
|
1170
|
+
// The `on:` clause lives on `join.refSummary` for every join shape; everything
|
|
1171
|
+
// else (filterList, plus any givens hiding inside the source's embedded Query)
|
|
1172
|
+
// is collected by `givenUsageOfSource` for source-typed joins.
|
|
1173
|
+
function getJoinGivenUsage(join) {
|
|
1174
|
+
const onClause = (0, malloy_types_1.givenUsageFrom)(join.refSummary);
|
|
1175
|
+
if ((0, malloy_types_1.isSourceDef)(join)) {
|
|
1176
|
+
return [...givenUsageOfSource(join), ...onClause];
|
|
1177
|
+
}
|
|
1178
|
+
return onClause;
|
|
1179
|
+
}
|
|
1180
|
+
// Dedup'd union of `expandedGivenUsage` across every segment in a Query's
|
|
1181
|
+
// finalized pipeline, recursing through nested turtle pipelines. This is the
|
|
1182
|
+
// per-Query summary that consumers (PreparedQuery.givens, satisfiability
|
|
1183
|
+
// check, `givenUsageOfSource` for QuerySourceDef) read instead of re-walking
|
|
1184
|
+
// segments. Called only from the query-arrow / query-refine construction
|
|
1185
|
+
// sites where every segment has been through getExpandedSegment.
|
|
1186
|
+
function computeQueryGivenUsage(pipeline) {
|
|
1187
|
+
const seen = new Set();
|
|
1188
|
+
const result = [];
|
|
1189
|
+
function add(items) {
|
|
1190
|
+
if (!items)
|
|
1191
|
+
return;
|
|
1192
|
+
for (const g of items) {
|
|
1193
|
+
if (seen.has(g.id))
|
|
1194
|
+
continue;
|
|
1195
|
+
seen.add(g.id);
|
|
1196
|
+
result.push(g);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
function visit(segment) {
|
|
1200
|
+
if ((0, malloy_types_1.isQuerySegment)(segment) || (0, malloy_types_1.isIndexSegment)(segment)) {
|
|
1201
|
+
add(segment.expandedGivenUsage);
|
|
1202
|
+
}
|
|
1203
|
+
if ((0, malloy_types_1.isQuerySegment)(segment)) {
|
|
1204
|
+
for (const field of segment.queryFields) {
|
|
1205
|
+
if ((0, malloy_types_1.isTurtle)(field)) {
|
|
1206
|
+
field.pipeline.forEach(visit);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
pipeline.forEach(visit);
|
|
1212
|
+
return result;
|
|
1213
|
+
}
|
|
1214
|
+
// Returns every given a SourceDef references — its own filterList plus any
|
|
1215
|
+
// givens hiding inside an embedded Query. The single point of knowledge for
|
|
1216
|
+
// "where can a Query embed in a SourceDef" — when a future SourceDef variant
|
|
1217
|
+
// grows an embedded Query, teach this helper.
|
|
1218
|
+
//
|
|
1219
|
+
// Composite sources: composite-source support across the codebase is
|
|
1220
|
+
// partial; the givens work isn't chasing it. The `composite` arm here is
|
|
1221
|
+
// defensive — for the top-level `run: composite ->` path it never fires
|
|
1222
|
+
// because composite resolution runs first and `expandRefUsage` is seeded
|
|
1223
|
+
// with the resolved branch. If an unresolved `CompositeSourceDef` ever
|
|
1224
|
+
// reaches here (e.g. composites in join positions if/when those work),
|
|
1225
|
+
// the conservative union over all branches is the safe fallback. See
|
|
1226
|
+
// ~/ctx/mp/implementation.md "Composite sources — partial coverage".
|
|
1227
|
+
function givenUsageOfSource(sd) {
|
|
1228
|
+
var _a, _b, _c;
|
|
1229
|
+
const fromFilters = ((_a = sd.filterList) !== null && _a !== void 0 ? _a : []).flatMap(f => (0, malloy_types_1.givenUsageFrom)(f.refSummary));
|
|
1230
|
+
switch (sd.type) {
|
|
1231
|
+
case 'query_source':
|
|
1232
|
+
return [...fromFilters, ...((_b = sd.query.givenUsage) !== null && _b !== void 0 ? _b : [])];
|
|
1233
|
+
case 'sql_select': {
|
|
1234
|
+
const fromSegments = ((_c = sd.selectSegments) !== null && _c !== void 0 ? _c : []).flatMap(seg => {
|
|
1235
|
+
var _a;
|
|
1236
|
+
if ((0, malloy_types_1.isSegmentSQL)(seg))
|
|
1237
|
+
return [];
|
|
1238
|
+
if ((0, malloy_types_1.isSegmentSource)(seg))
|
|
1239
|
+
return givenUsageOfSource(seg);
|
|
1240
|
+
// Remaining variant of SQLPhraseSegment is `Query`
|
|
1241
|
+
return (_a = seg.givenUsage) !== null && _a !== void 0 ? _a : [];
|
|
1242
|
+
});
|
|
1243
|
+
return [...fromFilters, ...fromSegments];
|
|
1244
|
+
}
|
|
1245
|
+
case 'composite':
|
|
1246
|
+
return [
|
|
1247
|
+
...fromFilters,
|
|
1248
|
+
...sd.sources.flatMap(s => givenUsageOfSource(s)),
|
|
1249
|
+
];
|
|
1250
|
+
default:
|
|
1251
|
+
// table, query_result, finalize, nest_source, virtual — no embedded Query.
|
|
1252
|
+
// (query_result/finalize/nest_source are pipeline-internal and only seen
|
|
1253
|
+
// within a Query whose segments are walked anyway. virtual is opaque.)
|
|
1254
|
+
return fromFilters;
|
|
1255
|
+
}
|
|
1086
1256
|
}
|
|
1087
1257
|
function isUngroupedBy(ungrouping, groupedBy) {
|
|
1088
1258
|
if (ungrouping.ungroupedFields === '*')
|
|
@@ -1098,7 +1268,7 @@ function checkRequiredGroupBys(compositeResolvedSourceDef, segment) {
|
|
|
1098
1268
|
var _a;
|
|
1099
1269
|
const nests = extractNestLevels(segment);
|
|
1100
1270
|
const sourceExtensions = (0, malloy_types_1.isQuerySegment)(segment)
|
|
1101
|
-
? (_a = segment.extendSource) !== null && _a !== void 0 ? _a : []
|
|
1271
|
+
? ((_a = segment.extendSource) !== null && _a !== void 0 ? _a : [])
|
|
1102
1272
|
: [];
|
|
1103
1273
|
const unsatisfied = _checkRequiredGroupBys(nests, mergeFields(compositeResolvedSourceDef.fields, sourceExtensions));
|
|
1104
1274
|
return unsatisfied;
|