@malloydata/malloy 0.0.215 → 0.0.216-dev241118202522
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/dialect/functions/util.d.ts +8 -8
- package/dist/dialect/functions/util.js +15 -7
- package/dist/lang/ast/ast-utils.js +2 -0
- package/dist/lang/ast/expressions/expr-aggregate-function.js +1 -0
- package/dist/lang/ast/expressions/expr-compare.js +7 -14
- package/dist/lang/ast/expressions/expr-count-distinct.js +1 -0
- package/dist/lang/ast/expressions/expr-count.js +3 -0
- package/dist/lang/ast/expressions/expr-func.js +3 -0
- package/dist/lang/ast/expressions/expr-id-reference.js +10 -1
- package/dist/lang/ast/expressions/expr-now.js +2 -0
- package/dist/lang/ast/expressions/expr-ungroup.js +1 -0
- package/dist/lang/ast/field-space/dynamic-space.d.ts +1 -3
- package/dist/lang/ast/field-space/dynamic-space.js +11 -15
- package/dist/lang/ast/field-space/query-spaces.d.ts +19 -0
- package/dist/lang/ast/field-space/query-spaces.js +104 -12
- package/dist/lang/ast/field-space/reference-field.js +7 -1
- package/dist/lang/ast/field-space/refined-space.d.ts +1 -0
- package/dist/lang/ast/field-space/refined-space.js +9 -6
- package/dist/lang/ast/field-space/struct-space-field-base.js +4 -0
- package/dist/lang/ast/index.d.ts +1 -0
- package/dist/lang/ast/index.js +1 -0
- package/dist/lang/ast/query-builders/index-builder.js +1 -1
- package/dist/lang/ast/query-builders/reduce-builder.d.ts +2 -1
- package/dist/lang/ast/query-builders/reduce-builder.js +9 -5
- package/dist/lang/ast/query-elements/query-base.js +16 -3
- package/dist/lang/ast/query-items/field-declaration.js +3 -0
- package/dist/lang/ast/query-properties/filters.d.ts +3 -0
- package/dist/lang/ast/query-properties/filters.js +42 -26
- package/dist/lang/ast/query-properties/nest.d.ts +1 -0
- package/dist/lang/ast/query-properties/nest.js +5 -1
- package/dist/lang/ast/source-elements/composite-source.d.ts +16 -0
- package/dist/lang/ast/source-elements/composite-source.js +75 -0
- package/dist/lang/ast/source-elements/source.d.ts +2 -2
- package/dist/lang/ast/source-properties/join.js +2 -0
- package/dist/lang/ast/source-query-elements/sq-compose.d.ts +13 -0
- package/dist/lang/ast/source-query-elements/sq-compose.js +48 -0
- package/dist/lang/ast/typedesc-utils.js +7 -1
- package/dist/lang/ast/types/expr-value.js +4 -0
- package/dist/lang/ast/types/expression-def.js +4 -5
- package/dist/lang/ast/types/query-builder.d.ts +2 -1
- package/dist/lang/ast/types/space-field.js +14 -1
- package/dist/lang/ast/types/space-param.js +3 -0
- package/dist/lang/ast/view-elements/reference-view.js +1 -0
- package/dist/lang/ast/view-elements/refine-utils.js +2 -0
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +113 -112
- package/dist/lang/lib/Malloy/MalloyLexer.js +1149 -1143
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +126 -112
- package/dist/lang/lib/Malloy/MalloyParser.js +1380 -1282
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +13 -0
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +8 -0
- package/dist/lang/malloy-to-ast.d.ts +1 -0
- package/dist/lang/malloy-to-ast.js +5 -0
- package/dist/lang/parse-log.d.ts +10 -1
- package/dist/lang/parse-log.js +7 -0
- package/dist/lang/test/composite-field-usage.spec.d.ts +1 -0
- package/dist/lang/test/composite-field-usage.spec.js +155 -0
- package/dist/lang/test/parse-expects.d.ts +2 -1
- package/dist/lang/test/parse-expects.js +36 -0
- package/dist/lang/test/source.spec.js +9 -0
- package/dist/lang/test/test-translator.d.ts +3 -1
- package/dist/lang/test/test-translator.js +15 -4
- package/dist/lang/utils.d.ts +1 -0
- package/dist/lang/utils.js +5 -1
- package/dist/model/composite_source_utils.d.ts +65 -0
- package/dist/model/composite_source_utils.js +279 -0
- package/dist/model/malloy_query.d.ts +3 -3
- package/dist/model/malloy_query.js +13 -6
- package/dist/model/malloy_types.d.ts +19 -2
- package/dist/model/malloy_types.js +15 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -17,9 +17,9 @@ export interface DialectFunctionOverloadDef {
|
|
|
17
17
|
export declare function arg(name: string): Expr;
|
|
18
18
|
export declare function spread(e: Expr, prefix?: string | undefined, suffix?: string | undefined): Expr;
|
|
19
19
|
export declare function sql(strings: TemplateStringsArray, ...subExprs: SQLExprElement[]): Expr;
|
|
20
|
-
export declare function constant(type:
|
|
21
|
-
export declare function output(type:
|
|
22
|
-
export declare function literal(type:
|
|
20
|
+
export declare function constant(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
|
|
21
|
+
export declare function output(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
|
|
22
|
+
export declare function literal(type: FunctionParamTypeDesc): FunctionParamTypeDesc;
|
|
23
23
|
export declare function variadicParam(name: string, ...allowedTypes: FunctionParamTypeDesc[]): FunctionParameterDef;
|
|
24
24
|
/**
|
|
25
25
|
* Prefer `makeParam` for future function definitions
|
|
@@ -29,14 +29,14 @@ export declare function makeParam(name: string, ...allowedTypes: FunctionParamTy
|
|
|
29
29
|
param: FunctionParameterDef;
|
|
30
30
|
arg: Expr;
|
|
31
31
|
};
|
|
32
|
-
export declare function maxScalar(type: LeafExpressionType):
|
|
33
|
-
export declare function maxAggregate(type: LeafExpressionType):
|
|
32
|
+
export declare function maxScalar(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
33
|
+
export declare function maxAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
34
34
|
export declare function anyExprType(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
35
35
|
export declare function maxUngroupedAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
36
36
|
export declare function maxAnalytic(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
37
|
-
export declare function minScalar(type: LeafExpressionType):
|
|
38
|
-
export declare function minAggregate(type: LeafExpressionType):
|
|
39
|
-
export declare function minAnalytic(type: LeafExpressionType):
|
|
37
|
+
export declare function minScalar(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
38
|
+
export declare function minAggregate(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
39
|
+
export declare function minAnalytic(type: LeafExpressionType): FunctionParamTypeDesc;
|
|
40
40
|
export declare function overload(returnType: TypeDesc, params: FunctionParameterDef[], e: Expr, options?: {
|
|
41
41
|
needsWindowOrderBy?: boolean;
|
|
42
42
|
between?: {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.expandOverrideMapFromBase = exports.expandBlueprintMap = exports.overload = exports.minAnalytic = exports.minAggregate = exports.minScalar = exports.maxAnalytic = exports.maxUngroupedAggregate = exports.anyExprType = exports.maxAggregate = exports.maxScalar = exports.makeParam = exports.param = exports.variadicParam = exports.literal = exports.output = exports.constant = exports.sql = exports.spread = exports.arg = void 0;
|
|
26
|
+
const composite_source_utils_1 = require("../../model/composite_source_utils");
|
|
26
27
|
function arg(name) {
|
|
27
28
|
return { node: 'function_parameter', name };
|
|
28
29
|
}
|
|
@@ -159,27 +160,34 @@ function removeGeneric(type, generic) {
|
|
|
159
160
|
return generic.type;
|
|
160
161
|
}
|
|
161
162
|
function expandReturnTypeBlueprint(blueprint, generic) {
|
|
163
|
+
var _a;
|
|
164
|
+
let base;
|
|
162
165
|
if (typeof blueprint === 'string') {
|
|
163
|
-
|
|
166
|
+
base = minScalar(blueprint);
|
|
164
167
|
}
|
|
165
168
|
else if ('generic' in blueprint) {
|
|
166
|
-
|
|
169
|
+
base = minScalar(removeGeneric(blueprint, generic));
|
|
167
170
|
}
|
|
168
171
|
else if ('literal' in blueprint) {
|
|
169
|
-
|
|
172
|
+
base = literal(minScalar(removeGeneric(blueprint.literal, generic)));
|
|
170
173
|
}
|
|
171
174
|
else if ('constant' in blueprint) {
|
|
172
|
-
|
|
175
|
+
base = constant(minScalar(removeGeneric(blueprint.constant, generic)));
|
|
173
176
|
}
|
|
174
177
|
else if ('dimension' in blueprint) {
|
|
175
|
-
|
|
178
|
+
base = minScalar(removeGeneric(blueprint.dimension, generic));
|
|
176
179
|
}
|
|
177
180
|
else if ('measure' in blueprint) {
|
|
178
|
-
|
|
181
|
+
base = minAggregate(removeGeneric(blueprint.measure, generic));
|
|
179
182
|
}
|
|
180
183
|
else {
|
|
181
|
-
|
|
184
|
+
base = minAnalytic(removeGeneric(blueprint.calculation, generic));
|
|
182
185
|
}
|
|
186
|
+
return {
|
|
187
|
+
...base,
|
|
188
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
189
|
+
expressionType: (_a = base.expressionType) !== null && _a !== void 0 ? _a : 'scalar',
|
|
190
|
+
};
|
|
183
191
|
}
|
|
184
192
|
function isTypeDescBlueprint(blueprint) {
|
|
185
193
|
return (typeof blueprint === 'string' ||
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.errorFor = void 0;
|
|
26
|
+
const composite_source_utils_1 = require("../../model/composite_source_utils");
|
|
26
27
|
/**
|
|
27
28
|
* When a translation hits an error, log and return one of these as a value.
|
|
28
29
|
* This will allow the rest of the translation walk to complete. The
|
|
@@ -37,6 +38,7 @@ function errorFor(reason) {
|
|
|
37
38
|
expressionType: 'scalar',
|
|
38
39
|
value: { node: 'error', message: reason },
|
|
39
40
|
evalSpace: 'constant',
|
|
41
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
exports.errorFor = errorFor;
|
|
@@ -92,6 +92,7 @@ class ExprAggregateFunction extends expression_def_1.ExpressionDef {
|
|
|
92
92
|
? { node: 'outputField', name: this.source.refString }
|
|
93
93
|
: { node: 'field', path: this.source.path },
|
|
94
94
|
evalSpace: footType.evalSpace,
|
|
95
|
+
compositeFieldUsage: footType.compositeFieldUsage,
|
|
95
96
|
};
|
|
96
97
|
structPath = this.source.path;
|
|
97
98
|
// Here we handle a special case where you write `foo.agg()` and `foo` is a
|
|
@@ -46,8 +46,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.ExprLegacyIn = exports.ExprEquality = exports.ExprCompare = void 0;
|
|
49
|
-
const model_1 = require("../../../model");
|
|
50
49
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
50
|
+
const expr_value_1 = require("../types/expr-value");
|
|
51
51
|
const expression_def_1 = require("../types/expression-def");
|
|
52
52
|
const binary_boolean_1 = require("./binary-boolean");
|
|
53
53
|
const compareTypes = {
|
|
@@ -101,23 +101,16 @@ class ExprLegacyIn extends expression_def_1.ExpressionDef {
|
|
|
101
101
|
}
|
|
102
102
|
getExpression(fs) {
|
|
103
103
|
const lookFor = this.expr.getExpression(fs);
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
expressionType = (0, model_1.maxExpressionType)(expressionType, choice.expressionType);
|
|
108
|
-
evalSpace = (0, model_1.mergeEvalSpaces)(evalSpace, choice.evalSpace);
|
|
109
|
-
return choice.value;
|
|
110
|
-
});
|
|
111
|
-
return {
|
|
112
|
-
type: 'boolean',
|
|
113
|
-
expressionType,
|
|
114
|
-
evalSpace,
|
|
104
|
+
const oneOf = this.choices.map(e => e.getExpression(fs));
|
|
105
|
+
return (0, expr_value_1.computedExprValue)({
|
|
106
|
+
dataType: { type: 'boolean' },
|
|
115
107
|
value: {
|
|
116
108
|
node: 'in',
|
|
117
109
|
not: this.notIn,
|
|
118
|
-
kids: { e: lookFor.value, oneOf },
|
|
110
|
+
kids: { e: lookFor.value, oneOf: oneOf.map(v => v.value) },
|
|
119
111
|
},
|
|
120
|
-
|
|
112
|
+
from: [lookFor, ...oneOf],
|
|
113
|
+
});
|
|
121
114
|
}
|
|
122
115
|
}
|
|
123
116
|
exports.ExprLegacyIn = ExprLegacyIn;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ExprCount = void 0;
|
|
26
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
26
27
|
const expr_aggregate_function_1 = require("./expr-aggregate-function");
|
|
27
28
|
class ExprCount extends expr_aggregate_function_1.ExprAggregateFunction {
|
|
28
29
|
constructor(source) {
|
|
@@ -44,6 +45,7 @@ class ExprCount extends expr_aggregate_function_1.ExprAggregateFunction {
|
|
|
44
45
|
evalSpace: ev.evalSpace,
|
|
45
46
|
expressionType: 'aggregate',
|
|
46
47
|
value: ev.value,
|
|
48
|
+
compositeFieldUsage: ev.compositeFieldUsage,
|
|
47
49
|
};
|
|
48
50
|
}
|
|
49
51
|
getExpression(_fs) {
|
|
@@ -61,6 +63,7 @@ class ExprCount extends expr_aggregate_function_1.ExprAggregateFunction {
|
|
|
61
63
|
expressionType: 'aggregate',
|
|
62
64
|
value: ret,
|
|
63
65
|
evalSpace: 'output',
|
|
66
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
64
67
|
};
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -54,6 +54,7 @@ const expression_def_1 = require("../types/expression-def");
|
|
|
54
54
|
const field_space_1 = require("../types/field-space");
|
|
55
55
|
const utils_1 = require("../../../model/utils");
|
|
56
56
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
57
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
57
58
|
class ExprFunc extends expression_def_1.ExpressionDef {
|
|
58
59
|
constructor(name, args, isRaw, rawType, source) {
|
|
59
60
|
super({ args: args });
|
|
@@ -141,6 +142,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
141
142
|
expressionType: footType.expressionType,
|
|
142
143
|
value: { node: 'field', path: this.source.path },
|
|
143
144
|
evalSpace: footType.evalSpace,
|
|
145
|
+
compositeFieldUsage: footType.compositeFieldUsage,
|
|
144
146
|
};
|
|
145
147
|
structPath = this.source.path.slice(0, -1);
|
|
146
148
|
}
|
|
@@ -335,6 +337,7 @@ class ExprFunc extends expression_def_1.ExpressionDef {
|
|
|
335
337
|
expressionType,
|
|
336
338
|
value: funcCall,
|
|
337
339
|
evalSpace,
|
|
340
|
+
compositeFieldUsage: (0, composite_source_utils_1.mergeCompositeFieldUsage)(...argExprs.map(e => e.compositeFieldUsage)),
|
|
338
341
|
};
|
|
339
342
|
}
|
|
340
343
|
}
|
|
@@ -25,6 +25,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.ExprIdReference = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
27
|
const expression_def_1 = require("../types/expression-def");
|
|
28
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
28
29
|
class ExprIdReference extends expression_def_1.ExpressionDef {
|
|
29
30
|
constructor(fieldReference) {
|
|
30
31
|
super();
|
|
@@ -37,14 +38,22 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
|
|
|
37
38
|
}
|
|
38
39
|
getExpression(fs) {
|
|
39
40
|
const def = this.fieldReference.getField(fs);
|
|
41
|
+
// TODO Currently the join usage is always equivalent to the reference path here;
|
|
42
|
+
// if/when we add namespaces, this will not be the case, and we will need to get the
|
|
43
|
+
// join path from `getField` / `lookup`
|
|
44
|
+
const compositeJoinUsage = this.fieldReference.list
|
|
45
|
+
.map(n => n.name)
|
|
46
|
+
.slice(0, -1);
|
|
40
47
|
if (def.found) {
|
|
41
48
|
const td = def.found.typeDesc();
|
|
49
|
+
const compositeFieldUsage = (0, composite_source_utils_1.joinedCompositeFieldUsage)(compositeJoinUsage, td.compositeFieldUsage);
|
|
42
50
|
if (def.isOutputField) {
|
|
43
51
|
return {
|
|
44
52
|
...td,
|
|
45
53
|
// TODO what about literal??
|
|
46
54
|
evalSpace: td.evalSpace === 'constant' ? 'constant' : 'output',
|
|
47
55
|
value: { node: 'outputField', name: this.refString },
|
|
56
|
+
compositeFieldUsage,
|
|
48
57
|
};
|
|
49
58
|
}
|
|
50
59
|
const value = { node: def.found.refType, path: this.fieldReference.path };
|
|
@@ -52,7 +61,7 @@ class ExprIdReference extends expression_def_1.ExpressionDef {
|
|
|
52
61
|
const evalSpace = (0, malloy_types_1.expressionIsAggregate)(td.expressionType)
|
|
53
62
|
? 'output'
|
|
54
63
|
: td.evalSpace;
|
|
55
|
-
return { ...td, value, evalSpace };
|
|
64
|
+
return { ...td, value, evalSpace, compositeFieldUsage };
|
|
56
65
|
}
|
|
57
66
|
return this.loggedErrorExpr(def.error.code, def.error.message);
|
|
58
67
|
}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ExprNow = void 0;
|
|
26
26
|
const expression_def_1 = require("../types/expression-def");
|
|
27
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
27
28
|
class ExprNow extends expression_def_1.ExpressionDef {
|
|
28
29
|
constructor() {
|
|
29
30
|
super(...arguments);
|
|
@@ -36,6 +37,7 @@ class ExprNow extends expression_def_1.ExpressionDef {
|
|
|
36
37
|
// `now` is considered to be a constant, at least in the dialects we support today
|
|
37
38
|
evalSpace: 'constant',
|
|
38
39
|
value: { node: 'now' },
|
|
40
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
39
41
|
};
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -106,6 +106,7 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
|
|
|
106
106
|
expressionType: 'ungrouped_aggregate',
|
|
107
107
|
value: ungroup,
|
|
108
108
|
evalSpace: 'output',
|
|
109
|
+
compositeFieldUsage: exprVal.compositeFieldUsage,
|
|
109
110
|
};
|
|
110
111
|
}
|
|
111
112
|
return this.loggedErrorExpr('ungroup-with-non-scalar', `${this.control}() incompatible type`);
|
|
@@ -7,14 +7,12 @@ import { ParameterSpace } from './parameter-space';
|
|
|
7
7
|
import { SourceDef } from '../../../model/malloy_types';
|
|
8
8
|
import { SourceFieldSpace } from '../types/field-space';
|
|
9
9
|
export declare abstract class DynamicSpace extends StaticSpace implements SourceFieldSpace {
|
|
10
|
-
protected
|
|
10
|
+
protected sourceDef: model.SourceDef | undefined;
|
|
11
11
|
protected fromSource: model.SourceDef;
|
|
12
|
-
completions: (() => void)[];
|
|
13
12
|
private complete;
|
|
14
13
|
private parameters;
|
|
15
14
|
protected newTimezone?: string;
|
|
16
15
|
constructor(extending: SourceDef);
|
|
17
|
-
isComplete(): void;
|
|
18
16
|
protected setEntry(name: string, value: SpaceEntry): void;
|
|
19
17
|
addParameters(parameters: HasParameter[]): DynamicSpace;
|
|
20
18
|
parameterSpace(): ParameterSpace;
|
|
@@ -59,17 +59,13 @@ const parameter_space_1 = require("./parameter-space");
|
|
|
59
59
|
class DynamicSpace extends static_space_1.StaticSpace {
|
|
60
60
|
constructor(extending) {
|
|
61
61
|
super(structuredClone(extending));
|
|
62
|
-
this.completions = [];
|
|
63
62
|
this.complete = false;
|
|
64
63
|
this.parameters = [];
|
|
65
64
|
this.fromSource = extending;
|
|
66
|
-
this.
|
|
67
|
-
}
|
|
68
|
-
isComplete() {
|
|
69
|
-
this.complete = true;
|
|
65
|
+
this.sourceDef = undefined;
|
|
70
66
|
}
|
|
71
67
|
setEntry(name, value) {
|
|
72
|
-
if (this.
|
|
68
|
+
if (this.complete) {
|
|
73
69
|
throw new Error('Space already final');
|
|
74
70
|
}
|
|
75
71
|
super.setEntry(name, value);
|
|
@@ -104,7 +100,8 @@ class DynamicSpace extends static_space_1.StaticSpace {
|
|
|
104
100
|
this.newTimezone = tz;
|
|
105
101
|
}
|
|
106
102
|
structDef() {
|
|
107
|
-
|
|
103
|
+
this.complete = true;
|
|
104
|
+
if (this.sourceDef === undefined) {
|
|
108
105
|
// Grab all the parameters so that we can populate the "final" structDef
|
|
109
106
|
// with parameters immediately so that views can see them when they are translating
|
|
110
107
|
const parameters = {};
|
|
@@ -113,8 +110,8 @@ class DynamicSpace extends static_space_1.StaticSpace {
|
|
|
113
110
|
parameters[name] = entry.parameter();
|
|
114
111
|
}
|
|
115
112
|
}
|
|
116
|
-
this.
|
|
117
|
-
this.
|
|
113
|
+
this.sourceDef = { ...this.fromSource, fields: [] };
|
|
114
|
+
this.sourceDef.parameters = parameters;
|
|
118
115
|
// Need to process the entities in specific order
|
|
119
116
|
const fields = [];
|
|
120
117
|
const joins = [];
|
|
@@ -137,14 +134,14 @@ class DynamicSpace extends static_space_1.StaticSpace {
|
|
|
137
134
|
if (field instanceof join_space_field_1.JoinSpaceField) {
|
|
138
135
|
const joinStruct = field.join.structDef(parameterSpace);
|
|
139
136
|
if (!error_factory_1.ErrorFactory.didCreate(joinStruct)) {
|
|
140
|
-
this.
|
|
137
|
+
this.sourceDef.fields.push(joinStruct);
|
|
141
138
|
fixupJoins.push([field.join, joinStruct]);
|
|
142
139
|
}
|
|
143
140
|
}
|
|
144
141
|
else {
|
|
145
142
|
const fieldDef = field.fieldDef();
|
|
146
143
|
if (fieldDef) {
|
|
147
|
-
this.
|
|
144
|
+
this.sourceDef.fields.push(fieldDef);
|
|
148
145
|
}
|
|
149
146
|
// TODO I'm just removing this, but perhaps instead I should just filter
|
|
150
147
|
// out ReferenceFields and still make this check.
|
|
@@ -158,11 +155,10 @@ class DynamicSpace extends static_space_1.StaticSpace {
|
|
|
158
155
|
join.fixupJoinOn(this, missingOn);
|
|
159
156
|
}
|
|
160
157
|
}
|
|
161
|
-
if (this.newTimezone && model.isSourceDef(this.
|
|
162
|
-
this.
|
|
158
|
+
if (this.newTimezone && model.isSourceDef(this.sourceDef)) {
|
|
159
|
+
this.sourceDef.queryTimezone = this.newTimezone;
|
|
163
160
|
}
|
|
164
|
-
this.
|
|
165
|
-
return this.final;
|
|
161
|
+
return this.sourceDef;
|
|
166
162
|
}
|
|
167
163
|
emptyStructDef() {
|
|
168
164
|
const ret = { ...this.fromSource };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as model from '../../../model/malloy_types';
|
|
2
2
|
import { FieldName, QueryFieldSpace, SourceFieldSpace } from '../types/field-space';
|
|
3
3
|
import { MalloyElement } from '../types/malloy-element';
|
|
4
|
+
import { SpaceField } from '../types/space-field';
|
|
4
5
|
import { WildcardFieldReference } from '../query-items/field-references';
|
|
5
6
|
import { RefinedSpace } from './refined-space';
|
|
6
7
|
import { LookupResult } from '../types/lookup-result';
|
|
7
8
|
import { QueryInputSpace } from './query-input-space';
|
|
9
|
+
import { SpaceEntry } from '../types/space-entry';
|
|
8
10
|
import { LogMessageOptions, MessageCode, MessageParameterType } from '../../parse-log';
|
|
9
11
|
/**
|
|
10
12
|
* The output space of a query operation. It is not named "QueryOutputSpace"
|
|
@@ -19,12 +21,29 @@ export declare abstract class QueryOperationSpace extends RefinedSpace implement
|
|
|
19
21
|
protected exprSpace: QueryInputSpace;
|
|
20
22
|
abstract readonly segmentType: 'reduce' | 'project' | 'index';
|
|
21
23
|
expandedWild: Record<string, string[]>;
|
|
24
|
+
compositeFieldUsers: ({
|
|
25
|
+
type: 'filter';
|
|
26
|
+
filter: model.FilterCondition;
|
|
27
|
+
logTo: MalloyElement;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'field';
|
|
30
|
+
name: string;
|
|
31
|
+
field: SpaceField;
|
|
32
|
+
logTo: MalloyElement | undefined;
|
|
33
|
+
})[];
|
|
34
|
+
_compositeFieldUsage: model.CompositeFieldUsage | undefined;
|
|
35
|
+
get compositeFieldUsage(): model.CompositeFieldUsage;
|
|
22
36
|
constructor(queryInputSpace: SourceFieldSpace, refineThis: model.PipeSegment | undefined, nestParent: QueryOperationSpace | undefined, astEl: MalloyElement);
|
|
23
37
|
abstract addRefineFromFields(refineThis: model.PipeSegment): void;
|
|
24
38
|
logError<T extends MessageCode>(code: T, parameters: MessageParameterType<T>, options?: Omit<LogMessageOptions, 'severity'>): T;
|
|
25
39
|
inputSpace(): QueryInputSpace;
|
|
26
40
|
outputSpace(): QueryOperationSpace;
|
|
27
41
|
protected addWild(wild: WildcardFieldReference): void;
|
|
42
|
+
protected addValidatedCompositeFieldUserFromEntry(name: string, entry: SpaceEntry): void;
|
|
43
|
+
private getJoinOnCompositeFieldUsage;
|
|
44
|
+
protected getCompositeFieldUsageIncludingJoinOns(compositeFieldUsage: model.CompositeFieldUsage): model.CompositeFieldUsage;
|
|
45
|
+
addCompositeFieldUserFromFilter(filter: model.FilterCondition, logTo: MalloyElement): void;
|
|
46
|
+
newEntry(name: string, logTo: MalloyElement, entry: SpaceEntry): void;
|
|
28
47
|
}
|
|
29
48
|
export declare abstract class QuerySpace extends QueryOperationSpace {
|
|
30
49
|
addRefineFromFields(refineThis: model.PipeSegment): void;
|
|
@@ -55,6 +55,8 @@ const refined_space_1 = require("./refined-space");
|
|
|
55
55
|
const column_space_field_1 = require("./column-space-field");
|
|
56
56
|
const static_space_1 = require("./static-space");
|
|
57
57
|
const query_input_space_1 = require("./query-input-space");
|
|
58
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
59
|
+
const struct_space_field_base_1 = require("./struct-space-field-base");
|
|
58
60
|
/**
|
|
59
61
|
* The output space of a query operation. It is not named "QueryOutputSpace"
|
|
60
62
|
* because this is the namespace of the Query which is a layer of an output and
|
|
@@ -62,12 +64,22 @@ const query_input_space_1 = require("./query-input-space");
|
|
|
62
64
|
* created and paired when a QueryOperationSpace is created.
|
|
63
65
|
*/
|
|
64
66
|
class QueryOperationSpace extends refined_space_1.RefinedSpace {
|
|
67
|
+
get compositeFieldUsage() {
|
|
68
|
+
if (this._compositeFieldUsage === undefined) {
|
|
69
|
+
throw new Error('Composite field usage accessed before computed');
|
|
70
|
+
}
|
|
71
|
+
return this._compositeFieldUsage;
|
|
72
|
+
}
|
|
65
73
|
constructor(queryInputSpace, refineThis, nestParent, astEl) {
|
|
66
74
|
super(queryInputSpace.emptyStructDef());
|
|
67
75
|
this.queryInputSpace = queryInputSpace;
|
|
68
76
|
this.nestParent = nestParent;
|
|
69
77
|
this.astEl = astEl;
|
|
70
78
|
this.expandedWild = {};
|
|
79
|
+
this.compositeFieldUsers = [];
|
|
80
|
+
// Composite field usage is not computed until `queryFieldDefs` is called; if anyone
|
|
81
|
+
// tries to access it before that, they'll get an error
|
|
82
|
+
this._compositeFieldUsage = undefined;
|
|
71
83
|
this.exprSpace = new query_input_space_1.QueryInputSpace(queryInputSpace.structDef(), this);
|
|
72
84
|
if (refineThis)
|
|
73
85
|
this.addRefineFromFields(refineThis);
|
|
@@ -134,8 +146,48 @@ class QueryOperationSpace extends refined_space_1.RefinedSpace {
|
|
|
134
146
|
}
|
|
135
147
|
// There were tests which expected these to be sorted, and that seems reasonable
|
|
136
148
|
for (const x of expandEntries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
137
|
-
this.
|
|
149
|
+
this.newEntry(x.name, wild, x.entry);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
addValidatedCompositeFieldUserFromEntry(name, entry) {
|
|
153
|
+
if (entry instanceof space_field_1.SpaceField) {
|
|
154
|
+
this.compositeFieldUsers.push({
|
|
155
|
+
type: 'field',
|
|
156
|
+
name,
|
|
157
|
+
field: entry,
|
|
158
|
+
logTo: undefined,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
getJoinOnCompositeFieldUsage(joinPath) {
|
|
163
|
+
var _a;
|
|
164
|
+
const reference = joinPath.map(n => new field_space_1.FieldName(n));
|
|
165
|
+
this.astEl.has({ reference });
|
|
166
|
+
const lookup = this.queryInputSpace.lookup(reference);
|
|
167
|
+
// Should always be found...
|
|
168
|
+
if (lookup.found && lookup.found instanceof struct_space_field_base_1.StructSpaceFieldBase) {
|
|
169
|
+
return ((_a = lookup.found.fieldDef().onCompositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)());
|
|
138
170
|
}
|
|
171
|
+
throw new Error('Unexpected join lookup was not found or not a struct');
|
|
172
|
+
}
|
|
173
|
+
getCompositeFieldUsageIncludingJoinOns(compositeFieldUsage) {
|
|
174
|
+
let compositeFieldUsageIncludingJoinOns = compositeFieldUsage;
|
|
175
|
+
const joinPaths = (0, composite_source_utils_1.compositeFieldUsageJoinPaths)(compositeFieldUsage);
|
|
176
|
+
for (const joinPath of joinPaths) {
|
|
177
|
+
compositeFieldUsageIncludingJoinOns = (0, composite_source_utils_1.mergeCompositeFieldUsage)(this.getJoinOnCompositeFieldUsage(joinPath), compositeFieldUsageIncludingJoinOns);
|
|
178
|
+
}
|
|
179
|
+
return compositeFieldUsageIncludingJoinOns;
|
|
180
|
+
}
|
|
181
|
+
addCompositeFieldUserFromFilter(filter, logTo) {
|
|
182
|
+
if (filter.compositeFieldUsage !== undefined) {
|
|
183
|
+
this.compositeFieldUsers.push({ type: 'filter', filter, logTo });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
newEntry(name, logTo, entry) {
|
|
187
|
+
if (entry instanceof space_field_1.SpaceField) {
|
|
188
|
+
this.compositeFieldUsers.push({ type: 'field', name, field: entry, logTo });
|
|
189
|
+
}
|
|
190
|
+
super.newEntry(name, logTo, entry);
|
|
139
191
|
}
|
|
140
192
|
}
|
|
141
193
|
exports.QueryOperationSpace = QueryOperationSpace;
|
|
@@ -147,17 +199,27 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
147
199
|
// TODO mtoy raw,partial,index
|
|
148
200
|
return;
|
|
149
201
|
}
|
|
202
|
+
if (refineThis === null || refineThis === void 0 ? void 0 : refineThis.extendSource) {
|
|
203
|
+
for (const xField of refineThis.extendSource) {
|
|
204
|
+
this.exprSpace.addFieldDef(xField);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
150
207
|
for (const field of refineThis.queryFields) {
|
|
151
208
|
if (field.type === 'fieldref') {
|
|
152
209
|
const refTo = this.exprSpace.lookup(field.path.map(f => new field_space_1.FieldName(f)));
|
|
153
210
|
if (refTo.found) {
|
|
154
|
-
|
|
211
|
+
const name = field.path[field.path.length - 1];
|
|
212
|
+
this.setEntry(name, refTo.found);
|
|
213
|
+
this.addValidatedCompositeFieldUserFromEntry(name, refTo.found);
|
|
155
214
|
}
|
|
156
215
|
}
|
|
157
216
|
else if (field.type !== 'turtle') {
|
|
158
217
|
// TODO can you reference fields in a turtle as fields in the output space,
|
|
159
218
|
// e.g. order_by: my_turtle.foo, or lag(my_turtle.foo)
|
|
160
|
-
|
|
219
|
+
const entry = new column_space_field_1.ColumnSpaceField(field);
|
|
220
|
+
const name = (_a = field.as) !== null && _a !== void 0 ? _a : field.name;
|
|
221
|
+
this.setEntry(name, entry);
|
|
222
|
+
this.addValidatedCompositeFieldUserFromEntry(name, entry);
|
|
161
223
|
}
|
|
162
224
|
}
|
|
163
225
|
}
|
|
@@ -176,16 +238,28 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
176
238
|
}
|
|
177
239
|
queryFieldDefs() {
|
|
178
240
|
const fields = [];
|
|
179
|
-
|
|
180
|
-
|
|
241
|
+
let compositeFieldUsage = (0, composite_source_utils_1.emptyCompositeFieldUsage)();
|
|
242
|
+
let narrowedCompositeFieldResolution = (0, composite_source_utils_1.emptyNarrowedCompositeFieldResolution)();
|
|
243
|
+
const source = this.inputSpace().structDef();
|
|
244
|
+
for (const user of this.compositeFieldUsers) {
|
|
245
|
+
let nextCompositeFieldUsage = undefined;
|
|
246
|
+
if (user.type === 'filter') {
|
|
247
|
+
if (user.filter.compositeFieldUsage) {
|
|
248
|
+
nextCompositeFieldUsage = user.filter.compositeFieldUsage;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const { name, field } = user;
|
|
181
253
|
const wildPath = this.expandedWild[name];
|
|
182
254
|
if (wildPath) {
|
|
183
255
|
fields.push({ type: 'fieldref', path: wildPath });
|
|
184
256
|
continue;
|
|
185
257
|
}
|
|
258
|
+
// TODO handle wildcards for composite sources
|
|
186
259
|
const fieldQueryDef = field.getQueryFieldDef(this.exprSpace);
|
|
187
260
|
if (fieldQueryDef) {
|
|
188
261
|
const typeDesc = field.typeDesc();
|
|
262
|
+
nextCompositeFieldUsage = typeDesc.compositeFieldUsage;
|
|
189
263
|
// Filter out fields whose type is 'error', which means that a totally bad field
|
|
190
264
|
// isn't sent to the compiler, where it will wig out.
|
|
191
265
|
// TODO Figure out how to make errors generated by `canContain` go in the right place,
|
|
@@ -205,8 +279,32 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
205
279
|
// project statements, where we added "*" as a field and also all the individual
|
|
206
280
|
// fields, but the individual fields didn't have field defs.
|
|
207
281
|
}
|
|
282
|
+
if (nextCompositeFieldUsage) {
|
|
283
|
+
const newCompositeFieldUsage = this.getCompositeFieldUsageIncludingJoinOns((0, composite_source_utils_1.compositeFieldUsageDifference)(nextCompositeFieldUsage, compositeFieldUsage));
|
|
284
|
+
compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(compositeFieldUsage, newCompositeFieldUsage);
|
|
285
|
+
if (!(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(newCompositeFieldUsage)) {
|
|
286
|
+
const result = (0, composite_source_utils_1.narrowCompositeFieldResolution)(source, compositeFieldUsage, narrowedCompositeFieldResolution);
|
|
287
|
+
if (result.error) {
|
|
288
|
+
if (user.logTo) {
|
|
289
|
+
user.logTo.logError('invalid-composite-field-usage', {
|
|
290
|
+
newUsage: newCompositeFieldUsage,
|
|
291
|
+
allUsage: compositeFieldUsage,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// This should not happen; logTo should only be not set for a field from a refinement,
|
|
296
|
+
// which should never fail the composite resolution
|
|
297
|
+
throw new Error('Unexpected invalid composite field resolution');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
narrowedCompositeFieldResolution =
|
|
302
|
+
result.narrowedCompositeFieldResolution;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
208
306
|
}
|
|
209
|
-
this.
|
|
307
|
+
this._compositeFieldUsage = compositeFieldUsage;
|
|
210
308
|
return fields;
|
|
211
309
|
}
|
|
212
310
|
getQuerySegment(rf) {
|
|
@@ -222,11 +320,6 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
222
320
|
this.logError('unexpected-index-segment', 'internal error generating index segment from non index query');
|
|
223
321
|
return { type: 'reduce', queryFields: [] };
|
|
224
322
|
}
|
|
225
|
-
if (refineFrom === null || refineFrom === void 0 ? void 0 : refineFrom.extendSource) {
|
|
226
|
-
for (const xField of refineFrom.extendSource) {
|
|
227
|
-
this.exprSpace.addFieldDef(xField);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
323
|
const segment = {
|
|
231
324
|
type: this.segmentType,
|
|
232
325
|
queryFields: this.queryFieldDefs(),
|
|
@@ -249,7 +342,6 @@ class QuerySpace extends QueryOperationSpace {
|
|
|
249
342
|
if (this.newTimezone) {
|
|
250
343
|
segment.queryTimezone = this.newTimezone;
|
|
251
344
|
}
|
|
252
|
-
this.isComplete();
|
|
253
345
|
return segment;
|
|
254
346
|
}
|
|
255
347
|
lookup(path) {
|
|
@@ -49,6 +49,7 @@ exports.ReferenceField = void 0;
|
|
|
49
49
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
50
50
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
51
51
|
const space_field_1 = require("../types/space-field");
|
|
52
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
52
53
|
class ReferenceField extends space_field_1.SpaceField {
|
|
53
54
|
constructor(fieldRef, inFS) {
|
|
54
55
|
super();
|
|
@@ -112,7 +113,12 @@ class ReferenceField extends space_field_1.SpaceField {
|
|
|
112
113
|
return this.memoTypeDesc;
|
|
113
114
|
const refTo = this.referenceTo;
|
|
114
115
|
if (refTo) {
|
|
115
|
-
|
|
116
|
+
const joinPath = this.fieldRef.list.slice(0, -1).map(x => x.refString);
|
|
117
|
+
const typeDesc = refTo.typeDesc();
|
|
118
|
+
this.memoTypeDesc = {
|
|
119
|
+
...typeDesc,
|
|
120
|
+
compositeFieldUsage: (0, composite_source_utils_1.joinedCompositeFieldUsage)(joinPath, typeDesc.compositeFieldUsage),
|
|
121
|
+
};
|
|
116
122
|
return this.memoTypeDesc;
|
|
117
123
|
}
|
|
118
124
|
return TDU.errorT;
|
|
@@ -11,4 +11,5 @@ export declare class RefinedSpace extends DynamicSpace {
|
|
|
11
11
|
*/
|
|
12
12
|
static filteredFrom(from: SourceDef, choose: FieldListEdit | undefined, parameters: ParameterSpace | undefined): RefinedSpace;
|
|
13
13
|
pushFields(...defs: MalloyElement[]): void;
|
|
14
|
+
addField(def: MalloyElement): void;
|
|
14
15
|
}
|
|
@@ -60,12 +60,15 @@ class RefinedSpace extends dynamic_space_1.DynamicSpace {
|
|
|
60
60
|
}
|
|
61
61
|
pushFields(...defs) {
|
|
62
62
|
for (const me of defs) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
this.addField(me);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
addField(def) {
|
|
67
|
+
if ((0, space_entry_1.canMakeEntry)(def)) {
|
|
68
|
+
def.makeEntry(this);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
def.logError('unexpected-element-type', `Internal error, ${def.elementType} not expected in this context`);
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
}
|