@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
|
@@ -46,6 +46,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.StructSpaceFieldBase = void 0;
|
|
49
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
49
50
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
50
51
|
const TDU = __importStar(require("../typedesc-utils"));
|
|
51
52
|
const space_field_1 = require("../types/space-field");
|
|
@@ -65,17 +66,20 @@ class StructSpaceFieldBase extends space_field_1.SpaceField {
|
|
|
65
66
|
};
|
|
66
67
|
}
|
|
67
68
|
typeDesc() {
|
|
69
|
+
var _a, _b;
|
|
68
70
|
if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
|
|
69
71
|
return {
|
|
70
72
|
type: this.structDef.type,
|
|
71
73
|
evalSpace: 'input',
|
|
72
74
|
expressionType: 'scalar',
|
|
75
|
+
compositeFieldUsage: (_a = this.structDef.onCompositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
73
76
|
};
|
|
74
77
|
}
|
|
75
78
|
return {
|
|
76
79
|
...TDU.atomicDef(this.structDef),
|
|
77
80
|
evalSpace: 'input',
|
|
78
81
|
expressionType: 'scalar',
|
|
82
|
+
compositeFieldUsage: (_b = this.structDef.onCompositeFieldUsage) !== null && _b !== void 0 ? _b : (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
79
83
|
};
|
|
80
84
|
}
|
|
81
85
|
}
|
package/dist/lang/ast/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './source-query-elements/sq-refine';
|
|
|
9
9
|
export * from './source-query-elements/sq-source';
|
|
10
10
|
export * from './source-query-elements/sq-reference';
|
|
11
11
|
export * from './source-query-elements/sq-extend';
|
|
12
|
+
export * from './source-query-elements/sq-compose';
|
|
12
13
|
export * from './source-properties/field-list-edit';
|
|
13
14
|
export * from './source-properties/primary-key';
|
|
14
15
|
export * from './source-properties/renames';
|
package/dist/lang/ast/index.js
CHANGED
|
@@ -47,6 +47,7 @@ __exportStar(require("./source-query-elements/sq-refine"), exports);
|
|
|
47
47
|
__exportStar(require("./source-query-elements/sq-source"), exports);
|
|
48
48
|
__exportStar(require("./source-query-elements/sq-reference"), exports);
|
|
49
49
|
__exportStar(require("./source-query-elements/sq-extend"), exports);
|
|
50
|
+
__exportStar(require("./source-query-elements/sq-compose"), exports);
|
|
50
51
|
__exportStar(require("./source-properties/field-list-edit"), exports);
|
|
51
52
|
__exportStar(require("./source-properties/primary-key"), exports);
|
|
52
53
|
__exportStar(require("./source-properties/renames"), exports);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FilterCondition, PipeSegment, QuerySegment } from '../../../model/malloy_types';
|
|
1
|
+
import { CompositeFieldUsage, FilterCondition, PipeSegment, QuerySegment } from '../../../model/malloy_types';
|
|
2
2
|
import { SourceFieldSpace } from '../types/field-space';
|
|
3
3
|
import { Ordering } from '../query-properties/ordering';
|
|
4
4
|
import { Top } from '../query-properties/top';
|
|
@@ -17,6 +17,7 @@ export declare abstract class QuerySegmentBuilder implements QueryBuilder {
|
|
|
17
17
|
filters: FilterCondition[];
|
|
18
18
|
execute(qp: QueryProperty): void;
|
|
19
19
|
abstract finalize(fromSeg: PipeSegment | undefined): PipeSegment;
|
|
20
|
+
get compositeFieldUsage(): CompositeFieldUsage;
|
|
20
21
|
refineFrom(from: PipeSegment | undefined, to: QuerySegment): void;
|
|
21
22
|
}
|
|
22
23
|
export declare class ReduceBuilder extends QuerySegmentBuilder implements QueryBuilder {
|
|
@@ -25,12 +25,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
25
25
|
exports.ReduceBuilder = exports.QuerySegmentBuilder = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
27
|
const error_factory_1 = require("../error-factory");
|
|
28
|
-
const filters_1 = require("../query-properties/filters");
|
|
29
28
|
const limit_1 = require("../query-properties/limit");
|
|
30
29
|
const ordering_1 = require("../query-properties/ordering");
|
|
31
30
|
const top_1 = require("../query-properties/top");
|
|
32
31
|
const query_spaces_1 = require("../field-space/query-spaces");
|
|
33
32
|
const definition_list_1 = require("../types/definition-list");
|
|
33
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
34
34
|
class QuerySegmentBuilder {
|
|
35
35
|
constructor() {
|
|
36
36
|
this.alwaysJoins = [];
|
|
@@ -44,10 +44,6 @@ class QuerySegmentBuilder {
|
|
|
44
44
|
if (qp instanceof definition_list_1.DefinitionList) {
|
|
45
45
|
this.resultFS.pushFields(...qp.list);
|
|
46
46
|
}
|
|
47
|
-
else if (qp instanceof filters_1.Filter) {
|
|
48
|
-
const filterFS = qp.havingClause ? this.resultFS : this.inputFS;
|
|
49
|
-
this.filters.push(...qp.getFilterList(filterFS));
|
|
50
|
-
}
|
|
51
47
|
else if (qp instanceof top_1.Top) {
|
|
52
48
|
if (this.limit) {
|
|
53
49
|
qp.logError('limit-already-specified', 'Query operation already limited');
|
|
@@ -81,7 +77,11 @@ class QuerySegmentBuilder {
|
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
}
|
|
80
|
+
get compositeFieldUsage() {
|
|
81
|
+
return this.resultFS.compositeFieldUsage;
|
|
82
|
+
}
|
|
84
83
|
refineFrom(from, to) {
|
|
84
|
+
var _a;
|
|
85
85
|
if (from && from.type !== 'index' && from.type !== 'raw') {
|
|
86
86
|
if (!this.order) {
|
|
87
87
|
if (from.orderBy) {
|
|
@@ -117,6 +117,10 @@ class QuerySegmentBuilder {
|
|
|
117
117
|
if (this.alwaysJoins.length > 0) {
|
|
118
118
|
to.alwaysJoins = [...this.alwaysJoins];
|
|
119
119
|
}
|
|
120
|
+
const fromCompositeFieldUsage = from && (0, malloy_types_1.isQuerySegment)(from)
|
|
121
|
+
? (_a = from.compositeFieldUsage) !== null && _a !== void 0 ? _a : (0, composite_source_utils_1.emptyCompositeFieldUsage)()
|
|
122
|
+
: (0, composite_source_utils_1.emptyCompositeFieldUsage)();
|
|
123
|
+
to.compositeFieldUsage = (0, composite_source_utils_1.mergeCompositeFieldUsage)(fromCompositeFieldUsage, this.compositeFieldUsage);
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
exports.QuerySegmentBuilder = QuerySegmentBuilder;
|
|
@@ -23,14 +23,27 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.QueryBase = void 0;
|
|
26
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
27
|
+
const malloy_types_1 = require("../../../model/malloy_types");
|
|
26
28
|
const query_utils_1 = require("../query-utils");
|
|
27
29
|
const malloy_element_1 = require("../types/malloy-element");
|
|
28
30
|
class QueryBase extends malloy_element_1.MalloyElement {
|
|
29
31
|
query() {
|
|
30
|
-
const
|
|
32
|
+
const { inputStruct, query } = this.queryComp(true);
|
|
33
|
+
// TODO add an error if a raw/index query is done against a composite source
|
|
34
|
+
let compositeResolvedSourceDef = undefined;
|
|
35
|
+
if (query.pipeline[0] && (0, malloy_types_1.isQuerySegment)(query.pipeline[0])) {
|
|
36
|
+
const compositeFieldUsage = query.pipeline[0].compositeFieldUsage;
|
|
37
|
+
if (compositeFieldUsage !== undefined &&
|
|
38
|
+
!(0, composite_source_utils_1.isEmptyCompositeFieldUsage)(compositeFieldUsage)) {
|
|
39
|
+
const resolved = (0, composite_source_utils_1.resolveCompositeSources)(inputStruct, compositeFieldUsage);
|
|
40
|
+
compositeResolvedSourceDef = resolved.sourceDef;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
31
43
|
return {
|
|
32
|
-
...
|
|
33
|
-
|
|
44
|
+
...query,
|
|
45
|
+
compositeResolvedSourceDef,
|
|
46
|
+
pipeline: (0, query_utils_1.detectAndRemovePartialStages)(query.pipeline, this),
|
|
34
47
|
};
|
|
35
48
|
}
|
|
36
49
|
}
|
|
@@ -112,6 +112,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
|
112
112
|
type: retType,
|
|
113
113
|
location: this.location,
|
|
114
114
|
e: exprValue.value,
|
|
115
|
+
compositeFieldUsage: exprValue.compositeFieldUsage,
|
|
115
116
|
};
|
|
116
117
|
if ((0, granular_result_1.isGranularResult)(exprValue)) {
|
|
117
118
|
timeRet.timeframe = exprValue.timeframe;
|
|
@@ -129,6 +130,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
|
129
130
|
name: exprName,
|
|
130
131
|
location: this.location,
|
|
131
132
|
e: exprValue.value,
|
|
133
|
+
compositeFieldUsage: exprValue.compositeFieldUsage,
|
|
132
134
|
};
|
|
133
135
|
break;
|
|
134
136
|
}
|
|
@@ -141,6 +143,7 @@ class AtomicFieldDeclaration extends malloy_element_1.MalloyElement {
|
|
|
141
143
|
join: 'one',
|
|
142
144
|
fields,
|
|
143
145
|
e: exprValue.value,
|
|
146
|
+
compositeFieldUsage: exprValue.compositeFieldUsage,
|
|
144
147
|
dialect: exprFS.dialectName(),
|
|
145
148
|
};
|
|
146
149
|
break;
|
|
@@ -2,6 +2,7 @@ import { FilterCondition } from '../../../model/malloy_types';
|
|
|
2
2
|
import { ExpressionDef } from '../types/expression-def';
|
|
3
3
|
import { FieldSpace } from '../types/field-space';
|
|
4
4
|
import { ListOf, MalloyElement } from '../types/malloy-element';
|
|
5
|
+
import { QueryBuilder } from '../types/query-builder';
|
|
5
6
|
import { LegalRefinementStage, QueryPropertyInterface } from '../types/query-property-interface';
|
|
6
7
|
export declare class FilterElement extends MalloyElement {
|
|
7
8
|
readonly expr: ExpressionDef;
|
|
@@ -16,5 +17,7 @@ export declare class Filter extends ListOf<FilterElement> implements QueryProper
|
|
|
16
17
|
forceQueryClass: undefined;
|
|
17
18
|
queryRefinementStage: LegalRefinementStage;
|
|
18
19
|
set having(isHaving: boolean);
|
|
20
|
+
protected checkedFilterCondition(fs: FieldSpace, filter: FilterElement): FilterCondition | undefined;
|
|
19
21
|
getFilterList(fs: FieldSpace): FilterCondition[];
|
|
22
|
+
queryExecute(executeFor: QueryBuilder): void;
|
|
20
23
|
}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.Filter = exports.FilterElement = void 0;
|
|
26
26
|
const malloy_types_1 = require("../../../model/malloy_types");
|
|
27
|
+
const utils_1 = require("../../utils");
|
|
27
28
|
const malloy_element_1 = require("../types/malloy-element");
|
|
28
29
|
const query_property_interface_1 = require("../types/query-property-interface");
|
|
29
30
|
class FilterElement extends malloy_element_1.MalloyElement {
|
|
@@ -42,6 +43,7 @@ class FilterElement extends malloy_element_1.MalloyElement {
|
|
|
42
43
|
code: this.exprSrc,
|
|
43
44
|
e: { node: 'false' },
|
|
44
45
|
expressionType: 'scalar',
|
|
46
|
+
compositeFieldUsage: exprVal.compositeFieldUsage,
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
const exprCond = {
|
|
@@ -49,6 +51,7 @@ class FilterElement extends malloy_element_1.MalloyElement {
|
|
|
49
51
|
code: this.exprSrc,
|
|
50
52
|
e: exprVal.value,
|
|
51
53
|
expressionType: exprVal.expressionType,
|
|
54
|
+
compositeFieldUsage: exprVal.compositeFieldUsage,
|
|
52
55
|
};
|
|
53
56
|
return exprCond;
|
|
54
57
|
}
|
|
@@ -68,36 +71,49 @@ class Filter extends malloy_element_1.ListOf {
|
|
|
68
71
|
? query_property_interface_1.LegalRefinementStage.Tail
|
|
69
72
|
: query_property_interface_1.LegalRefinementStage.Head;
|
|
70
73
|
}
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
74
|
+
checkedFilterCondition(fs, filter) {
|
|
75
|
+
const fExpr = filter.filterCondition(fs);
|
|
76
|
+
// mtoy todo is having we never set then queryRefinementStage might be wrong
|
|
77
|
+
// ... calculations and aggregations must go last
|
|
78
|
+
// Aggregates are ALSO checked at SQL generation time, but checking
|
|
79
|
+
// here allows better reflection of errors back to user.
|
|
80
|
+
if (this.havingClause !== undefined) {
|
|
81
|
+
const isAggregate = (0, malloy_types_1.expressionIsAggregate)(fExpr.expressionType);
|
|
82
|
+
const isAnalytic = (0, malloy_types_1.expressionIsAnalytic)(fExpr.expressionType);
|
|
83
|
+
if (this.havingClause) {
|
|
84
|
+
if (isAnalytic) {
|
|
85
|
+
filter.logError('analytic-in-having', 'Analytic expressions are not allowed in `having:`');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (isAnalytic) {
|
|
91
|
+
filter.logError('analytic-in-where', 'Analytic expressions are not allowed in `where:`');
|
|
92
|
+
return;
|
|
87
93
|
}
|
|
88
|
-
else {
|
|
89
|
-
|
|
90
|
-
oneElement.logError('analytic-in-where', 'Analytic expressions are not allowed in `where:`');
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
else if (isAggregate) {
|
|
94
|
-
oneElement.logError('aggregate-in-where', 'Aggregate expressions are not allowed in `where:`; use `having:`');
|
|
95
|
-
}
|
|
94
|
+
else if (isAggregate) {
|
|
95
|
+
filter.logError('aggregate-in-where', 'Aggregate expressions are not allowed in `where:`; use `having:`');
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
checked.push(fExpr);
|
|
99
98
|
}
|
|
100
|
-
return
|
|
99
|
+
return fExpr;
|
|
100
|
+
}
|
|
101
|
+
getFilterList(fs) {
|
|
102
|
+
return this.list
|
|
103
|
+
.map(filter => this.checkedFilterCondition(fs, filter))
|
|
104
|
+
.filter(utils_1.isNotUndefined);
|
|
105
|
+
}
|
|
106
|
+
queryExecute(executeFor) {
|
|
107
|
+
const filterFS = this.havingClause
|
|
108
|
+
? executeFor.resultFS
|
|
109
|
+
: executeFor.inputFS;
|
|
110
|
+
for (const filter of this.list) {
|
|
111
|
+
const fExpr = this.checkedFilterCondition(filterFS, filter);
|
|
112
|
+
if (fExpr !== undefined) {
|
|
113
|
+
executeFor.filters.push(fExpr);
|
|
114
|
+
executeFor.resultFS.addCompositeFieldUserFromFilter(fExpr, filter);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
101
117
|
}
|
|
102
118
|
}
|
|
103
119
|
exports.Filter = Filter;
|
|
@@ -7,6 +7,7 @@ export declare class NestFieldDeclaration extends ViewFieldDeclaration implement
|
|
|
7
7
|
elementType: string;
|
|
8
8
|
queryRefinementStage: LegalRefinementStage;
|
|
9
9
|
forceQueryClass: QueryClass;
|
|
10
|
+
turtleDef: model.TurtleDef | undefined;
|
|
10
11
|
queryExecute(executeFor: QueryBuilder): void;
|
|
11
12
|
getFieldDef(fs: FieldSpace): model.TurtleDef;
|
|
12
13
|
}
|
|
@@ -32,21 +32,25 @@ class NestFieldDeclaration extends view_field_declaration_1.ViewFieldDeclaration
|
|
|
32
32
|
this.elementType = 'nest-field-declaration';
|
|
33
33
|
this.queryRefinementStage = query_property_interface_1.LegalRefinementStage.Single;
|
|
34
34
|
this.forceQueryClass = query_property_interface_1.QueryClass.Grouping;
|
|
35
|
+
this.turtleDef = undefined;
|
|
35
36
|
}
|
|
36
37
|
queryExecute(executeFor) {
|
|
37
38
|
executeFor.resultFS.pushFields(this);
|
|
38
39
|
}
|
|
39
40
|
getFieldDef(fs) {
|
|
41
|
+
if (this.turtleDef)
|
|
42
|
+
return this.turtleDef;
|
|
40
43
|
if (fs.isQueryFieldSpace()) {
|
|
41
44
|
const { pipeline, annotation } = this.view.pipelineComp(fs, fs.outputSpace());
|
|
42
45
|
const checkedPipeline = (0, query_utils_1.detectAndRemovePartialStages)(pipeline, this);
|
|
43
|
-
|
|
46
|
+
this.turtleDef = {
|
|
44
47
|
type: 'turtle',
|
|
45
48
|
name: this.name,
|
|
46
49
|
pipeline: checkedPipeline,
|
|
47
50
|
annotation: { ...this.note, inherits: annotation },
|
|
48
51
|
location: this.location,
|
|
49
52
|
};
|
|
53
|
+
return this.turtleDef;
|
|
50
54
|
}
|
|
51
55
|
throw this.internalError('Unexpected namespace for nest');
|
|
52
56
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Annotation, SourceDef } from '../../../model/malloy_types';
|
|
2
|
+
import { HasParameter } from '../parameters/has-parameter';
|
|
3
|
+
import { Source } from './source';
|
|
4
|
+
import { ParameterSpace } from '../field-space/parameter-space';
|
|
5
|
+
/**
|
|
6
|
+
* A Source that is a virtual union of the fields of other sources, choosing
|
|
7
|
+
* the first source that has all the fields at query time.
|
|
8
|
+
*/
|
|
9
|
+
export declare class CompositeSource extends Source {
|
|
10
|
+
readonly sources: Source[];
|
|
11
|
+
elementType: string;
|
|
12
|
+
currentAnnotation?: Annotation;
|
|
13
|
+
constructor(sources: Source[]);
|
|
14
|
+
getSourceDef(parameterSpace: ParameterSpace | undefined): SourceDef;
|
|
15
|
+
withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined): SourceDef;
|
|
16
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.CompositeSource = void 0;
|
|
10
|
+
const malloy_types_1 = require("../../../model/malloy_types");
|
|
11
|
+
const source_1 = require("./source");
|
|
12
|
+
/**
|
|
13
|
+
* A Source that is a virtual union of the fields of other sources, choosing
|
|
14
|
+
* the first source that has all the fields at query time.
|
|
15
|
+
*/
|
|
16
|
+
class CompositeSource extends source_1.Source {
|
|
17
|
+
constructor(sources) {
|
|
18
|
+
super({ sources });
|
|
19
|
+
this.sources = sources;
|
|
20
|
+
this.elementType = 'compositeSource';
|
|
21
|
+
}
|
|
22
|
+
getSourceDef(parameterSpace) {
|
|
23
|
+
return this.withParameters(parameterSpace, []);
|
|
24
|
+
}
|
|
25
|
+
withParameters(parameterSpace, pList) {
|
|
26
|
+
const sourceDefs = this.sources.map(source => source.withParameters(parameterSpace, pList));
|
|
27
|
+
const connection = sourceDefs[0].connection;
|
|
28
|
+
const dialect = sourceDefs[0].dialect;
|
|
29
|
+
const name = 'composite_source';
|
|
30
|
+
const fields = [];
|
|
31
|
+
const fieldNames = new Set();
|
|
32
|
+
this.sources.forEach((source, index) => {
|
|
33
|
+
var _a;
|
|
34
|
+
const sourceDef = sourceDefs[index];
|
|
35
|
+
// Check that connections all match; don't bother checking dialect, since it will
|
|
36
|
+
// match if the connection matches.
|
|
37
|
+
if (sourceDef.connection !== connection) {
|
|
38
|
+
source.logError('composite-source-connection-mismatch', `All sources in a composite source must share the same connection; connection \`${sourceDef.connection}\` differs from previous connection \`${connection}\``);
|
|
39
|
+
}
|
|
40
|
+
for (const field of sourceDef.fields) {
|
|
41
|
+
if (!(0, malloy_types_1.isAtomic)(field)) {
|
|
42
|
+
source.logWarning('composite-source-atomic-fields-only', `Only atomic fields are supported in composite sources; field \`${field.name}\` is not atomic and will be ignored`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const fieldName = (_a = field.as) !== null && _a !== void 0 ? _a : field.name;
|
|
46
|
+
if (!fieldNames.has(fieldName)) {
|
|
47
|
+
fieldNames.add(fieldName);
|
|
48
|
+
const compositeField = {
|
|
49
|
+
...field,
|
|
50
|
+
name: fieldName,
|
|
51
|
+
as: undefined,
|
|
52
|
+
e: { node: 'compositeField' },
|
|
53
|
+
compositeFieldUsage: { fields: [fieldName], joinedUsage: {} },
|
|
54
|
+
code: this.code,
|
|
55
|
+
location: this.codeLocation,
|
|
56
|
+
};
|
|
57
|
+
fields.push(compositeField);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
type: 'composite',
|
|
63
|
+
// TODO Use sourceRefs rather than sourceDefs when possible to avoid potential
|
|
64
|
+
// explosion of source defs...
|
|
65
|
+
sources: sourceDefs,
|
|
66
|
+
connection,
|
|
67
|
+
fields,
|
|
68
|
+
dialect,
|
|
69
|
+
name,
|
|
70
|
+
parameters: sourceDefs[0].parameters,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.CompositeSource = CompositeSource;
|
|
75
|
+
//# sourceMappingURL=composite-source.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InvokedStructRef, Parameter, SourceDef
|
|
1
|
+
import { InvokedStructRef, Parameter, SourceDef } from '../../../model/malloy_types';
|
|
2
2
|
import { MalloyElement } from '../types/malloy-element';
|
|
3
3
|
import { HasParameter } from '../parameters/has-parameter';
|
|
4
4
|
import { ParameterSpace } from '../field-space/parameter-space';
|
|
@@ -10,5 +10,5 @@ export declare abstract class Source extends MalloyElement {
|
|
|
10
10
|
abstract getSourceDef(parameterSpace: ParameterSpace | undefined): SourceDef;
|
|
11
11
|
structRef(parameterSpace: ParameterSpace | undefined): InvokedStructRef;
|
|
12
12
|
protected packParameters(pList: HasParameter[] | undefined): Record<string, Parameter> | undefined;
|
|
13
|
-
withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined):
|
|
13
|
+
withParameters(parameterSpace: ParameterSpace | undefined, pList: HasParameter[] | undefined): SourceDef;
|
|
14
14
|
}
|
|
@@ -95,6 +95,7 @@ class KeyJoin extends Join {
|
|
|
95
95
|
right: exprX.value,
|
|
96
96
|
},
|
|
97
97
|
};
|
|
98
|
+
inStruct.onCompositeFieldUsage = exprX.compositeFieldUsage;
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
else {
|
|
@@ -137,6 +138,7 @@ class ExpressionJoin extends Join {
|
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
140
|
inStruct.onExpression = exprX.value;
|
|
141
|
+
inStruct.onCompositeFieldUsage = exprX.compositeFieldUsage;
|
|
140
142
|
}
|
|
141
143
|
structDef(parameterSpace) {
|
|
142
144
|
var _a;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CompositeSource } from '../source-elements/composite-source';
|
|
2
|
+
import { SourceQueryElement } from './source-query-element';
|
|
3
|
+
/**
|
|
4
|
+
* e.g. `compose(source_a, source_b)`
|
|
5
|
+
*/
|
|
6
|
+
export declare class SQCompose extends SourceQueryElement {
|
|
7
|
+
readonly sources: SourceQueryElement[];
|
|
8
|
+
elementType: string;
|
|
9
|
+
asSource?: CompositeSource;
|
|
10
|
+
constructor(sources: SourceQueryElement[]);
|
|
11
|
+
getSource(): CompositeSource | undefined;
|
|
12
|
+
isSource(): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SQCompose = void 0;
|
|
10
|
+
const composite_source_1 = require("../source-elements/composite-source");
|
|
11
|
+
const source_query_element_1 = require("./source-query-element");
|
|
12
|
+
/**
|
|
13
|
+
* e.g. `compose(source_a, source_b)`
|
|
14
|
+
*/
|
|
15
|
+
class SQCompose extends source_query_element_1.SourceQueryElement {
|
|
16
|
+
constructor(sources) {
|
|
17
|
+
super({ sources });
|
|
18
|
+
this.sources = sources;
|
|
19
|
+
this.elementType = 'sq-compose';
|
|
20
|
+
}
|
|
21
|
+
getSource() {
|
|
22
|
+
if (this.asSource) {
|
|
23
|
+
return this.asSource;
|
|
24
|
+
}
|
|
25
|
+
const sources = this.sources.map(s => s.getSource());
|
|
26
|
+
if (sources.length === 0) {
|
|
27
|
+
this.sqLog('empty-composite-source', 'Composite source must have at least one input source');
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
else if (sources.length === 1) {
|
|
31
|
+
this.sqLog('unnecessary-composite-source', 'A composite source with one input is equivalent to that input', { severity: 'warn' });
|
|
32
|
+
}
|
|
33
|
+
if (hasNoUndefined(sources)) {
|
|
34
|
+
this.asSource = new composite_source_1.CompositeSource(sources);
|
|
35
|
+
this.has({ asSource: this.asSource });
|
|
36
|
+
return this.asSource;
|
|
37
|
+
}
|
|
38
|
+
this.sqLog('invalid-composite-source-input', 'All composite source inputs must be valid sources');
|
|
39
|
+
}
|
|
40
|
+
isSource() {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.SQCompose = SQCompose;
|
|
45
|
+
function hasNoUndefined(arr) {
|
|
46
|
+
return arr.every(s => s !== undefined);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=sq-compose.js.map
|
|
@@ -24,12 +24,18 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.atomicDef = exports.inspect = exports.typeEq = exports.typeIn = exports.eq = exports.any = exports.anyAtomicT = exports.aggregateBoolT = exports.viewT = exports.errorT = exports.boolT = exports.timestampT = exports.dateT = exports.stringT = exports.numberT = exports.nullT = void 0;
|
|
26
26
|
const model_1 = require("../../model");
|
|
27
|
+
const composite_source_utils_1 = require("../../model/composite_source_utils");
|
|
27
28
|
function mkTypeDesc(
|
|
28
29
|
// The problem is that record and array, as currently defined, require a dialect
|
|
29
30
|
// which isn't available. In retrospect the dialect shouldn't be in the type,
|
|
30
31
|
// it should only be in the field, which I wil do eventually.
|
|
31
32
|
dataType, expressionType = 'scalar', evalSpace = 'constant') {
|
|
32
|
-
return {
|
|
33
|
+
return {
|
|
34
|
+
type: dataType,
|
|
35
|
+
expressionType,
|
|
36
|
+
evalSpace,
|
|
37
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
38
|
+
};
|
|
33
39
|
}
|
|
34
40
|
exports.nullT = mkTypeDesc('null');
|
|
35
41
|
exports.numberT = mkTypeDesc('number');
|
|
@@ -24,12 +24,14 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.literalTimeResult = exports.literalExprValue = exports.computedErrorExprValue = exports.computedTimeResult = exports.computedExprValue = void 0;
|
|
26
26
|
const model_1 = require("../../../model");
|
|
27
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
27
28
|
function computedExprValue({ value, dataType, from, }) {
|
|
28
29
|
return {
|
|
29
30
|
...dataType,
|
|
30
31
|
value,
|
|
31
32
|
expressionType: (0, model_1.maxOfExpressionTypes)(from.map(e => e.expressionType)),
|
|
32
33
|
evalSpace: (0, model_1.mergeEvalSpaces)(...from.map(e => e.evalSpace)),
|
|
34
|
+
compositeFieldUsage: (0, composite_source_utils_1.mergeCompositeFieldUsage)(...from.map(e => e.compositeFieldUsage)),
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
exports.computedExprValue = computedExprValue;
|
|
@@ -40,6 +42,7 @@ function computedTimeResult({ value, dataType, from, timeframe, }) {
|
|
|
40
42
|
expressionType: xv.expressionType,
|
|
41
43
|
evalSpace: xv.evalSpace,
|
|
42
44
|
value: xv.value,
|
|
45
|
+
compositeFieldUsage: (0, composite_source_utils_1.mergeCompositeFieldUsage)(...from.map(e => e.compositeFieldUsage)),
|
|
43
46
|
};
|
|
44
47
|
if (timeframe) {
|
|
45
48
|
y.timeframe = timeframe;
|
|
@@ -67,6 +70,7 @@ function literalTimeResult({ value, dataType, timeframe, }) {
|
|
|
67
70
|
expressionType: xv.expressionType,
|
|
68
71
|
evalSpace: xv.evalSpace,
|
|
69
72
|
value: xv.value,
|
|
73
|
+
compositeFieldUsage: (0, composite_source_utils_1.emptyCompositeFieldUsage)(),
|
|
70
74
|
};
|
|
71
75
|
if (timeframe) {
|
|
72
76
|
y.timeframe = timeframe;
|
|
@@ -200,12 +200,11 @@ function getMorphicValue(mv, mt) {
|
|
|
200
200
|
return mv;
|
|
201
201
|
}
|
|
202
202
|
if (mv.morphic && mv.morphic[mt]) {
|
|
203
|
-
return {
|
|
204
|
-
type: mt,
|
|
203
|
+
return (0, expr_value_1.computedExprValue)({
|
|
204
|
+
dataType: { type: mt },
|
|
205
205
|
value: mv.morphic[mt],
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
};
|
|
206
|
+
from: [mv],
|
|
207
|
+
});
|
|
209
208
|
}
|
|
210
209
|
}
|
|
211
210
|
exports.getMorphicValue = getMorphicValue;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { PipeSegment } from '../../../model/malloy_types';
|
|
1
|
+
import { FilterCondition, PipeSegment } from '../../../model/malloy_types';
|
|
2
2
|
import { QueryProperty } from './query-property';
|
|
3
3
|
import { QueryInputSpace } from '../field-space/query-input-space';
|
|
4
4
|
import { QueryOperationSpace } from '../field-space/query-spaces';
|
|
5
5
|
export interface QueryBuilder {
|
|
6
|
+
filters: FilterCondition[];
|
|
6
7
|
type: 'grouping' | 'index' | 'project';
|
|
7
8
|
inputFS: QueryInputSpace;
|
|
8
9
|
resultFS: QueryOperationSpace;
|
|
@@ -24,14 +24,27 @@
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.SpaceField = void 0;
|
|
26
26
|
const space_entry_1 = require("./space-entry");
|
|
27
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
27
28
|
class SpaceField extends space_entry_1.SpaceEntry {
|
|
28
29
|
constructor() {
|
|
29
30
|
super(...arguments);
|
|
30
31
|
this.refType = 'field';
|
|
31
32
|
}
|
|
32
33
|
fieldTypeFromFieldDef(def) {
|
|
34
|
+
var _a, _b, _c;
|
|
33
35
|
const expressionType = def.expressionType || 'scalar';
|
|
34
|
-
const ref = {
|
|
36
|
+
const ref = {
|
|
37
|
+
...def,
|
|
38
|
+
expressionType,
|
|
39
|
+
evalSpace: 'input',
|
|
40
|
+
compositeFieldUsage:
|
|
41
|
+
// Use the composite field usage in the def if it exists, otherwise, if the
|
|
42
|
+
// field has an e whic is a composite field, then the composite field usage
|
|
43
|
+
// should be just the name of the field.
|
|
44
|
+
(_a = def.compositeFieldUsage) !== null && _a !== void 0 ? _a : (((_b = def.e) === null || _b === void 0 ? void 0 : _b.node) === 'compositeField'
|
|
45
|
+
? { fields: [(_c = def.as) !== null && _c !== void 0 ? _c : def.name], joinedUsage: {} }
|
|
46
|
+
: (0, composite_source_utils_1.emptyCompositeFieldUsage)()),
|
|
47
|
+
};
|
|
35
48
|
return ref;
|
|
36
49
|
}
|
|
37
50
|
getQueryFieldDef(_fs) {
|