@malloydata/malloy 0.0.22-dev230126015148 → 0.0.22-dev230206094309
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/package.json +2 -2
- package/dist/connection_utils.d.ts +0 -1
- package/dist/connection_utils.js +0 -66
- package/dist/dialect/dialect.d.ts +0 -66
- package/dist/dialect/dialect.js +0 -85
- package/dist/dialect/dialect_map.d.ts +0 -3
- package/dist/dialect/dialect_map.js +0 -45
- package/dist/dialect/duckdb.d.ts +0 -52
- package/dist/dialect/duckdb.js +0 -364
- package/dist/dialect/index.d.ts +0 -6
- package/dist/dialect/index.js +0 -37
- package/dist/dialect/postgres.d.ts +0 -52
- package/dist/dialect/postgres.js +0 -330
- package/dist/dialect/standardsql.d.ts +0 -49
- package/dist/dialect/standardsql.js +0 -381
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59
- package/dist/lang/ast/apply-expr.d.ts +0 -3
- package/dist/lang/ast/apply-expr.js +0 -34
- package/dist/lang/ast/ast-expr.d.ts +0 -206
- package/dist/lang/ast/ast-expr.js +0 -781
- package/dist/lang/ast/ast-main.d.ts +0 -915
- package/dist/lang/ast/ast-main.js +0 -3672
- package/dist/lang/ast/ast-time-expr.d.ts +0 -69
- package/dist/lang/ast/ast-time-expr.js +0 -389
- package/dist/lang/ast/ast-types.d.ts +0 -83
- package/dist/lang/ast/ast-types.js +0 -225
- package/dist/lang/ast/index.d.ts +0 -5
- package/dist/lang/ast/index.js +0 -44
- package/dist/lang/ast/time-utils.d.ts +0 -9
- package/dist/lang/ast/time-utils.js +0 -104
- package/dist/lang/field-utils.d.ts +0 -5
- package/dist/lang/field-utils.js +0 -43
- package/dist/lang/index.d.ts +0 -9
- package/dist/lang/index.js +0 -32
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +0 -165
- package/dist/lang/lib/Malloy/MalloyLexer.js +0 -1232
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +0 -1947
- package/dist/lang/lib/Malloy/MalloyParser.js +0 -11909
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -2022
- package/dist/lang/lib/Malloy/MalloyParserListener.js +0 -4
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -1274
- package/dist/lang/lib/Malloy/MalloyParserVisitor.js +0 -4
- package/dist/lang/parse-log.d.ts +0 -27
- package/dist/lang/parse-log.js +0 -51
- package/dist/lang/parse-malloy.d.ts +0 -236
- package/dist/lang/parse-malloy.js +0 -746
- package/dist/lang/parse-to-ast.d.ts +0 -155
- package/dist/lang/parse-to-ast.js +0 -990
- package/dist/lang/parse-tree-walkers/document-completion-walker.d.ts +0 -10
- package/dist/lang/parse-tree-walkers/document-completion-walker.js +0 -148
- package/dist/lang/parse-tree-walkers/document-help-context-walker.d.ts +0 -9
- package/dist/lang/parse-tree-walkers/document-help-context-walker.js +0 -107
- package/dist/lang/parse-tree-walkers/document-highlight-walker.d.ts +0 -83
- package/dist/lang/parse-tree-walkers/document-highlight-walker.js +0 -385
- package/dist/lang/parse-tree-walkers/document-symbol-walker.d.ts +0 -11
- package/dist/lang/parse-tree-walkers/document-symbol-walker.js +0 -182
- package/dist/lang/parse-tree-walkers/explore-query-walker.d.ts +0 -34
- package/dist/lang/parse-tree-walkers/explore-query-walker.js +0 -74
- package/dist/lang/parse-tree-walkers/find-external-references.d.ts +0 -11
- package/dist/lang/parse-tree-walkers/find-external-references.js +0 -61
- package/dist/lang/reference-list.d.ts +0 -10
- package/dist/lang/reference-list.js +0 -90
- package/dist/lang/space-field.d.ts +0 -17
- package/dist/lang/space-field.js +0 -127
- package/dist/lang/test/document-help-context-walker.spec.d.ts +0 -1
- package/dist/lang/test/document-help-context-walker.spec.js +0 -55
- package/dist/lang/test/document-symbol-walker.spec.d.ts +0 -1
- package/dist/lang/test/document-symbol-walker.spec.js +0 -110
- package/dist/lang/test/field-symbols.spec.d.ts +0 -1
- package/dist/lang/test/field-symbols.spec.js +0 -180
- package/dist/lang/test/parse.spec.d.ts +0 -14
- package/dist/lang/test/parse.spec.js +0 -2134
- package/dist/lang/test/test-translator.d.ts +0 -38
- package/dist/lang/test/test-translator.js +0 -344
- package/dist/lang/zone.d.ts +0 -57
- package/dist/lang/zone.js +0 -107
- package/dist/malloy.d.ts +0 -1146
- package/dist/malloy.js +0 -2413
- package/dist/model/index.d.ts +0 -2
- package/dist/model/index.js +0 -45
- package/dist/model/malloy_query.d.ts +0 -351
- package/dist/model/malloy_query.js +0 -3174
- package/dist/model/malloy_types.d.ts +0 -551
- package/dist/model/malloy_types.js +0 -378
- package/dist/model/sql_block.d.ts +0 -7
- package/dist/model/sql_block.js +0 -56
- package/dist/model/utils.d.ts +0 -22
- package/dist/model/utils.js +0 -102
- package/dist/run_sql_options.d.ts +0 -3
- package/dist/run_sql_options.js +0 -25
- package/dist/runtime_types.d.ts +0 -105
- package/dist/runtime_types.js +0 -25
|
@@ -1,3672 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.TurtleHeadedPipe = exports.ExistingQuery = exports.Index = exports.Turtles = exports.Limit = exports.Ordering = exports.OrderBy = exports.WildcardFieldReference = exports.RenameField = exports.PrimaryKey = exports.Document = exports.QOPDesc = exports.Aggregate = exports.GroupBy = exports.FieldListEdit = exports.ProjectStatement = exports.isFieldCollectionMember = exports.FieldReferences = exports.FieldReference = exports.FieldName = exports.Renames = exports.Dimensions = exports.Measures = exports.DeclareFields = exports.Filter = exports.FilterElement = exports.ExploreDesc = exports.isExploreProperty = exports.isQueryProperty = exports.Joins = exports.ExpressionJoin = exports.KeyJoin = exports.Join = exports.QuerySource = exports.SQLSource = exports.NamedSource = exports.ModelEntryReference = exports.IsValueBlock = exports.TableSource = exports.RefinedExplore = exports.DefineSourceList = exports.DefineExplore = exports.isDocStatement = exports.RunList = exports.Mallobj = exports.isExploreField = exports.Unimplemented = exports.ListOf = exports.MalloyElement = exports.ErrorFactory = void 0;
|
|
27
|
-
exports.RenameSpaceField = exports.QueryFieldAST = exports.ExpressionFieldFromAst = exports.AbstractParameter = exports.SpaceSeed = exports.DefinedParameter = exports.SpaceParam = exports.ColumnSpaceField = exports.QueryFieldStruct = exports.QueryField = exports.StructSpaceField = exports.SpaceField = exports.SpaceEntry = exports.ProjectFieldSpace = exports.ReduceFieldSpace = exports.ResultSpace = exports.DynamicSpace = exports.StaticSpace = exports.DefSpace = exports.Range = exports.ExprTime = exports.ExprDuration = exports.TypeMistmatch = exports.ExprGranularTime = exports.ExprCompare = exports.BinaryBoolean = exports.applyBinary = exports.FieldDeclaration = exports.ConstantSubExpression = exports.ExpressionDef = exports.SampleProperty = exports.SQLStatement = exports.SQLString = exports.ConstantParameter = exports.HasParameter = exports.ImportStatement = exports.JSONStructDef = exports.JSONElement = exports.Top = exports.AnonymousQuery = exports.DefineQuery = exports.DefineQueryList = exports.isQueryElement = exports.Nests = exports.isNestedQuery = exports.NestDefinition = exports.NestRefinement = exports.NestReference = exports.TurtleDecl = exports.FullQuery = void 0;
|
|
28
|
-
exports.IndexFieldSpace = exports.WildSpaceField = exports.ReferenceField = exports.QuerySpace = exports.JoinSpaceField = void 0;
|
|
29
|
-
/*
|
|
30
|
-
* Copyright 2023 Google LLC
|
|
31
|
-
*
|
|
32
|
-
* Permission is hereby granted, free of charge, to any person obtaining
|
|
33
|
-
* a copy of this software and associated documentation files
|
|
34
|
-
* (the "Software"), to deal in the Software without restriction,
|
|
35
|
-
* including without limitation the rights to use, copy, modify, merge,
|
|
36
|
-
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
37
|
-
* and to permit persons to whom the Software is furnished to do so,
|
|
38
|
-
* subject to the following conditions:
|
|
39
|
-
*
|
|
40
|
-
* The above copyright notice and this permission notice shall be
|
|
41
|
-
* included in all copies or substantial portions of the Software.
|
|
42
|
-
*
|
|
43
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
44
|
-
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
45
|
-
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
46
|
-
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
47
|
-
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
48
|
-
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
49
|
-
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
50
|
-
*/
|
|
51
|
-
const lodash_1 = require("lodash");
|
|
52
|
-
const model = __importStar(require("../../model/malloy_types"));
|
|
53
|
-
const dialect_map_1 = require("../../dialect/dialect_map");
|
|
54
|
-
const malloy_types_1 = require("../../model/malloy_types");
|
|
55
|
-
const malloy_query_1 = require("../../model/malloy_query");
|
|
56
|
-
const ast_types_1 = require("./ast-types");
|
|
57
|
-
const sql_block_1 = require("../../model/sql_block");
|
|
58
|
-
const util_1 = require("util");
|
|
59
|
-
const time_utils_1 = require("./time-utils");
|
|
60
|
-
const apply_expr_1 = require("./apply-expr");
|
|
61
|
-
const field_utils_1 = require("../field-utils");
|
|
62
|
-
/*
|
|
63
|
-
** For times when there is a code generation error but your function needs
|
|
64
|
-
** to return some kind of object to type properly, the ErrorFactory is
|
|
65
|
-
** here to help you.
|
|
66
|
-
*/
|
|
67
|
-
const theErrorStruct = {
|
|
68
|
-
type: "struct",
|
|
69
|
-
name: "~malformed~",
|
|
70
|
-
dialect: "~malformed~",
|
|
71
|
-
structSource: { type: "table", tablePath: "//undefined_error_table_path" },
|
|
72
|
-
structRelationship: {
|
|
73
|
-
type: "basetable",
|
|
74
|
-
connectionName: "//undefined_error_connection",
|
|
75
|
-
},
|
|
76
|
-
fields: [],
|
|
77
|
-
};
|
|
78
|
-
class ErrorFactory {
|
|
79
|
-
static get structDef() {
|
|
80
|
-
return { ...theErrorStruct };
|
|
81
|
-
}
|
|
82
|
-
static isErrorStructDef(s) {
|
|
83
|
-
return s.name.includes(theErrorStruct.name);
|
|
84
|
-
}
|
|
85
|
-
static get query() {
|
|
86
|
-
return {
|
|
87
|
-
structRef: ErrorFactory.structDef,
|
|
88
|
-
pipeline: [],
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
static get reduceSegment() {
|
|
92
|
-
return { type: "reduce", fields: [] };
|
|
93
|
-
}
|
|
94
|
-
static get projectSegment() {
|
|
95
|
-
return { type: "project", fields: [] };
|
|
96
|
-
}
|
|
97
|
-
static get indexSegment() {
|
|
98
|
-
return { type: "index", fields: [] };
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
exports.ErrorFactory = ErrorFactory;
|
|
102
|
-
function opOutputStruct(logTo, inputStruct, opDesc) {
|
|
103
|
-
const badModel = ErrorFactory.isErrorStructDef(inputStruct);
|
|
104
|
-
// Don't call into the model code with a broken model
|
|
105
|
-
if (!badModel) {
|
|
106
|
-
try {
|
|
107
|
-
return malloy_query_1.Segment.nextStructDef(inputStruct, opDesc);
|
|
108
|
-
}
|
|
109
|
-
catch (e) {
|
|
110
|
-
logTo.log(`INTERNAL ERROR model/Segment.nextStructDef: ${e.message}\n` +
|
|
111
|
-
`QUERY: ${(0, util_1.inspect)(opDesc, { breakLength: 72, depth: Infinity })}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return { ...ErrorFactory.structDef, dialect: inputStruct.dialect };
|
|
115
|
-
}
|
|
116
|
-
class MalloyElement {
|
|
117
|
-
/**
|
|
118
|
-
* @param kids All children passed to the constructor are not optional
|
|
119
|
-
*/
|
|
120
|
-
constructor(kids) {
|
|
121
|
-
this.children = {};
|
|
122
|
-
this.parent = null;
|
|
123
|
-
this.logged = new Set();
|
|
124
|
-
if (kids) {
|
|
125
|
-
this.has(kids);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Record all elements as children of this element, and mark this
|
|
130
|
-
* element as their parent.
|
|
131
|
-
* @param kids Some of these might be undefined, in which case they are ignored
|
|
132
|
-
*/
|
|
133
|
-
has(kids) {
|
|
134
|
-
for (const kidName in kids) {
|
|
135
|
-
const kidValue = kids[kidName];
|
|
136
|
-
if (kidValue !== undefined) {
|
|
137
|
-
this.children[kidName] = kidValue;
|
|
138
|
-
if (kidValue instanceof MalloyElement) {
|
|
139
|
-
kidValue.parent = this;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
for (const oneKid of kidValue) {
|
|
143
|
-
oneKid.parent = this;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
get location() {
|
|
150
|
-
if (this.codeLocation) {
|
|
151
|
-
return this.codeLocation;
|
|
152
|
-
}
|
|
153
|
-
if (this.parent) {
|
|
154
|
-
return this.parent.location;
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
url: this.sourceURL,
|
|
158
|
-
range: {
|
|
159
|
-
start: { line: 0, character: 0 },
|
|
160
|
-
end: { line: 0, character: 0 },
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
set location(loc) {
|
|
165
|
-
this.codeLocation = loc;
|
|
166
|
-
}
|
|
167
|
-
namespace() {
|
|
168
|
-
if (this instanceof Document) {
|
|
169
|
-
return this;
|
|
170
|
-
}
|
|
171
|
-
else if (this.parent) {
|
|
172
|
-
return this.parent.namespace();
|
|
173
|
-
}
|
|
174
|
-
throw new Error("INTERNAL ERROR: Translation without document scope");
|
|
175
|
-
}
|
|
176
|
-
modelEntry(reference) {
|
|
177
|
-
var _a;
|
|
178
|
-
const key = reference instanceof ModelEntryReference ? reference.name : reference;
|
|
179
|
-
const result = (_a = this.namespace()) === null || _a === void 0 ? void 0 : _a.getEntry(key);
|
|
180
|
-
if (reference instanceof ModelEntryReference) {
|
|
181
|
-
if ((result === null || result === void 0 ? void 0 : result.entry.type) === "query") {
|
|
182
|
-
this.addReference({
|
|
183
|
-
type: "queryReference",
|
|
184
|
-
text: key,
|
|
185
|
-
definition: result.entry,
|
|
186
|
-
location: reference.location,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
else if ((result === null || result === void 0 ? void 0 : result.entry.type) === "struct") {
|
|
190
|
-
if (model.isSQLBlock(result.entry)) {
|
|
191
|
-
this.addReference({
|
|
192
|
-
type: "sqlBlockReference",
|
|
193
|
-
text: key,
|
|
194
|
-
definition: result.entry,
|
|
195
|
-
location: reference.location,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
this.addReference({
|
|
200
|
-
type: "exploreReference",
|
|
201
|
-
text: key,
|
|
202
|
-
definition: result.entry,
|
|
203
|
-
location: reference.location,
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return result;
|
|
209
|
-
}
|
|
210
|
-
translator() {
|
|
211
|
-
if (this.xlate) {
|
|
212
|
-
return this.xlate;
|
|
213
|
-
}
|
|
214
|
-
if (this.parent) {
|
|
215
|
-
return this.parent.translator();
|
|
216
|
-
}
|
|
217
|
-
return undefined;
|
|
218
|
-
}
|
|
219
|
-
setTranslator(x) {
|
|
220
|
-
this.xlate = x;
|
|
221
|
-
}
|
|
222
|
-
addReference(reference) {
|
|
223
|
-
var _a;
|
|
224
|
-
(_a = this.translator()) === null || _a === void 0 ? void 0 : _a.addReference(reference);
|
|
225
|
-
}
|
|
226
|
-
get sourceURL() {
|
|
227
|
-
const trans = this.translator();
|
|
228
|
-
return (trans === null || trans === void 0 ? void 0 : trans.sourceURL) || "(missing)";
|
|
229
|
-
}
|
|
230
|
-
errorsExist() {
|
|
231
|
-
var _a;
|
|
232
|
-
const logger = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.logger;
|
|
233
|
-
if (logger) {
|
|
234
|
-
return logger.hasErrors();
|
|
235
|
-
}
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
log(message) {
|
|
239
|
-
if (this.codeLocation) {
|
|
240
|
-
/*
|
|
241
|
-
* If this element has a location, then don't report the same
|
|
242
|
-
* error message at the same location more than once
|
|
243
|
-
*/
|
|
244
|
-
if (this.logged.has(message)) {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
this.logged.add(message);
|
|
248
|
-
}
|
|
249
|
-
const trans = this.translator();
|
|
250
|
-
const msg = { at: this.location, message };
|
|
251
|
-
const logTo = trans === null || trans === void 0 ? void 0 : trans.root.logger;
|
|
252
|
-
if (logTo) {
|
|
253
|
-
logTo.log(msg);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
throw new Error(`Translation error (without error reporter):\n${JSON.stringify(msg, null, 2)}`);
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Mostly for debugging / testing. A string-y version of this object which
|
|
260
|
-
* is used to ask "are these two AST segments equal". Formatted so that
|
|
261
|
-
* errors would be human readable.
|
|
262
|
-
* @param indent only used for recursion
|
|
263
|
-
*/
|
|
264
|
-
toString() {
|
|
265
|
-
return this.stringify("", 0);
|
|
266
|
-
}
|
|
267
|
-
stringify(prefix, indent) {
|
|
268
|
-
const left = " ".repeat(indent);
|
|
269
|
-
let asString = `${left}${prefix}<${this.elementType}>${this.varInfo()}`;
|
|
270
|
-
for (const kidLabel of Object.keys(this.children)) {
|
|
271
|
-
const kiddle = this.children[kidLabel];
|
|
272
|
-
if (kiddle instanceof MalloyElement) {
|
|
273
|
-
asString += "\n" + kiddle.stringify(`${kidLabel}: `, indent + 2);
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
asString += `\n${left} ${kidLabel}: [`;
|
|
277
|
-
if (kiddle.length > 0) {
|
|
278
|
-
asString +=
|
|
279
|
-
"\n" +
|
|
280
|
-
kiddle.map((k) => k.stringify("", indent + 4)).join("\n") +
|
|
281
|
-
`\n${left} `;
|
|
282
|
-
}
|
|
283
|
-
asString += "]";
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return asString;
|
|
287
|
-
}
|
|
288
|
-
walk(callBack) {
|
|
289
|
-
callBack(this);
|
|
290
|
-
for (const kidLabel of Object.keys(this.children)) {
|
|
291
|
-
const kiddle = this.children[kidLabel];
|
|
292
|
-
if (kiddle instanceof MalloyElement) {
|
|
293
|
-
kiddle.walk(callBack);
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
for (const k of kiddle) {
|
|
297
|
-
k.walk(callBack);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
varInfo() {
|
|
303
|
-
let extra = "";
|
|
304
|
-
for (const [key, value] of Object.entries(this)) {
|
|
305
|
-
if (key !== "elementType") {
|
|
306
|
-
if (typeof value == "boolean") {
|
|
307
|
-
extra += value ? ` ${key}` : ` !${key}`;
|
|
308
|
-
}
|
|
309
|
-
else if (typeof value === "string" || typeof value === "number") {
|
|
310
|
-
extra += ` ${key}=${value}`;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return extra;
|
|
315
|
-
}
|
|
316
|
-
internalError(msg) {
|
|
317
|
-
this.log(`INTERNAL ERROR IN TRANSLATION: ${msg}`);
|
|
318
|
-
return new Error(msg);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
exports.MalloyElement = MalloyElement;
|
|
322
|
-
class ListOf extends MalloyElement {
|
|
323
|
-
constructor(listDesc, elements) {
|
|
324
|
-
super();
|
|
325
|
-
this.elementType = "genericElementList";
|
|
326
|
-
this.elements = elements;
|
|
327
|
-
if (this.elementType === "genericElementList") {
|
|
328
|
-
this.elementType = listDesc;
|
|
329
|
-
}
|
|
330
|
-
this.newContents();
|
|
331
|
-
}
|
|
332
|
-
newContents() {
|
|
333
|
-
this.has({ [this.elementType]: this.elements });
|
|
334
|
-
}
|
|
335
|
-
get list() {
|
|
336
|
-
return this.elements;
|
|
337
|
-
}
|
|
338
|
-
empty() {
|
|
339
|
-
return this.elements.length === 0;
|
|
340
|
-
}
|
|
341
|
-
notEmpty() {
|
|
342
|
-
return this.elements.length > 0;
|
|
343
|
-
}
|
|
344
|
-
push(...el) {
|
|
345
|
-
this.elements.push(...el);
|
|
346
|
-
this.newContents();
|
|
347
|
-
return this.elements;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
exports.ListOf = ListOf;
|
|
351
|
-
class Unimplemented extends MalloyElement {
|
|
352
|
-
constructor() {
|
|
353
|
-
super(...arguments);
|
|
354
|
-
this.elementType = "unimplemented";
|
|
355
|
-
this.reported = false;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
exports.Unimplemented = Unimplemented;
|
|
359
|
-
function getStructFieldDef(s, fn) {
|
|
360
|
-
return s.fields.find((fld) => (fld.as || fld.name) === fn);
|
|
361
|
-
}
|
|
362
|
-
function isFieldDecl(f) {
|
|
363
|
-
return (f instanceof FieldDeclaration ||
|
|
364
|
-
f instanceof Join ||
|
|
365
|
-
f instanceof TurtleDecl ||
|
|
366
|
-
f instanceof Turtles);
|
|
367
|
-
}
|
|
368
|
-
function isExploreField(f) {
|
|
369
|
-
return isFieldDecl(f) || f instanceof RenameField;
|
|
370
|
-
}
|
|
371
|
-
exports.isExploreField = isExploreField;
|
|
372
|
-
/**
|
|
373
|
-
* A "Mallobj" is a thing which you can run queries against, it has been called
|
|
374
|
-
* an "exploreable", or a "space".
|
|
375
|
-
*/
|
|
376
|
-
class Mallobj extends MalloyElement {
|
|
377
|
-
structRef() {
|
|
378
|
-
return this.structDef();
|
|
379
|
-
}
|
|
380
|
-
withParameters(pList) {
|
|
381
|
-
const before = this.structDef();
|
|
382
|
-
// TODO name collisions are flagged where?
|
|
383
|
-
if (pList) {
|
|
384
|
-
const parameters = { ...(before.parameters || {}) };
|
|
385
|
-
for (const hasP of pList) {
|
|
386
|
-
const pVal = hasP.parameter();
|
|
387
|
-
parameters[pVal.name] = pVal;
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
...before,
|
|
391
|
-
parameters,
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
return before;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
exports.Mallobj = Mallobj;
|
|
398
|
-
class QueryHeadStruct extends Mallobj {
|
|
399
|
-
constructor(fromRef) {
|
|
400
|
-
super();
|
|
401
|
-
this.fromRef = fromRef;
|
|
402
|
-
this.elementType = "internalOnlyQueryHead";
|
|
403
|
-
}
|
|
404
|
-
structRef() {
|
|
405
|
-
return this.fromRef;
|
|
406
|
-
}
|
|
407
|
-
structDef() {
|
|
408
|
-
if (model.refIsStructDef(this.fromRef)) {
|
|
409
|
-
return this.fromRef;
|
|
410
|
-
}
|
|
411
|
-
const ns = new NamedSource(this.fromRef);
|
|
412
|
-
this.has({ exploreReference: ns });
|
|
413
|
-
return ns.structDef();
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
class RunList extends ListOf {
|
|
417
|
-
constructor() {
|
|
418
|
-
super(...arguments);
|
|
419
|
-
this.execCursor = 0;
|
|
420
|
-
}
|
|
421
|
-
executeList(doc) {
|
|
422
|
-
while (this.execCursor < this.elements.length) {
|
|
423
|
-
if (doc.errorsExist()) {
|
|
424
|
-
// This stops cascading errors
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
const el = this.elements[this.execCursor];
|
|
428
|
-
if (isDocStatement(el)) {
|
|
429
|
-
const resp = el.execute(doc);
|
|
430
|
-
if (resp) {
|
|
431
|
-
return resp;
|
|
432
|
-
}
|
|
433
|
-
this.execCursor += 1;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return undefined;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
exports.RunList = RunList;
|
|
440
|
-
function isDocStatement(e) {
|
|
441
|
-
return e.execute !== undefined;
|
|
442
|
-
}
|
|
443
|
-
exports.isDocStatement = isDocStatement;
|
|
444
|
-
class DefineExplore extends MalloyElement {
|
|
445
|
-
constructor(name, mallobj, exported, params) {
|
|
446
|
-
super({ explore: mallobj });
|
|
447
|
-
this.name = name;
|
|
448
|
-
this.mallobj = mallobj;
|
|
449
|
-
this.exported = exported;
|
|
450
|
-
this.elementType = "defineExplore";
|
|
451
|
-
if (params) {
|
|
452
|
-
this.parameters = [];
|
|
453
|
-
for (const el of params) {
|
|
454
|
-
if (el instanceof HasParameter) {
|
|
455
|
-
this.parameters.push(el);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
this.log(`Unexpected element type in define statement: ${el.elementType}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
this.has({ parameters: this.parameters });
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
execute(doc) {
|
|
465
|
-
if (doc.modelEntry(this.name)) {
|
|
466
|
-
this.log(`Cannot redefine '${this.name}'`);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
const structDef = this.mallobj.withParameters(this.parameters);
|
|
470
|
-
if (ErrorFactory.isErrorStructDef(structDef)) {
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
doc.setEntry(this.name, {
|
|
474
|
-
entry: {
|
|
475
|
-
...structDef,
|
|
476
|
-
as: this.name,
|
|
477
|
-
location: this.location,
|
|
478
|
-
},
|
|
479
|
-
exported: this.exported,
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
exports.DefineExplore = DefineExplore;
|
|
485
|
-
class DefineSourceList extends RunList {
|
|
486
|
-
constructor(sourceList) {
|
|
487
|
-
super("defineSources", sourceList);
|
|
488
|
-
}
|
|
489
|
-
execute(doc) {
|
|
490
|
-
return this.executeList(doc);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
exports.DefineSourceList = DefineSourceList;
|
|
494
|
-
/**
|
|
495
|
-
* A Mallobj made from a source and a set of refinements
|
|
496
|
-
*/
|
|
497
|
-
class RefinedExplore extends Mallobj {
|
|
498
|
-
constructor(source, refinement) {
|
|
499
|
-
super({ source, refinement });
|
|
500
|
-
this.source = source;
|
|
501
|
-
this.refinement = refinement;
|
|
502
|
-
this.elementType = "refinedExplore";
|
|
503
|
-
}
|
|
504
|
-
structDef() {
|
|
505
|
-
return this.withParameters([]);
|
|
506
|
-
}
|
|
507
|
-
withParameters(pList) {
|
|
508
|
-
let primaryKey;
|
|
509
|
-
let fieldListEdit;
|
|
510
|
-
const fields = [];
|
|
511
|
-
const filters = [];
|
|
512
|
-
for (const el of this.refinement.list) {
|
|
513
|
-
const errTo = el;
|
|
514
|
-
if (el instanceof PrimaryKey) {
|
|
515
|
-
if (primaryKey) {
|
|
516
|
-
primaryKey.log("Primary key already defined");
|
|
517
|
-
el.log("Primary key redefined");
|
|
518
|
-
}
|
|
519
|
-
primaryKey = el;
|
|
520
|
-
}
|
|
521
|
-
else if (el instanceof FieldListEdit) {
|
|
522
|
-
if (fieldListEdit) {
|
|
523
|
-
fieldListEdit.log("Too many accept/except statements");
|
|
524
|
-
el.log("Too many accept/except statements");
|
|
525
|
-
}
|
|
526
|
-
fieldListEdit = el;
|
|
527
|
-
}
|
|
528
|
-
else if (el instanceof DeclareFields ||
|
|
529
|
-
el instanceof Joins ||
|
|
530
|
-
el instanceof Turtles ||
|
|
531
|
-
el instanceof Renames) {
|
|
532
|
-
fields.push(...el.list);
|
|
533
|
-
}
|
|
534
|
-
else if (el instanceof Filter) {
|
|
535
|
-
filters.push(el);
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
538
|
-
errTo.log(`Unexpected explore property: '${errTo.elementType}'`);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
const from = (0, lodash_1.cloneDeep)(this.source.structDef());
|
|
542
|
-
if (primaryKey) {
|
|
543
|
-
from.primaryKey = primaryKey.field.name;
|
|
544
|
-
}
|
|
545
|
-
const fs = DynamicSpace.filteredFrom(from, fieldListEdit);
|
|
546
|
-
fs.addField(...fields);
|
|
547
|
-
if (pList) {
|
|
548
|
-
fs.addParameters(pList);
|
|
549
|
-
}
|
|
550
|
-
if (primaryKey) {
|
|
551
|
-
const keyDef = primaryKey.field.getField(fs);
|
|
552
|
-
if (keyDef.error) {
|
|
553
|
-
primaryKey.log(keyDef.error);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
const retStruct = fs.structDef();
|
|
557
|
-
const filterList = retStruct.filterList || [];
|
|
558
|
-
let moreFilters = false;
|
|
559
|
-
for (const filter of filters) {
|
|
560
|
-
for (const el of filter.list) {
|
|
561
|
-
const fc = el.filterExpression(fs);
|
|
562
|
-
if (model.expressionIsCalculation(fc.expressionType)) {
|
|
563
|
-
el.log("Can't use aggregate computations in top level filters");
|
|
564
|
-
}
|
|
565
|
-
else {
|
|
566
|
-
filterList.push(fc);
|
|
567
|
-
moreFilters = true;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
if (moreFilters) {
|
|
572
|
-
return { ...retStruct, filterList };
|
|
573
|
-
}
|
|
574
|
-
return retStruct;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
exports.RefinedExplore = RefinedExplore;
|
|
578
|
-
class TableSource extends Mallobj {
|
|
579
|
-
constructor(name) {
|
|
580
|
-
super();
|
|
581
|
-
this.name = name;
|
|
582
|
-
this.elementType = "tableSource";
|
|
583
|
-
}
|
|
584
|
-
structDef() {
|
|
585
|
-
var _a;
|
|
586
|
-
const tableDefEntry = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.schemaZone.getEntry(this.name);
|
|
587
|
-
let msg = `Schema read failure for table '${this.name}'`;
|
|
588
|
-
if (tableDefEntry) {
|
|
589
|
-
if (tableDefEntry.status == "present") {
|
|
590
|
-
tableDefEntry.value.location = this.location;
|
|
591
|
-
tableDefEntry.value.fields.forEach((field) => (field.location = this.location));
|
|
592
|
-
return {
|
|
593
|
-
...tableDefEntry.value,
|
|
594
|
-
fields: tableDefEntry.value.fields.map((field) => ({
|
|
595
|
-
...field,
|
|
596
|
-
location: this.location,
|
|
597
|
-
})),
|
|
598
|
-
location: this.location,
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
if (tableDefEntry.status == "error") {
|
|
602
|
-
msg = tableDefEntry.message;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
this.log(msg);
|
|
606
|
-
return ErrorFactory.structDef;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
exports.TableSource = TableSource;
|
|
610
|
-
class IsValueBlock extends MalloyElement {
|
|
611
|
-
constructor(isMap) {
|
|
612
|
-
super();
|
|
613
|
-
this.isMap = isMap;
|
|
614
|
-
this.elementType = "isValueBlock";
|
|
615
|
-
this.has(isMap);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
exports.IsValueBlock = IsValueBlock;
|
|
619
|
-
class ModelEntryReference extends MalloyElement {
|
|
620
|
-
constructor(name) {
|
|
621
|
-
super();
|
|
622
|
-
this.name = name;
|
|
623
|
-
this.elementType = "modelEntryReference";
|
|
624
|
-
}
|
|
625
|
-
get refString() {
|
|
626
|
-
return this.name;
|
|
627
|
-
}
|
|
628
|
-
toString() {
|
|
629
|
-
return this.refString;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
exports.ModelEntryReference = ModelEntryReference;
|
|
633
|
-
class NamedSource extends Mallobj {
|
|
634
|
-
constructor(ref, paramValues = {}) {
|
|
635
|
-
super();
|
|
636
|
-
this.ref = ref;
|
|
637
|
-
this.elementType = "namedSource";
|
|
638
|
-
if (paramValues && Object.keys(paramValues).length > 0) {
|
|
639
|
-
this.isBlock = new IsValueBlock(paramValues);
|
|
640
|
-
this.has({ parameterValues: this.isBlock });
|
|
641
|
-
}
|
|
642
|
-
if (ref instanceof ModelEntryReference) {
|
|
643
|
-
this.has({ ref });
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
get refName() {
|
|
647
|
-
return this.ref instanceof ModelEntryReference ? this.ref.name : this.ref;
|
|
648
|
-
}
|
|
649
|
-
structRef() {
|
|
650
|
-
if (this.isBlock) {
|
|
651
|
-
return this.structDef();
|
|
652
|
-
}
|
|
653
|
-
const modelEnt = this.modelEntry(this.ref);
|
|
654
|
-
if (modelEnt && !modelEnt.exported) {
|
|
655
|
-
// If we are not exporting the referenced structdef, don't
|
|
656
|
-
// use the reference
|
|
657
|
-
return this.structDef();
|
|
658
|
-
}
|
|
659
|
-
return this.refName;
|
|
660
|
-
}
|
|
661
|
-
modelStruct() {
|
|
662
|
-
const modelEnt = this.modelEntry(this.ref);
|
|
663
|
-
const entry = modelEnt === null || modelEnt === void 0 ? void 0 : modelEnt.entry;
|
|
664
|
-
if (!entry) {
|
|
665
|
-
const undefMsg = `Undefined source '${this.refName}'`;
|
|
666
|
-
(this.ref instanceof ModelEntryReference ? this.ref : this).log(undefMsg);
|
|
667
|
-
return;
|
|
668
|
-
}
|
|
669
|
-
if (entry.type === "query") {
|
|
670
|
-
this.log(`Must use 'from()' for query source '${this.refName}`);
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
else if (modelEnt.sqlType) {
|
|
674
|
-
this.log(`Must use 'from_sql()' for sql source '${this.refName}`);
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
return { ...entry };
|
|
678
|
-
}
|
|
679
|
-
structDef() {
|
|
680
|
-
/*
|
|
681
|
-
Can't really generate the callback list until after all the
|
|
682
|
-
things before me are translated, and that kinda screws up
|
|
683
|
-
the translation process, so that might be a better place
|
|
684
|
-
to start the next step, because how that gets done might
|
|
685
|
-
make any code I write which ignores the translation problem
|
|
686
|
-
kind of meaningless.
|
|
687
|
-
|
|
688
|
-
Maybe the output of a translation is something which describes
|
|
689
|
-
all the missing data, and then there is a "link" step where you
|
|
690
|
-
can do other translations and link them into a partial translation
|
|
691
|
-
which might result in a full translation.
|
|
692
|
-
*/
|
|
693
|
-
var _a;
|
|
694
|
-
const ret = this.modelStruct();
|
|
695
|
-
if (!ret) {
|
|
696
|
-
const notFound = ErrorFactory.structDef;
|
|
697
|
-
const err = `${this.refName}-undefined`;
|
|
698
|
-
notFound.name = notFound.name + err;
|
|
699
|
-
notFound.dialect = notFound.dialect + err;
|
|
700
|
-
return notFound;
|
|
701
|
-
}
|
|
702
|
-
const declared = { ...ret.parameters } || {};
|
|
703
|
-
const makeWith = ((_a = this.isBlock) === null || _a === void 0 ? void 0 : _a.isMap) || {};
|
|
704
|
-
for (const [pName, pExpr] of Object.entries(makeWith)) {
|
|
705
|
-
const decl = declared[pName];
|
|
706
|
-
// const pVal = pExpr.constantValue();
|
|
707
|
-
if (!decl) {
|
|
708
|
-
this.log(`Value given for undeclared parameter '${pName}`);
|
|
709
|
-
}
|
|
710
|
-
else {
|
|
711
|
-
if (model.isValueParameter(decl)) {
|
|
712
|
-
if (decl.constant) {
|
|
713
|
-
pExpr.log(`Cannot override constant parameter ${pName}`);
|
|
714
|
-
}
|
|
715
|
-
else {
|
|
716
|
-
const pVal = pExpr.constantValue();
|
|
717
|
-
let value = pVal.value;
|
|
718
|
-
if (pVal.dataType !== decl.type) {
|
|
719
|
-
value = (0, time_utils_1.castTo)(decl.type, pVal.value, true);
|
|
720
|
-
}
|
|
721
|
-
decl.value = value;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
else {
|
|
725
|
-
// TODO type checking here -- except I am still not sure what
|
|
726
|
-
// datatype half conditions have ..
|
|
727
|
-
decl.condition = pExpr.constantCondition(decl.type).value;
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
for (const checkDef in ret.parameters) {
|
|
732
|
-
if (!model.paramHasValue(declared[checkDef])) {
|
|
733
|
-
this.log(`Value not provided for required parameter ${checkDef}`);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
return ret;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
exports.NamedSource = NamedSource;
|
|
740
|
-
class SQLSource extends NamedSource {
|
|
741
|
-
constructor() {
|
|
742
|
-
super(...arguments);
|
|
743
|
-
this.elementType = "sqlSource";
|
|
744
|
-
}
|
|
745
|
-
structRef() {
|
|
746
|
-
return this.structDef();
|
|
747
|
-
}
|
|
748
|
-
modelStruct() {
|
|
749
|
-
const modelEnt = this.modelEntry(this.ref);
|
|
750
|
-
const entry = modelEnt === null || modelEnt === void 0 ? void 0 : modelEnt.entry;
|
|
751
|
-
if (!entry) {
|
|
752
|
-
this.log(`Undefined from_sql source '${this.refName}'`);
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
if (entry.type === "query") {
|
|
756
|
-
this.log(`Cannot use 'from_sql()' to explore query '${this.refName}'`);
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
else if (!modelEnt.sqlType) {
|
|
760
|
-
this.log(`Cannot use 'from_sql()' to explore '${this.refName}'`);
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
return entry;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
exports.SQLSource = SQLSource;
|
|
767
|
-
class QuerySource extends Mallobj {
|
|
768
|
-
constructor(query) {
|
|
769
|
-
super({ query });
|
|
770
|
-
this.query = query;
|
|
771
|
-
this.elementType = "querySource";
|
|
772
|
-
}
|
|
773
|
-
structDef() {
|
|
774
|
-
const comp = this.query.queryComp();
|
|
775
|
-
const queryStruct = comp.outputStruct;
|
|
776
|
-
queryStruct.structSource = { type: "query", query: comp.query };
|
|
777
|
-
return queryStruct;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
exports.QuerySource = QuerySource;
|
|
781
|
-
class Join extends MalloyElement {
|
|
782
|
-
}
|
|
783
|
-
exports.Join = Join;
|
|
784
|
-
class KeyJoin extends Join {
|
|
785
|
-
constructor(name, source, keyExpr) {
|
|
786
|
-
super({ name, source, keyExpr });
|
|
787
|
-
this.name = name;
|
|
788
|
-
this.source = source;
|
|
789
|
-
this.keyExpr = keyExpr;
|
|
790
|
-
this.elementType = "joinOnKey";
|
|
791
|
-
}
|
|
792
|
-
structDef() {
|
|
793
|
-
const sourceDef = this.source.structDef();
|
|
794
|
-
const joinStruct = {
|
|
795
|
-
...sourceDef,
|
|
796
|
-
structRelationship: {
|
|
797
|
-
type: "one",
|
|
798
|
-
onExpression: ["('join fixup'='not done yet')"],
|
|
799
|
-
},
|
|
800
|
-
location: this.location,
|
|
801
|
-
};
|
|
802
|
-
if (sourceDef.structSource.type === "query") {
|
|
803
|
-
// the name from query does not need to be preserved
|
|
804
|
-
joinStruct.name = this.name.refString;
|
|
805
|
-
}
|
|
806
|
-
else {
|
|
807
|
-
joinStruct.as = this.name.refString;
|
|
808
|
-
}
|
|
809
|
-
return joinStruct;
|
|
810
|
-
}
|
|
811
|
-
fixupJoinOn(outer, inStruct) {
|
|
812
|
-
const exprX = this.keyExpr.getExpression(outer);
|
|
813
|
-
if (inStruct.primaryKey) {
|
|
814
|
-
const pkey = inStruct.fields.find((f) => (f.as || f.name) === inStruct.primaryKey);
|
|
815
|
-
if (pkey) {
|
|
816
|
-
if (pkey.type === exprX.dataType) {
|
|
817
|
-
inStruct.structRelationship = {
|
|
818
|
-
type: "one",
|
|
819
|
-
onExpression: [
|
|
820
|
-
{ type: "field", path: `${this.name}.${inStruct.primaryKey}` },
|
|
821
|
-
"=",
|
|
822
|
-
...exprX.value,
|
|
823
|
-
],
|
|
824
|
-
};
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
else {
|
|
828
|
-
this.log(`join_one: with type mismatch with primary key: ${exprX.dataType}/${pkey.type}`);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
else {
|
|
832
|
-
this.log(`join_one: Primary key '${pkey}' not found in source`);
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
else {
|
|
836
|
-
this.log(`join_one: Cannot use with unless source has a primary key`);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
exports.KeyJoin = KeyJoin;
|
|
841
|
-
class ExpressionJoin extends Join {
|
|
842
|
-
constructor(name, source) {
|
|
843
|
-
super({ name, source });
|
|
844
|
-
this.name = name;
|
|
845
|
-
this.source = source;
|
|
846
|
-
this.elementType = "joinOnExpr";
|
|
847
|
-
this.joinType = "one";
|
|
848
|
-
}
|
|
849
|
-
set joinOn(joinExpr) {
|
|
850
|
-
this.expr = joinExpr;
|
|
851
|
-
this.has({ on: joinExpr });
|
|
852
|
-
}
|
|
853
|
-
get joinOn() {
|
|
854
|
-
return this.expr;
|
|
855
|
-
}
|
|
856
|
-
fixupJoinOn(outer, inStruct) {
|
|
857
|
-
if (this.expr == undefined) {
|
|
858
|
-
return;
|
|
859
|
-
}
|
|
860
|
-
const exprX = this.expr.getExpression(outer);
|
|
861
|
-
if (exprX.dataType !== "boolean") {
|
|
862
|
-
this.log("join conditions must be boolean expressions");
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
const joinRel = inStruct.structRelationship;
|
|
866
|
-
if (model.isJoinOn(joinRel)) {
|
|
867
|
-
joinRel.onExpression = (0, ast_types_1.compressExpr)(exprX.value);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
structDef() {
|
|
871
|
-
const sourceDef = this.source.structDef();
|
|
872
|
-
const joinStruct = {
|
|
873
|
-
...sourceDef,
|
|
874
|
-
structRelationship: { type: this.joinType },
|
|
875
|
-
location: this.location,
|
|
876
|
-
};
|
|
877
|
-
if (sourceDef.structSource.type === "query") {
|
|
878
|
-
// the name from query does not need to be preserved
|
|
879
|
-
joinStruct.name = this.name.refString;
|
|
880
|
-
delete joinStruct.as;
|
|
881
|
-
}
|
|
882
|
-
else {
|
|
883
|
-
joinStruct.as = this.name.refString;
|
|
884
|
-
}
|
|
885
|
-
return joinStruct;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
exports.ExpressionJoin = ExpressionJoin;
|
|
889
|
-
class Joins extends ListOf {
|
|
890
|
-
constructor(joins) {
|
|
891
|
-
super("joinList", joins);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
exports.Joins = Joins;
|
|
895
|
-
function isQueryProperty(q) {
|
|
896
|
-
return (q instanceof Ordering ||
|
|
897
|
-
q instanceof Top ||
|
|
898
|
-
q instanceof Limit ||
|
|
899
|
-
q instanceof Filter ||
|
|
900
|
-
q instanceof Index ||
|
|
901
|
-
q instanceof SampleProperty ||
|
|
902
|
-
q instanceof Joins ||
|
|
903
|
-
q instanceof DeclareFields ||
|
|
904
|
-
q instanceof ProjectStatement ||
|
|
905
|
-
q instanceof Aggregate ||
|
|
906
|
-
q instanceof Nests ||
|
|
907
|
-
isNestedQuery(q) ||
|
|
908
|
-
q instanceof GroupBy);
|
|
909
|
-
}
|
|
910
|
-
exports.isQueryProperty = isQueryProperty;
|
|
911
|
-
function isExploreProperty(p) {
|
|
912
|
-
return (p instanceof Filter ||
|
|
913
|
-
p instanceof Joins ||
|
|
914
|
-
p instanceof DeclareFields ||
|
|
915
|
-
p instanceof FieldListEdit ||
|
|
916
|
-
p instanceof Renames ||
|
|
917
|
-
p instanceof PrimaryKey ||
|
|
918
|
-
p instanceof Turtles);
|
|
919
|
-
}
|
|
920
|
-
exports.isExploreProperty = isExploreProperty;
|
|
921
|
-
class ExploreDesc extends ListOf {
|
|
922
|
-
constructor(props) {
|
|
923
|
-
super("exploreDesc", props);
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
exports.ExploreDesc = ExploreDesc;
|
|
927
|
-
class FilterElement extends MalloyElement {
|
|
928
|
-
constructor(expr, exprSrc) {
|
|
929
|
-
super({ expr });
|
|
930
|
-
this.expr = expr;
|
|
931
|
-
this.exprSrc = exprSrc;
|
|
932
|
-
this.elementType = "filterElement";
|
|
933
|
-
}
|
|
934
|
-
filterExpression(fs) {
|
|
935
|
-
const exprVal = this.expr.getExpression(fs);
|
|
936
|
-
if (exprVal.dataType !== "boolean") {
|
|
937
|
-
this.expr.log("Filter expression must have boolean value");
|
|
938
|
-
return {
|
|
939
|
-
code: this.exprSrc,
|
|
940
|
-
expression: ["_FILTER_MUST_RETURN_BOOLEAN_"],
|
|
941
|
-
expressionType: "scalar",
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
const exprCond = {
|
|
945
|
-
code: this.exprSrc,
|
|
946
|
-
expression: (0, ast_types_1.compressExpr)(exprVal.value),
|
|
947
|
-
expressionType: exprVal.expressionType,
|
|
948
|
-
};
|
|
949
|
-
return exprCond;
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
exports.FilterElement = FilterElement;
|
|
953
|
-
class Filter extends ListOf {
|
|
954
|
-
constructor(elements = []) {
|
|
955
|
-
super("filterElements", elements);
|
|
956
|
-
this.elementType = "filter";
|
|
957
|
-
}
|
|
958
|
-
set having(isHaving) {
|
|
959
|
-
this.elementType = isHaving ? "having" : "where";
|
|
960
|
-
}
|
|
961
|
-
getFilterList(fs) {
|
|
962
|
-
const checked = [];
|
|
963
|
-
for (const oneElement of this.list) {
|
|
964
|
-
const fExpr = oneElement.filterExpression(fs);
|
|
965
|
-
// Aggregates are ALSO checked at SQL generation time, but checking
|
|
966
|
-
// here allows better reflection of errors back to user.
|
|
967
|
-
if (this.havingClause !== undefined) {
|
|
968
|
-
if (this.havingClause) {
|
|
969
|
-
if (model.expressionIsCalculation(fExpr.expressionType)) {
|
|
970
|
-
oneElement.log("Aggregate or Analytical expression expected in HAVING filter");
|
|
971
|
-
continue;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
if (fExpr.expressionType !== "scalar") {
|
|
976
|
-
oneElement.log("Aggregate or Analytical expressions not allowed in WHERE");
|
|
977
|
-
continue;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
checked.push(fExpr);
|
|
982
|
-
}
|
|
983
|
-
return checked;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
exports.Filter = Filter;
|
|
987
|
-
class DeclareFields extends ListOf {
|
|
988
|
-
constructor(fields, fieldType = "declare") {
|
|
989
|
-
super(fieldType, fields);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
exports.DeclareFields = DeclareFields;
|
|
993
|
-
class Measures extends DeclareFields {
|
|
994
|
-
constructor(measures) {
|
|
995
|
-
super(measures, "measure");
|
|
996
|
-
for (const dim of measures) {
|
|
997
|
-
dim.isMeasure = true;
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
exports.Measures = Measures;
|
|
1002
|
-
class Dimensions extends DeclareFields {
|
|
1003
|
-
constructor(dimensions) {
|
|
1004
|
-
super(dimensions, "dimension");
|
|
1005
|
-
for (const dim of dimensions) {
|
|
1006
|
-
dim.isMeasure = false;
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
exports.Dimensions = Dimensions;
|
|
1011
|
-
class Renames extends ListOf {
|
|
1012
|
-
constructor(renames) {
|
|
1013
|
-
super("renameField", renames);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
exports.Renames = Renames;
|
|
1017
|
-
class FieldName extends MalloyElement {
|
|
1018
|
-
constructor(name) {
|
|
1019
|
-
super();
|
|
1020
|
-
this.name = name;
|
|
1021
|
-
this.elementType = "fieldName";
|
|
1022
|
-
}
|
|
1023
|
-
get refString() {
|
|
1024
|
-
return this.name;
|
|
1025
|
-
}
|
|
1026
|
-
toString() {
|
|
1027
|
-
return this.refString;
|
|
1028
|
-
}
|
|
1029
|
-
getField(fs) {
|
|
1030
|
-
return fs.lookup([this]);
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
exports.FieldName = FieldName;
|
|
1034
|
-
class FieldReference extends ListOf {
|
|
1035
|
-
constructor(names) {
|
|
1036
|
-
super("fieldReference", names);
|
|
1037
|
-
this.elementType = "fieldReference";
|
|
1038
|
-
}
|
|
1039
|
-
get refString() {
|
|
1040
|
-
return this.list.map((n) => n.refString).join(".");
|
|
1041
|
-
}
|
|
1042
|
-
get outputName() {
|
|
1043
|
-
const last = this.list[this.list.length - 1];
|
|
1044
|
-
return last.refString;
|
|
1045
|
-
}
|
|
1046
|
-
get sourceString() {
|
|
1047
|
-
if (this.list.length > 1) {
|
|
1048
|
-
return this.list
|
|
1049
|
-
.slice(0, -1)
|
|
1050
|
-
.map((n) => n.refString)
|
|
1051
|
-
.join(".");
|
|
1052
|
-
}
|
|
1053
|
-
return undefined;
|
|
1054
|
-
}
|
|
1055
|
-
get nameString() {
|
|
1056
|
-
return this.list[this.list.length - 1].refString;
|
|
1057
|
-
}
|
|
1058
|
-
getField(fs) {
|
|
1059
|
-
return fs.lookup(this.list);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
exports.FieldReference = FieldReference;
|
|
1063
|
-
class FieldReferences extends ListOf {
|
|
1064
|
-
constructor(members) {
|
|
1065
|
-
super("fieldReferenceList", members);
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
exports.FieldReferences = FieldReferences;
|
|
1069
|
-
function isFieldCollectionMember(el) {
|
|
1070
|
-
return (el instanceof FieldReference ||
|
|
1071
|
-
el instanceof WildcardFieldReference ||
|
|
1072
|
-
el instanceof FieldDeclaration);
|
|
1073
|
-
}
|
|
1074
|
-
exports.isFieldCollectionMember = isFieldCollectionMember;
|
|
1075
|
-
class ProjectStatement extends ListOf {
|
|
1076
|
-
constructor(members) {
|
|
1077
|
-
super("fieldCollection", members);
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
exports.ProjectStatement = ProjectStatement;
|
|
1081
|
-
class FieldListEdit extends MalloyElement {
|
|
1082
|
-
constructor(edit, refs) {
|
|
1083
|
-
super({ refs });
|
|
1084
|
-
this.edit = edit;
|
|
1085
|
-
this.refs = refs;
|
|
1086
|
-
this.elementType = "fieldListEdit";
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
exports.FieldListEdit = FieldListEdit;
|
|
1090
|
-
class GroupBy extends ListOf {
|
|
1091
|
-
constructor(members) {
|
|
1092
|
-
super("groupBy", members);
|
|
1093
|
-
for (const el of members) {
|
|
1094
|
-
if (el instanceof FieldDeclaration) {
|
|
1095
|
-
el.isMeasure = false;
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
exports.GroupBy = GroupBy;
|
|
1101
|
-
class Aggregate extends ListOf {
|
|
1102
|
-
constructor(members) {
|
|
1103
|
-
super("aggregate", members);
|
|
1104
|
-
for (const el of members) {
|
|
1105
|
-
if (el instanceof FieldDeclaration) {
|
|
1106
|
-
el.isMeasure = true;
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
exports.Aggregate = Aggregate;
|
|
1112
|
-
class ReduceExecutor {
|
|
1113
|
-
constructor(baseFS) {
|
|
1114
|
-
this.filters = [];
|
|
1115
|
-
this.resultFS = this.getResultSpace(baseFS);
|
|
1116
|
-
this.inputFS = this.resultFS.exprSpace;
|
|
1117
|
-
}
|
|
1118
|
-
getResultSpace(fs) {
|
|
1119
|
-
return new ReduceFieldSpace(fs);
|
|
1120
|
-
}
|
|
1121
|
-
execute(qp) {
|
|
1122
|
-
if (qp instanceof GroupBy ||
|
|
1123
|
-
qp instanceof Aggregate ||
|
|
1124
|
-
qp instanceof Nests) {
|
|
1125
|
-
this.resultFS.addQueryItems(...qp.list);
|
|
1126
|
-
}
|
|
1127
|
-
else if (isNestedQuery(qp)) {
|
|
1128
|
-
this.resultFS.addQueryItems(qp);
|
|
1129
|
-
}
|
|
1130
|
-
else if (qp instanceof Filter) {
|
|
1131
|
-
this.filters.push(...qp.getFilterList(this.inputFS));
|
|
1132
|
-
}
|
|
1133
|
-
else if (qp instanceof Top) {
|
|
1134
|
-
if (this.limit) {
|
|
1135
|
-
qp.log("Query operation already limited");
|
|
1136
|
-
}
|
|
1137
|
-
else {
|
|
1138
|
-
this.limit = qp.limit;
|
|
1139
|
-
}
|
|
1140
|
-
if (qp.by) {
|
|
1141
|
-
if (this.order) {
|
|
1142
|
-
qp.log("Query operation is already sorted");
|
|
1143
|
-
}
|
|
1144
|
-
else {
|
|
1145
|
-
this.order = qp;
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
else if (qp instanceof Limit) {
|
|
1150
|
-
if (this.limit) {
|
|
1151
|
-
qp.log("Query operation already limited");
|
|
1152
|
-
}
|
|
1153
|
-
else {
|
|
1154
|
-
this.limit = qp.limit;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
else if (qp instanceof Ordering) {
|
|
1158
|
-
if (this.order) {
|
|
1159
|
-
qp.log("Query operation already sorted");
|
|
1160
|
-
}
|
|
1161
|
-
else {
|
|
1162
|
-
this.order = qp;
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
else if (qp instanceof Joins || qp instanceof DeclareFields) {
|
|
1166
|
-
for (const qel of qp.list) {
|
|
1167
|
-
this.inputFS.extendSource(qel);
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
refineFrom(from, to) {
|
|
1172
|
-
if (from && from.type !== "index") {
|
|
1173
|
-
if (!this.order) {
|
|
1174
|
-
if (from.orderBy) {
|
|
1175
|
-
to.orderBy = from.orderBy;
|
|
1176
|
-
}
|
|
1177
|
-
else if (from.by) {
|
|
1178
|
-
to.by = from.by;
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
if (!this.limit && from.limit) {
|
|
1182
|
-
to.limit = from.limit;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
if (this.limit) {
|
|
1186
|
-
to.limit = this.limit;
|
|
1187
|
-
}
|
|
1188
|
-
if (this.order instanceof Top) {
|
|
1189
|
-
const topBy = this.order.getBy(this.inputFS);
|
|
1190
|
-
if (topBy) {
|
|
1191
|
-
to.by = topBy;
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
if (this.order instanceof Ordering) {
|
|
1195
|
-
to.orderBy = this.order.getOrderBy(this.inputFS);
|
|
1196
|
-
}
|
|
1197
|
-
const oldFilters = (from === null || from === void 0 ? void 0 : from.filterList) || [];
|
|
1198
|
-
if (this.filters.length > 0 && !oldFilters) {
|
|
1199
|
-
to.filterList = this.filters;
|
|
1200
|
-
}
|
|
1201
|
-
else if (oldFilters) {
|
|
1202
|
-
to.filterList = [...oldFilters, ...this.filters];
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
finalize(fromSeg) {
|
|
1206
|
-
let from;
|
|
1207
|
-
if (fromSeg) {
|
|
1208
|
-
if (model.isReduceSegment(fromSeg)) {
|
|
1209
|
-
from = fromSeg;
|
|
1210
|
-
}
|
|
1211
|
-
else {
|
|
1212
|
-
this.inputFS.result.log(`Can't refine reduce with ${fromSeg.type}`);
|
|
1213
|
-
return ErrorFactory.reduceSegment;
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
const reduceSegment = this.resultFS.getQuerySegment(from);
|
|
1217
|
-
this.refineFrom(from, reduceSegment);
|
|
1218
|
-
return reduceSegment;
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
class ProjectExecutor extends ReduceExecutor {
|
|
1222
|
-
getResultSpace(fs) {
|
|
1223
|
-
return new ProjectFieldSpace(fs);
|
|
1224
|
-
}
|
|
1225
|
-
execute(qp) {
|
|
1226
|
-
if (qp instanceof ProjectStatement) {
|
|
1227
|
-
this.resultFS.addMembers(qp.list);
|
|
1228
|
-
}
|
|
1229
|
-
else if ((qp instanceof Filter && qp.elementType === "having") ||
|
|
1230
|
-
qp instanceof Measures ||
|
|
1231
|
-
qp instanceof GroupBy) {
|
|
1232
|
-
qp.log("Illegal statement in a project query operation");
|
|
1233
|
-
}
|
|
1234
|
-
else {
|
|
1235
|
-
super.execute(qp);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
finalize(fromSeg) {
|
|
1239
|
-
let from;
|
|
1240
|
-
if (fromSeg) {
|
|
1241
|
-
if (model.isProjectSegment(fromSeg)) {
|
|
1242
|
-
from = fromSeg;
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1245
|
-
this.resultFS.log(`Can't refine project with ${fromSeg.type}`);
|
|
1246
|
-
return ErrorFactory.projectSegment;
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
const projectSegment = this.resultFS.getQuerySegment(from);
|
|
1250
|
-
this.refineFrom(from, projectSegment);
|
|
1251
|
-
return projectSegment;
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
class IndexExecutor {
|
|
1255
|
-
constructor(inputFS) {
|
|
1256
|
-
this.filters = [];
|
|
1257
|
-
this.resultFS = new IndexFieldSpace(inputFS);
|
|
1258
|
-
this.inputFS = this.resultFS.exprSpace;
|
|
1259
|
-
}
|
|
1260
|
-
execute(qp) {
|
|
1261
|
-
if (qp instanceof Filter) {
|
|
1262
|
-
this.filters.push(...qp.getFilterList(this.inputFS));
|
|
1263
|
-
}
|
|
1264
|
-
else if (qp instanceof Limit) {
|
|
1265
|
-
if (this.limit) {
|
|
1266
|
-
this.limit.log("Ignored, too many limit: statements");
|
|
1267
|
-
}
|
|
1268
|
-
this.limit = qp;
|
|
1269
|
-
}
|
|
1270
|
-
else if (qp instanceof Index) {
|
|
1271
|
-
this.resultFS.addMembers(qp.fields.list);
|
|
1272
|
-
if (qp.weightBy) {
|
|
1273
|
-
if (this.indexOn) {
|
|
1274
|
-
this.indexOn.log("Ignoring previous BY");
|
|
1275
|
-
}
|
|
1276
|
-
this.indexOn = qp.weightBy;
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
else if (qp instanceof SampleProperty) {
|
|
1280
|
-
this.sample = qp.sampling();
|
|
1281
|
-
}
|
|
1282
|
-
else {
|
|
1283
|
-
qp.log("Not legal in an index query operation");
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
finalize(from) {
|
|
1287
|
-
if (from && from.type !== "index") {
|
|
1288
|
-
this.resultFS.log(`Can't refine index with ${from.type}`);
|
|
1289
|
-
return ErrorFactory.indexSegment;
|
|
1290
|
-
}
|
|
1291
|
-
const indexSegment = this.resultFS.getPipeSegment(from);
|
|
1292
|
-
const oldFilters = (from === null || from === void 0 ? void 0 : from.filterList) || [];
|
|
1293
|
-
if (this.filters.length > 0 && !oldFilters) {
|
|
1294
|
-
indexSegment.filterList = this.filters;
|
|
1295
|
-
}
|
|
1296
|
-
else if (oldFilters) {
|
|
1297
|
-
indexSegment.filterList = [...oldFilters, ...this.filters];
|
|
1298
|
-
}
|
|
1299
|
-
if (from === null || from === void 0 ? void 0 : from.limit) {
|
|
1300
|
-
indexSegment.limit = from.limit;
|
|
1301
|
-
}
|
|
1302
|
-
if (this.limit) {
|
|
1303
|
-
indexSegment.limit = this.limit.limit;
|
|
1304
|
-
}
|
|
1305
|
-
if (this.indexOn) {
|
|
1306
|
-
indexSegment.weightMeasure = this.indexOn.refString;
|
|
1307
|
-
}
|
|
1308
|
-
if (from === null || from === void 0 ? void 0 : from.sample) {
|
|
1309
|
-
indexSegment.sample = from.sample;
|
|
1310
|
-
}
|
|
1311
|
-
if (this.sample) {
|
|
1312
|
-
indexSegment.sample = this.sample;
|
|
1313
|
-
}
|
|
1314
|
-
return indexSegment;
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
class QOPDesc extends ListOf {
|
|
1318
|
-
constructor(props) {
|
|
1319
|
-
super("queryOperator", props);
|
|
1320
|
-
this.opType = "grouping";
|
|
1321
|
-
}
|
|
1322
|
-
computeType() {
|
|
1323
|
-
let firstGuess;
|
|
1324
|
-
if (this.refineThis) {
|
|
1325
|
-
if (this.refineThis.type == "reduce") {
|
|
1326
|
-
firstGuess = "grouping";
|
|
1327
|
-
}
|
|
1328
|
-
else {
|
|
1329
|
-
firstGuess = this.refineThis.type;
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
let anyGrouping = false;
|
|
1333
|
-
for (const el of this.list) {
|
|
1334
|
-
if (el instanceof Index) {
|
|
1335
|
-
firstGuess || (firstGuess = "index");
|
|
1336
|
-
if (firstGuess !== "index") {
|
|
1337
|
-
el.log(`index: not legal in ${firstGuess} query`);
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
else if (el instanceof Nests ||
|
|
1341
|
-
isNestedQuery(el) ||
|
|
1342
|
-
el instanceof GroupBy) {
|
|
1343
|
-
firstGuess || (firstGuess = "grouping");
|
|
1344
|
-
anyGrouping = true;
|
|
1345
|
-
if (firstGuess === "project" || firstGuess === "index") {
|
|
1346
|
-
el.log(`group_by: not legal in ${firstGuess} query`);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
else if (el instanceof Aggregate) {
|
|
1350
|
-
firstGuess || (firstGuess = "aggregate");
|
|
1351
|
-
if (firstGuess === "project" || firstGuess === "index") {
|
|
1352
|
-
el.log(`aggregate: not legal in ${firstGuess} query`);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
else if (el instanceof ProjectStatement) {
|
|
1356
|
-
firstGuess || (firstGuess = "project");
|
|
1357
|
-
if (firstGuess !== "project") {
|
|
1358
|
-
el.log(`project: not legal in ${firstGuess} query`);
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
if (firstGuess === "aggregate" && anyGrouping) {
|
|
1363
|
-
firstGuess = "grouping";
|
|
1364
|
-
}
|
|
1365
|
-
if (!firstGuess) {
|
|
1366
|
-
this.log("Can't determine query type (group_by/aggregate/nest,project,index)");
|
|
1367
|
-
}
|
|
1368
|
-
const guessType = firstGuess || "grouping";
|
|
1369
|
-
this.opType = guessType;
|
|
1370
|
-
return guessType;
|
|
1371
|
-
}
|
|
1372
|
-
refineFrom(existing) {
|
|
1373
|
-
this.refineThis = existing;
|
|
1374
|
-
}
|
|
1375
|
-
getExecutor(baseFS) {
|
|
1376
|
-
switch (this.computeType()) {
|
|
1377
|
-
case "aggregate":
|
|
1378
|
-
case "grouping":
|
|
1379
|
-
return new ReduceExecutor(baseFS);
|
|
1380
|
-
case "project":
|
|
1381
|
-
return new ProjectExecutor(baseFS);
|
|
1382
|
-
case "index":
|
|
1383
|
-
return new IndexExecutor(baseFS);
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
getOp(inputFS, forPipeline) {
|
|
1387
|
-
const qex = this.getExecutor(inputFS);
|
|
1388
|
-
if (forPipeline === null || forPipeline === void 0 ? void 0 : forPipeline.nestedInQuerySpace) {
|
|
1389
|
-
qex.inputFS.nestParent = forPipeline.nestedInQuerySpace;
|
|
1390
|
-
}
|
|
1391
|
-
qex.resultFS.astEl = this;
|
|
1392
|
-
for (const qp of this.list) {
|
|
1393
|
-
qex.execute(qp);
|
|
1394
|
-
}
|
|
1395
|
-
const segment = qex.finalize(this.refineThis);
|
|
1396
|
-
return {
|
|
1397
|
-
segment,
|
|
1398
|
-
outputSpace: () => new DynamicSpace(opOutputStruct(this, inputFS.structDef(), segment)),
|
|
1399
|
-
};
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
exports.QOPDesc = QOPDesc;
|
|
1403
|
-
/**
|
|
1404
|
-
* The Document class is a little weird because we might need to bounce back
|
|
1405
|
-
* to the requestor, which might be on the other side of a wire, to get
|
|
1406
|
-
* back some schema information. The intended translation of a Document
|
|
1407
|
-
* is to call initModelDef(), and then to call modelDataRequest() until it
|
|
1408
|
-
* returns undefined. At any time you can call modelDef to get the model
|
|
1409
|
-
* as it exists so far, but the translation is not complete until
|
|
1410
|
-
* modelDataRequest() returns undefined;
|
|
1411
|
-
*
|
|
1412
|
-
* TODO probably modelRequest should be the method and you call it
|
|
1413
|
-
* until it returns a model with no additional data needed ...
|
|
1414
|
-
* that can be tomorrow
|
|
1415
|
-
*/
|
|
1416
|
-
class Document extends MalloyElement {
|
|
1417
|
-
constructor(statements) {
|
|
1418
|
-
super();
|
|
1419
|
-
this.elementType = "document";
|
|
1420
|
-
this.documentModel = {};
|
|
1421
|
-
this.queryList = [];
|
|
1422
|
-
this.sqlBlocks = [];
|
|
1423
|
-
this.didInitModel = false;
|
|
1424
|
-
this.statements = new RunList("topLevelStatements", statements);
|
|
1425
|
-
this.has({ statements });
|
|
1426
|
-
}
|
|
1427
|
-
initModelDef(extendingModelDef) {
|
|
1428
|
-
if (this.didInitModel) {
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
this.documentModel = {};
|
|
1432
|
-
this.queryList = [];
|
|
1433
|
-
this.sqlBlocks = [];
|
|
1434
|
-
if (extendingModelDef) {
|
|
1435
|
-
for (const inName in extendingModelDef.contents) {
|
|
1436
|
-
const struct = extendingModelDef.contents[inName];
|
|
1437
|
-
if (struct.type == "struct") {
|
|
1438
|
-
const exported = extendingModelDef.exports.includes(inName);
|
|
1439
|
-
this.setEntry(inName, { entry: struct, exported });
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
this.didInitModel = true;
|
|
1444
|
-
}
|
|
1445
|
-
compile() {
|
|
1446
|
-
const needs = this.statements.executeList(this);
|
|
1447
|
-
const ret = {
|
|
1448
|
-
modelDef: this.modelDef(),
|
|
1449
|
-
queryList: this.queryList,
|
|
1450
|
-
sqlBlocks: this.sqlBlocks,
|
|
1451
|
-
needs,
|
|
1452
|
-
};
|
|
1453
|
-
return ret;
|
|
1454
|
-
}
|
|
1455
|
-
modelDef() {
|
|
1456
|
-
const def = { name: "", exports: [], contents: {} };
|
|
1457
|
-
for (const entry in this.documentModel) {
|
|
1458
|
-
const entryDef = this.documentModel[entry].entry;
|
|
1459
|
-
if (entryDef.type === "struct" || entryDef.type === "query") {
|
|
1460
|
-
if (this.documentModel[entry].exported) {
|
|
1461
|
-
def.exports.push(entry);
|
|
1462
|
-
}
|
|
1463
|
-
def.contents[entry] = (0, lodash_1.cloneDeep)(entryDef);
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
return def;
|
|
1467
|
-
}
|
|
1468
|
-
defineSQL(sql, name) {
|
|
1469
|
-
const ret = { ...sql, as: `$${this.sqlBlocks.length}` };
|
|
1470
|
-
if (name) {
|
|
1471
|
-
if (this.getEntry(name)) {
|
|
1472
|
-
return false;
|
|
1473
|
-
}
|
|
1474
|
-
ret.as = name;
|
|
1475
|
-
this.setEntry(name, { entry: ret, sqlType: true });
|
|
1476
|
-
}
|
|
1477
|
-
this.sqlBlocks.push(ret);
|
|
1478
|
-
return true;
|
|
1479
|
-
}
|
|
1480
|
-
getEntry(str) {
|
|
1481
|
-
return this.documentModel[str];
|
|
1482
|
-
}
|
|
1483
|
-
setEntry(str, ent) {
|
|
1484
|
-
this.documentModel[str] = ent;
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
exports.Document = Document;
|
|
1488
|
-
class PrimaryKey extends MalloyElement {
|
|
1489
|
-
constructor(field) {
|
|
1490
|
-
super({ field });
|
|
1491
|
-
this.field = field;
|
|
1492
|
-
this.elementType = "primary key";
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
exports.PrimaryKey = PrimaryKey;
|
|
1496
|
-
class RenameField extends MalloyElement {
|
|
1497
|
-
constructor(newName, oldName) {
|
|
1498
|
-
super();
|
|
1499
|
-
this.newName = newName;
|
|
1500
|
-
this.oldName = oldName;
|
|
1501
|
-
this.elementType = "renameField";
|
|
1502
|
-
this.has({ oldName });
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
exports.RenameField = RenameField;
|
|
1506
|
-
class WildcardFieldReference extends MalloyElement {
|
|
1507
|
-
constructor(joinPath, star) {
|
|
1508
|
-
super();
|
|
1509
|
-
this.joinPath = joinPath;
|
|
1510
|
-
this.star = star;
|
|
1511
|
-
this.elementType = "wildcardFieldReference";
|
|
1512
|
-
this.has({ joinPath });
|
|
1513
|
-
}
|
|
1514
|
-
getFieldDef() {
|
|
1515
|
-
throw this.internalError("fielddef request from wildcard reference");
|
|
1516
|
-
}
|
|
1517
|
-
get refString() {
|
|
1518
|
-
return this.joinPath
|
|
1519
|
-
? `${this.joinPath.refString}.${this.star}`
|
|
1520
|
-
: this.star;
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
exports.WildcardFieldReference = WildcardFieldReference;
|
|
1524
|
-
class OrderBy extends MalloyElement {
|
|
1525
|
-
constructor(field, dir) {
|
|
1526
|
-
super();
|
|
1527
|
-
this.field = field;
|
|
1528
|
-
this.dir = dir;
|
|
1529
|
-
this.elementType = "orderBy";
|
|
1530
|
-
if (field instanceof FieldName) {
|
|
1531
|
-
this.has({ field });
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
get modelField() {
|
|
1535
|
-
return typeof this.field === "number" ? this.field : this.field.refString;
|
|
1536
|
-
}
|
|
1537
|
-
getOrderBy(_fs) {
|
|
1538
|
-
// TODO jump-to-definition `fs` cannot currently `lookup` fields in the output space
|
|
1539
|
-
// if (this.field instanceof FieldName) {
|
|
1540
|
-
// const entry = this.field.getField(_fs);
|
|
1541
|
-
// if (entry.error) {
|
|
1542
|
-
// this.field.log(entry.error);
|
|
1543
|
-
// }
|
|
1544
|
-
// }
|
|
1545
|
-
const orderElement = { field: this.modelField };
|
|
1546
|
-
if (this.dir) {
|
|
1547
|
-
orderElement.dir = this.dir;
|
|
1548
|
-
}
|
|
1549
|
-
return orderElement;
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
exports.OrderBy = OrderBy;
|
|
1553
|
-
class Ordering extends ListOf {
|
|
1554
|
-
constructor(list) {
|
|
1555
|
-
super("ordering", list);
|
|
1556
|
-
}
|
|
1557
|
-
getOrderBy(fs) {
|
|
1558
|
-
return this.list.map((el) => el.getOrderBy(fs));
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
exports.Ordering = Ordering;
|
|
1562
|
-
class Limit extends MalloyElement {
|
|
1563
|
-
constructor(limit) {
|
|
1564
|
-
super();
|
|
1565
|
-
this.limit = limit;
|
|
1566
|
-
this.elementType = "limit";
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
exports.Limit = Limit;
|
|
1570
|
-
class Turtles extends ListOf {
|
|
1571
|
-
constructor(turtles) {
|
|
1572
|
-
super("turtleDeclarationList", turtles);
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
exports.Turtles = Turtles;
|
|
1576
|
-
class Index extends MalloyElement {
|
|
1577
|
-
constructor(fields) {
|
|
1578
|
-
super({ fields });
|
|
1579
|
-
this.fields = fields;
|
|
1580
|
-
this.elementType = "index";
|
|
1581
|
-
}
|
|
1582
|
-
useWeight(fn) {
|
|
1583
|
-
this.has({ weightBy: fn });
|
|
1584
|
-
this.weightBy = fn;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
exports.Index = Index;
|
|
1588
|
-
function isTurtle(fd) {
|
|
1589
|
-
const ret = fd && typeof fd !== "string" && fd.type === "turtle";
|
|
1590
|
-
return !!ret;
|
|
1591
|
-
}
|
|
1592
|
-
/**
|
|
1593
|
-
* Generic abstract for all pipelines, the first segment might be a reference
|
|
1594
|
-
* to an existing pipeline (query or turtle), and if there is a refinement it
|
|
1595
|
-
* is refers to the first segment of the composed pipeline.
|
|
1596
|
-
*/
|
|
1597
|
-
class PipelineDesc extends MalloyElement {
|
|
1598
|
-
constructor() {
|
|
1599
|
-
super(...arguments);
|
|
1600
|
-
this.elementType = "pipelineDesc";
|
|
1601
|
-
this.qops = [];
|
|
1602
|
-
}
|
|
1603
|
-
refineHead(refinement) {
|
|
1604
|
-
this.headRefinement = refinement;
|
|
1605
|
-
this.has({ headRefinement: refinement });
|
|
1606
|
-
}
|
|
1607
|
-
addSegments(...segDesc) {
|
|
1608
|
-
this.qops.push(...segDesc);
|
|
1609
|
-
this.has({ segments: this.qops });
|
|
1610
|
-
}
|
|
1611
|
-
appendOps(modelPipe, existingEndSpace) {
|
|
1612
|
-
let nextFS = existingEndSpace;
|
|
1613
|
-
let returnPipe;
|
|
1614
|
-
for (const qop of this.qops) {
|
|
1615
|
-
const qopIsNested = modelPipe.length == 0;
|
|
1616
|
-
const next = qop.getOp(nextFS, qopIsNested ? this : null);
|
|
1617
|
-
if (returnPipe == undefined) {
|
|
1618
|
-
returnPipe = [...modelPipe];
|
|
1619
|
-
}
|
|
1620
|
-
returnPipe.push(next.segment);
|
|
1621
|
-
nextFS = next.outputSpace();
|
|
1622
|
-
}
|
|
1623
|
-
return {
|
|
1624
|
-
opList: returnPipe || modelPipe,
|
|
1625
|
-
structDef: nextFS.structDef(),
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
refinePipeline(fs, modelPipe) {
|
|
1629
|
-
if (!this.headRefinement) {
|
|
1630
|
-
return modelPipe;
|
|
1631
|
-
}
|
|
1632
|
-
const pipeline = [];
|
|
1633
|
-
if (modelPipe.pipeHead) {
|
|
1634
|
-
const { pipeline: turtlePipe } = this.expandTurtle(modelPipe.pipeHead.name, fs.structDef());
|
|
1635
|
-
pipeline.push(...turtlePipe);
|
|
1636
|
-
}
|
|
1637
|
-
pipeline.push(...modelPipe.pipeline);
|
|
1638
|
-
const firstSeg = pipeline[0];
|
|
1639
|
-
if (firstSeg) {
|
|
1640
|
-
this.headRefinement.refineFrom(firstSeg);
|
|
1641
|
-
}
|
|
1642
|
-
pipeline[0] = this.headRefinement.getOp(fs, this).segment;
|
|
1643
|
-
return { pipeline };
|
|
1644
|
-
}
|
|
1645
|
-
expandTurtle(turtleName, fromStruct) {
|
|
1646
|
-
const turtle = getStructFieldDef(fromStruct, turtleName);
|
|
1647
|
-
if (!turtle) {
|
|
1648
|
-
this.log(`Query '${turtleName}' is not defined in source`);
|
|
1649
|
-
}
|
|
1650
|
-
else if (turtle.type !== "turtle") {
|
|
1651
|
-
this.log(`'${turtleName}' is not a query`);
|
|
1652
|
-
}
|
|
1653
|
-
else {
|
|
1654
|
-
return { pipeline: turtle.pipeline, location: turtle.location };
|
|
1655
|
-
}
|
|
1656
|
-
return { pipeline: [], location: undefined };
|
|
1657
|
-
}
|
|
1658
|
-
getOutputStruct(walkStruct, pipeline) {
|
|
1659
|
-
for (const modelQop of pipeline) {
|
|
1660
|
-
walkStruct = opOutputStruct(this, walkStruct, modelQop);
|
|
1661
|
-
}
|
|
1662
|
-
return walkStruct;
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
class ExistingQuery extends PipelineDesc {
|
|
1666
|
-
set head(head) {
|
|
1667
|
-
this._head = head;
|
|
1668
|
-
this.has({ head });
|
|
1669
|
-
}
|
|
1670
|
-
get head() {
|
|
1671
|
-
return this._head;
|
|
1672
|
-
}
|
|
1673
|
-
queryComp() {
|
|
1674
|
-
if (!this.head) {
|
|
1675
|
-
throw this.internalError("can't make query from nameless query");
|
|
1676
|
-
}
|
|
1677
|
-
const queryEntry = this.modelEntry(this.head);
|
|
1678
|
-
const seedQuery = queryEntry === null || queryEntry === void 0 ? void 0 : queryEntry.entry;
|
|
1679
|
-
const oops = function () {
|
|
1680
|
-
return {
|
|
1681
|
-
outputStruct: ErrorFactory.structDef,
|
|
1682
|
-
query: ErrorFactory.query,
|
|
1683
|
-
};
|
|
1684
|
-
};
|
|
1685
|
-
if (!seedQuery) {
|
|
1686
|
-
this.log(`Reference to undefined query '${this.head}'`);
|
|
1687
|
-
return oops();
|
|
1688
|
-
}
|
|
1689
|
-
if (seedQuery.type !== "query") {
|
|
1690
|
-
this.log(`Illegal reference to '${this.head}', query expected`);
|
|
1691
|
-
return oops();
|
|
1692
|
-
}
|
|
1693
|
-
const queryHead = new QueryHeadStruct(seedQuery.structRef);
|
|
1694
|
-
this.has({ queryHead });
|
|
1695
|
-
const exploreStruct = queryHead.structDef();
|
|
1696
|
-
const exploreFS = new DynamicSpace(exploreStruct);
|
|
1697
|
-
const sourcePipe = this.refinePipeline(exploreFS, seedQuery);
|
|
1698
|
-
const walkStruct = this.getOutputStruct(exploreStruct, sourcePipe.pipeline);
|
|
1699
|
-
const appended = this.appendOps(sourcePipe.pipeline, new DynamicSpace(walkStruct));
|
|
1700
|
-
const destPipe = { ...sourcePipe, pipeline: appended.opList };
|
|
1701
|
-
const query = {
|
|
1702
|
-
type: "query",
|
|
1703
|
-
...destPipe,
|
|
1704
|
-
structRef: queryHead.structRef(),
|
|
1705
|
-
location: this.location,
|
|
1706
|
-
};
|
|
1707
|
-
return { outputStruct: appended.structDef, query };
|
|
1708
|
-
}
|
|
1709
|
-
query() {
|
|
1710
|
-
return this.queryComp().query;
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
exports.ExistingQuery = ExistingQuery;
|
|
1714
|
-
class TurtleHeadedPipe extends PipelineDesc {
|
|
1715
|
-
set turtleName(turtleName) {
|
|
1716
|
-
this._turtleName = turtleName;
|
|
1717
|
-
this.has({ turtleName });
|
|
1718
|
-
}
|
|
1719
|
-
get turtleName() {
|
|
1720
|
-
return this._turtleName;
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
1723
|
-
exports.TurtleHeadedPipe = TurtleHeadedPipe;
|
|
1724
|
-
class FullQuery extends TurtleHeadedPipe {
|
|
1725
|
-
constructor(explore) {
|
|
1726
|
-
super({ explore });
|
|
1727
|
-
this.explore = explore;
|
|
1728
|
-
}
|
|
1729
|
-
queryComp() {
|
|
1730
|
-
const structRef = this.explore.structRef();
|
|
1731
|
-
const destQuery = {
|
|
1732
|
-
type: "query",
|
|
1733
|
-
structRef,
|
|
1734
|
-
pipeline: [],
|
|
1735
|
-
location: this.location,
|
|
1736
|
-
};
|
|
1737
|
-
const structDef = model.refIsStructDef(structRef)
|
|
1738
|
-
? structRef
|
|
1739
|
-
: this.explore.structDef();
|
|
1740
|
-
let pipeFs = new DynamicSpace(structDef);
|
|
1741
|
-
if (ErrorFactory.isErrorStructDef(structDef)) {
|
|
1742
|
-
return {
|
|
1743
|
-
outputStruct: structDef,
|
|
1744
|
-
query: {
|
|
1745
|
-
structRef: structRef,
|
|
1746
|
-
pipeline: [],
|
|
1747
|
-
},
|
|
1748
|
-
};
|
|
1749
|
-
}
|
|
1750
|
-
if (this.turtleName) {
|
|
1751
|
-
const { error } = this.turtleName.getField(pipeFs);
|
|
1752
|
-
if (error)
|
|
1753
|
-
this.log(error);
|
|
1754
|
-
const name = this.turtleName.refString;
|
|
1755
|
-
const { pipeline, location } = this.expandTurtle(name, structDef);
|
|
1756
|
-
destQuery.location = location;
|
|
1757
|
-
const refined = this.refinePipeline(pipeFs, { pipeline }).pipeline;
|
|
1758
|
-
if (this.headRefinement) {
|
|
1759
|
-
// TODO there is an issue with losing the name of the turtle
|
|
1760
|
-
// which we need to fix, possibly adding a "name:" field to a segment
|
|
1761
|
-
// TODO there was mention of promoting filters to the query
|
|
1762
|
-
destQuery.pipeline = refined;
|
|
1763
|
-
}
|
|
1764
|
-
else {
|
|
1765
|
-
destQuery.pipeHead = { name };
|
|
1766
|
-
}
|
|
1767
|
-
const pipeStruct = this.getOutputStruct(structDef, refined);
|
|
1768
|
-
pipeFs = new DynamicSpace(pipeStruct);
|
|
1769
|
-
}
|
|
1770
|
-
const appended = this.appendOps(destQuery.pipeline, pipeFs);
|
|
1771
|
-
destQuery.pipeline = appended.opList;
|
|
1772
|
-
return { outputStruct: appended.structDef, query: destQuery };
|
|
1773
|
-
}
|
|
1774
|
-
query() {
|
|
1775
|
-
return this.queryComp().query;
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
exports.FullQuery = FullQuery;
|
|
1779
|
-
class TurtleDecl extends TurtleHeadedPipe {
|
|
1780
|
-
constructor(name) {
|
|
1781
|
-
super();
|
|
1782
|
-
this.name = name;
|
|
1783
|
-
}
|
|
1784
|
-
getPipeline(fs) {
|
|
1785
|
-
const modelPipe = { pipeline: [] };
|
|
1786
|
-
if (this.turtleName) {
|
|
1787
|
-
const headEnt = this.turtleName.getField(fs);
|
|
1788
|
-
let reportWrongType = true;
|
|
1789
|
-
if (headEnt.error) {
|
|
1790
|
-
this.log(headEnt.error);
|
|
1791
|
-
reportWrongType = false;
|
|
1792
|
-
}
|
|
1793
|
-
else if (headEnt.found instanceof QueryField) {
|
|
1794
|
-
const headDef = headEnt.found.getQueryFieldDef(fs);
|
|
1795
|
-
if (isTurtle(headDef)) {
|
|
1796
|
-
const newPipe = this.refinePipeline(fs, headDef);
|
|
1797
|
-
modelPipe.pipeline = [...newPipe.pipeline];
|
|
1798
|
-
reportWrongType = false;
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
if (reportWrongType) {
|
|
1802
|
-
this.log(`Expected '${this.turtleName}' to be a query`);
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
else if (this.headRefinement) {
|
|
1806
|
-
throw this.internalError("Can't refine the head of a turtle in its definition");
|
|
1807
|
-
}
|
|
1808
|
-
let appendInput = fs;
|
|
1809
|
-
if (modelPipe.pipeline.length > 0) {
|
|
1810
|
-
let endStruct = appendInput.structDef();
|
|
1811
|
-
for (const existingSeg of modelPipe.pipeline) {
|
|
1812
|
-
endStruct = opOutputStruct(this, endStruct, existingSeg);
|
|
1813
|
-
}
|
|
1814
|
-
appendInput = new DynamicSpace(endStruct);
|
|
1815
|
-
}
|
|
1816
|
-
const appended = this.appendOps(modelPipe.pipeline, appendInput);
|
|
1817
|
-
modelPipe.pipeline = appended.opList;
|
|
1818
|
-
return modelPipe;
|
|
1819
|
-
}
|
|
1820
|
-
getFieldDef(fs, nestParent) {
|
|
1821
|
-
if (nestParent) {
|
|
1822
|
-
this.nestedInQuerySpace = nestParent;
|
|
1823
|
-
}
|
|
1824
|
-
const pipe = this.getPipeline(fs);
|
|
1825
|
-
return {
|
|
1826
|
-
type: "turtle",
|
|
1827
|
-
name: this.name,
|
|
1828
|
-
...pipe,
|
|
1829
|
-
location: this.location,
|
|
1830
|
-
};
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
exports.TurtleDecl = TurtleDecl;
|
|
1834
|
-
class NestReference extends FieldReference {
|
|
1835
|
-
constructor(name) {
|
|
1836
|
-
super([name]);
|
|
1837
|
-
this.name = name;
|
|
1838
|
-
this.elementType = "nestReference";
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
exports.NestReference = NestReference;
|
|
1842
|
-
class NestRefinement extends TurtleDecl {
|
|
1843
|
-
constructor(turtleName) {
|
|
1844
|
-
super(turtleName.refString);
|
|
1845
|
-
this.elementType = "nestRefinement";
|
|
1846
|
-
this.turtleName = turtleName;
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
exports.NestRefinement = NestRefinement;
|
|
1850
|
-
class NestDefinition extends TurtleDecl {
|
|
1851
|
-
constructor(name) {
|
|
1852
|
-
super(name);
|
|
1853
|
-
this.elementType = "nestDefinition";
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
exports.NestDefinition = NestDefinition;
|
|
1857
|
-
function isNestedQuery(me) {
|
|
1858
|
-
return (me instanceof NestRefinement ||
|
|
1859
|
-
me instanceof NestReference ||
|
|
1860
|
-
me instanceof NestDefinition);
|
|
1861
|
-
}
|
|
1862
|
-
exports.isNestedQuery = isNestedQuery;
|
|
1863
|
-
class Nests extends ListOf {
|
|
1864
|
-
constructor(nests) {
|
|
1865
|
-
super("nestedQueries", nests);
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
exports.Nests = Nests;
|
|
1869
|
-
function isQueryElement(e) {
|
|
1870
|
-
return e instanceof FullQuery || e instanceof ExistingQuery;
|
|
1871
|
-
}
|
|
1872
|
-
exports.isQueryElement = isQueryElement;
|
|
1873
|
-
class DefineQueryList extends RunList {
|
|
1874
|
-
constructor(queryList) {
|
|
1875
|
-
super("defineQueries", queryList);
|
|
1876
|
-
}
|
|
1877
|
-
execute(doc) {
|
|
1878
|
-
return this.executeList(doc);
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
exports.DefineQueryList = DefineQueryList;
|
|
1882
|
-
class DefineQuery extends MalloyElement {
|
|
1883
|
-
constructor(name, queryDetails) {
|
|
1884
|
-
super({ queryDetails });
|
|
1885
|
-
this.name = name;
|
|
1886
|
-
this.queryDetails = queryDetails;
|
|
1887
|
-
this.elementType = "defineQuery";
|
|
1888
|
-
}
|
|
1889
|
-
execute(doc) {
|
|
1890
|
-
const entry = {
|
|
1891
|
-
...this.queryDetails.query(),
|
|
1892
|
-
type: "query",
|
|
1893
|
-
name: this.name,
|
|
1894
|
-
location: this.location,
|
|
1895
|
-
};
|
|
1896
|
-
const exported = false;
|
|
1897
|
-
doc.setEntry(this.name, { entry, exported });
|
|
1898
|
-
return undefined;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
exports.DefineQuery = DefineQuery;
|
|
1902
|
-
class AnonymousQuery extends MalloyElement {
|
|
1903
|
-
constructor(theQuery) {
|
|
1904
|
-
super();
|
|
1905
|
-
this.theQuery = theQuery;
|
|
1906
|
-
this.elementType = "anonymousQuery";
|
|
1907
|
-
this.has({ query: theQuery });
|
|
1908
|
-
}
|
|
1909
|
-
execute(doc) {
|
|
1910
|
-
const modelQuery = this.theQuery.query();
|
|
1911
|
-
doc.queryList.push(modelQuery);
|
|
1912
|
-
return undefined;
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
exports.AnonymousQuery = AnonymousQuery;
|
|
1916
|
-
class Top extends MalloyElement {
|
|
1917
|
-
constructor(limit, by) {
|
|
1918
|
-
super();
|
|
1919
|
-
this.limit = limit;
|
|
1920
|
-
this.by = by;
|
|
1921
|
-
this.elementType = "top";
|
|
1922
|
-
this.has({ by });
|
|
1923
|
-
}
|
|
1924
|
-
getBy(fs) {
|
|
1925
|
-
if (this.by) {
|
|
1926
|
-
if (this.by instanceof FieldName) {
|
|
1927
|
-
// TODO jump-to-definition `fs` cannot currently `lookup` fields in the output space
|
|
1928
|
-
// const entry = this.by.getField(fs);
|
|
1929
|
-
// if (entry.error) {
|
|
1930
|
-
// this.by.log(entry.error);
|
|
1931
|
-
// }
|
|
1932
|
-
return { by: "name", name: this.by.refString };
|
|
1933
|
-
}
|
|
1934
|
-
else {
|
|
1935
|
-
const byExpr = this.by.getExpression(fs);
|
|
1936
|
-
if (model.expressionIsAggregate(byExpr.expressionType)) {
|
|
1937
|
-
this.log("top by expression must be an aggregate");
|
|
1938
|
-
}
|
|
1939
|
-
return { by: "expression", e: (0, ast_types_1.compressExpr)(byExpr.value) };
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
return undefined;
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
exports.Top = Top;
|
|
1946
|
-
class JSONElement extends MalloyElement {
|
|
1947
|
-
constructor(jsonSrc) {
|
|
1948
|
-
super();
|
|
1949
|
-
this.elementType = "jsonElement";
|
|
1950
|
-
try {
|
|
1951
|
-
this.value = JSON.parse(jsonSrc);
|
|
1952
|
-
}
|
|
1953
|
-
catch (SyntaxError) {
|
|
1954
|
-
this.log("JSON syntax error");
|
|
1955
|
-
this.value = undefined;
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
exports.JSONElement = JSONElement;
|
|
1960
|
-
class JSONStructDef extends Mallobj {
|
|
1961
|
-
constructor(struct) {
|
|
1962
|
-
super();
|
|
1963
|
-
this.struct = struct;
|
|
1964
|
-
this.elementType = "jsonStructDef";
|
|
1965
|
-
}
|
|
1966
|
-
static fromJSON(jsonObj) {
|
|
1967
|
-
const obj = jsonObj.value;
|
|
1968
|
-
if (obj &&
|
|
1969
|
-
obj.type === "struct" &&
|
|
1970
|
-
obj.structRelationship &&
|
|
1971
|
-
obj.structSource) {
|
|
1972
|
-
return new JSONStructDef(obj);
|
|
1973
|
-
}
|
|
1974
|
-
return undefined;
|
|
1975
|
-
}
|
|
1976
|
-
structDef() {
|
|
1977
|
-
return this.struct;
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
exports.JSONStructDef = JSONStructDef;
|
|
1981
|
-
class ImportStatement extends MalloyElement {
|
|
1982
|
-
/*
|
|
1983
|
-
* At the time of writng this comment, it is guaranteed that if an AST
|
|
1984
|
-
* node for an import statement is created, the translator has already
|
|
1985
|
-
* succesfully fetched the URL referred to in the statement.
|
|
1986
|
-
*
|
|
1987
|
-
* Error checking code in here is future proofing against a day when
|
|
1988
|
-
* there are other ways to contruct an AST.
|
|
1989
|
-
*/
|
|
1990
|
-
constructor(url, baseURL) {
|
|
1991
|
-
super();
|
|
1992
|
-
this.url = url;
|
|
1993
|
-
this.elementType = "import statement";
|
|
1994
|
-
try {
|
|
1995
|
-
this.fullURL = decodeURI(new URL(url, baseURL).toString());
|
|
1996
|
-
}
|
|
1997
|
-
catch (e) {
|
|
1998
|
-
this.log("Invalid URI in import statement");
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
execute(doc) {
|
|
2002
|
-
const trans = this.translator();
|
|
2003
|
-
if (!trans) {
|
|
2004
|
-
this.log("Cannot import without translation context");
|
|
2005
|
-
}
|
|
2006
|
-
else if (this.fullURL) {
|
|
2007
|
-
const src = trans.root.importZone.getEntry(this.fullURL);
|
|
2008
|
-
if (src.status === "present") {
|
|
2009
|
-
const childNeeds = trans.childRequest(this.fullURL);
|
|
2010
|
-
if (childNeeds) {
|
|
2011
|
-
return childNeeds;
|
|
2012
|
-
}
|
|
2013
|
-
const importStructs = trans.getChildExports(this.fullURL);
|
|
2014
|
-
for (const importing in importStructs) {
|
|
2015
|
-
doc.setEntry(importing, {
|
|
2016
|
-
entry: importStructs[importing],
|
|
2017
|
-
exported: false,
|
|
2018
|
-
});
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
else if (src.status === "error") {
|
|
2022
|
-
this.log(`import failed: '${src.message}'`);
|
|
2023
|
-
}
|
|
2024
|
-
else {
|
|
2025
|
-
this.log(`import failed with status: '${src.status}'`);
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
return undefined;
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
exports.ImportStatement = ImportStatement;
|
|
2032
|
-
class HasParameter extends MalloyElement {
|
|
2033
|
-
constructor(init) {
|
|
2034
|
-
super();
|
|
2035
|
-
this.elementType = "hasParameter";
|
|
2036
|
-
this.name = init.name;
|
|
2037
|
-
this.isCondition = init.isCondition;
|
|
2038
|
-
if (init.type && model.isAtomicFieldType(init.type)) {
|
|
2039
|
-
this.type = init.type;
|
|
2040
|
-
}
|
|
2041
|
-
if (init.default) {
|
|
2042
|
-
this.default = init.default;
|
|
2043
|
-
this.has({ default: this.default });
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
parameter() {
|
|
2047
|
-
var _a, _b;
|
|
2048
|
-
const name = this.name;
|
|
2049
|
-
const type = this.type || "string";
|
|
2050
|
-
if (this.isCondition) {
|
|
2051
|
-
const cCond = ((_a = this.default) === null || _a === void 0 ? void 0 : _a.constantCondition(type).value) || null;
|
|
2052
|
-
return {
|
|
2053
|
-
type,
|
|
2054
|
-
name,
|
|
2055
|
-
condition: cCond,
|
|
2056
|
-
};
|
|
2057
|
-
}
|
|
2058
|
-
const cVal = ((_b = this.default) === null || _b === void 0 ? void 0 : _b.constantValue().value) || null;
|
|
2059
|
-
return {
|
|
2060
|
-
value: cVal,
|
|
2061
|
-
type,
|
|
2062
|
-
name: this.name,
|
|
2063
|
-
constant: false,
|
|
2064
|
-
};
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
exports.HasParameter = HasParameter;
|
|
2068
|
-
class ConstantParameter extends HasParameter {
|
|
2069
|
-
constructor(name, value) {
|
|
2070
|
-
super({ name, isCondition: false });
|
|
2071
|
-
this.value = value;
|
|
2072
|
-
this.has({ value });
|
|
2073
|
-
}
|
|
2074
|
-
parameter() {
|
|
2075
|
-
const cVal = this.value.constantValue();
|
|
2076
|
-
if (!model.isAtomicFieldType(cVal.dataType)) {
|
|
2077
|
-
this.log(`Unexpected expression type '${cVal.dataType}'`);
|
|
2078
|
-
return {
|
|
2079
|
-
value: ["XXX-type-mismatch-error-XXX"],
|
|
2080
|
-
type: "string",
|
|
2081
|
-
name: this.name,
|
|
2082
|
-
constant: true,
|
|
2083
|
-
};
|
|
2084
|
-
}
|
|
2085
|
-
return {
|
|
2086
|
-
value: cVal.value,
|
|
2087
|
-
type: cVal.dataType,
|
|
2088
|
-
name: this.name,
|
|
2089
|
-
constant: true,
|
|
2090
|
-
};
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
exports.ConstantParameter = ConstantParameter;
|
|
2094
|
-
class SQLString extends MalloyElement {
|
|
2095
|
-
constructor() {
|
|
2096
|
-
super(...arguments);
|
|
2097
|
-
this.elementType = "sqlString";
|
|
2098
|
-
this.elements = [];
|
|
2099
|
-
this.containsQueries = false;
|
|
2100
|
-
}
|
|
2101
|
-
push(el) {
|
|
2102
|
-
if (typeof el == "string") {
|
|
2103
|
-
if (el.length > 0) {
|
|
2104
|
-
this.elements.push(el);
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
else if (isQueryElement(el)) {
|
|
2108
|
-
this.elements.push(el);
|
|
2109
|
-
this.containsQueries = true;
|
|
2110
|
-
el.parent = this;
|
|
2111
|
-
}
|
|
2112
|
-
else {
|
|
2113
|
-
el.log("This element is not legal inside an SQL string");
|
|
2114
|
-
}
|
|
2115
|
-
}
|
|
2116
|
-
sqlPhrases() {
|
|
2117
|
-
return this.elements.map((el) => {
|
|
2118
|
-
if (typeof el == "string") {
|
|
2119
|
-
return { sql: el };
|
|
2120
|
-
}
|
|
2121
|
-
return el.query();
|
|
2122
|
-
});
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
exports.SQLString = SQLString;
|
|
2126
|
-
class SQLStatement extends MalloyElement {
|
|
2127
|
-
constructor(select) {
|
|
2128
|
-
super();
|
|
2129
|
-
this.select = select;
|
|
2130
|
-
this.elementType = "sqlStatement";
|
|
2131
|
-
this.has({ select });
|
|
2132
|
-
}
|
|
2133
|
-
sqlBlock() {
|
|
2134
|
-
if (!this.requestBlock) {
|
|
2135
|
-
this.requestBlock = (0, sql_block_1.makeSQLBlock)(this.select.sqlPhrases(), this.connection);
|
|
2136
|
-
}
|
|
2137
|
-
return this.requestBlock;
|
|
2138
|
-
}
|
|
2139
|
-
/**
|
|
2140
|
-
* This is the one statement which pauses execution. First time through
|
|
2141
|
-
* it will generate a schema request, next time through it will either
|
|
2142
|
-
* record the error or record the schema.
|
|
2143
|
-
*/
|
|
2144
|
-
execute(doc) {
|
|
2145
|
-
var _a;
|
|
2146
|
-
const sqlDefEntry = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.sqlQueryZone;
|
|
2147
|
-
if (!sqlDefEntry) {
|
|
2148
|
-
this.log("Cant't look up schema for sql block");
|
|
2149
|
-
return;
|
|
2150
|
-
}
|
|
2151
|
-
const sql = this.sqlBlock();
|
|
2152
|
-
sqlDefEntry.reference(sql.name, this.location);
|
|
2153
|
-
const lookup = sqlDefEntry.getEntry(sql.name);
|
|
2154
|
-
if (lookup.status == "error") {
|
|
2155
|
-
const msgLines = lookup.message.split(/\r?\n/);
|
|
2156
|
-
this.select.log("Invalid SQL, " + msgLines.join("\n "));
|
|
2157
|
-
return undefined;
|
|
2158
|
-
}
|
|
2159
|
-
if (lookup.status == "present") {
|
|
2160
|
-
const location = this.select.location;
|
|
2161
|
-
const locStruct = {
|
|
2162
|
-
...lookup.value,
|
|
2163
|
-
fields: lookup.value.fields.map((f) => ({ ...f, location })),
|
|
2164
|
-
location: this.location,
|
|
2165
|
-
};
|
|
2166
|
-
if (this.is && !doc.defineSQL(locStruct, this.is)) {
|
|
2167
|
-
this.log(`'${this.is}' already defined`);
|
|
2168
|
-
}
|
|
2169
|
-
return undefined;
|
|
2170
|
-
}
|
|
2171
|
-
return {
|
|
2172
|
-
compileSQL: sql,
|
|
2173
|
-
partialModel: this.select.containsQueries ? doc.modelDef() : undefined,
|
|
2174
|
-
};
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
exports.SQLStatement = SQLStatement;
|
|
2178
|
-
class SampleProperty extends MalloyElement {
|
|
2179
|
-
constructor(sample) {
|
|
2180
|
-
super();
|
|
2181
|
-
this.sample = sample;
|
|
2182
|
-
this.elementType = "sampleProperty";
|
|
2183
|
-
}
|
|
2184
|
-
sampling() {
|
|
2185
|
-
return this.sample;
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
exports.SampleProperty = SampleProperty;
|
|
2189
|
-
/**
|
|
2190
|
-
* Root node for any element in an expression. These essentially
|
|
2191
|
-
* create a sub-tree in the larger AST. Expression nodes know
|
|
2192
|
-
* how to write themselves as SQL (or rather, generate the
|
|
2193
|
-
* template for SQL required by the query writer)
|
|
2194
|
-
*/
|
|
2195
|
-
class ExpressionDef extends MalloyElement {
|
|
2196
|
-
constructor() {
|
|
2197
|
-
super(...arguments);
|
|
2198
|
-
this.legalChildTypes = ast_types_1.FT.anyAtomicT;
|
|
2199
|
-
}
|
|
2200
|
-
granular() {
|
|
2201
|
-
return false;
|
|
2202
|
-
}
|
|
2203
|
-
/**
|
|
2204
|
-
* Some operators want to give the right hand value a chance to
|
|
2205
|
-
* rewrite itself. This requests a translation for a rewrite,
|
|
2206
|
-
* or returns undefined if that request should be denied.
|
|
2207
|
-
* @param fs FieldSpace
|
|
2208
|
-
* @returns Translated expression or undefined
|
|
2209
|
-
*/
|
|
2210
|
-
requestExpression(fs) {
|
|
2211
|
-
return this.getExpression(fs);
|
|
2212
|
-
}
|
|
2213
|
-
defaultFieldName() {
|
|
2214
|
-
return undefined;
|
|
2215
|
-
}
|
|
2216
|
-
/**
|
|
2217
|
-
* Check an expression for type compatibility
|
|
2218
|
-
* @param _eNode currently unused, will be used to get error location
|
|
2219
|
-
* @param eVal ...list of expressions that must match legalChildTypes
|
|
2220
|
-
*/
|
|
2221
|
-
typeCheck(eNode, eVal) {
|
|
2222
|
-
if (!ast_types_1.FT.in(eVal, this.legalChildTypes)) {
|
|
2223
|
-
eNode.log(`'${this.elementType}' Can't use type ${ast_types_1.FT.inspect(eVal)}`);
|
|
2224
|
-
return false;
|
|
2225
|
-
}
|
|
2226
|
-
return true;
|
|
2227
|
-
}
|
|
2228
|
-
/**
|
|
2229
|
-
* This is the operation which makes partial comparison and value trees work
|
|
2230
|
-
* The default implemention merely constructs LEFT OP RIGHT, but specialized
|
|
2231
|
-
* nodes like alternation trees or or partial comparison can control how
|
|
2232
|
-
* the appplication gets generated
|
|
2233
|
-
* @param fs The symbol table
|
|
2234
|
-
* @param op The operator being applied
|
|
2235
|
-
* @param expr The "other" (besdies 'this') value
|
|
2236
|
-
* @returns The translated expression
|
|
2237
|
-
*/
|
|
2238
|
-
apply(fs, op, left) {
|
|
2239
|
-
return applyBinary(fs, left, op, this);
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
2242
|
-
exports.ExpressionDef = ExpressionDef;
|
|
2243
|
-
class ConstantSubExpression extends ExpressionDef {
|
|
2244
|
-
constructor(expr) {
|
|
2245
|
-
super({ expr });
|
|
2246
|
-
this.expr = expr;
|
|
2247
|
-
this.elementType = "constantExpression";
|
|
2248
|
-
}
|
|
2249
|
-
getExpression(_fs) {
|
|
2250
|
-
return this.constantValue();
|
|
2251
|
-
}
|
|
2252
|
-
get constantFs() {
|
|
2253
|
-
if (!this.cfs) {
|
|
2254
|
-
this.cfs = new ConstantFieldSpace();
|
|
2255
|
-
}
|
|
2256
|
-
return this.cfs;
|
|
2257
|
-
}
|
|
2258
|
-
constantValue() {
|
|
2259
|
-
return this.expr.getExpression(this.constantFs);
|
|
2260
|
-
}
|
|
2261
|
-
constantCondition(type) {
|
|
2262
|
-
const compareAndContrast = new ExprCompare(new DollarReference(type), "=", this.expr);
|
|
2263
|
-
const application = compareAndContrast.getExpression(this.constantFs);
|
|
2264
|
-
return { ...application, value: (0, ast_types_1.compressExpr)(application.value) };
|
|
2265
|
-
}
|
|
2266
|
-
apply(fs, op, expr) {
|
|
2267
|
-
return this.expr.apply(fs, op, expr);
|
|
2268
|
-
}
|
|
2269
|
-
requestExpression(fs) {
|
|
2270
|
-
return this.expr.requestExpression(fs);
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
exports.ConstantSubExpression = ConstantSubExpression;
|
|
2274
|
-
class DollarReference extends ExpressionDef {
|
|
2275
|
-
constructor(refType) {
|
|
2276
|
-
super();
|
|
2277
|
-
this.refType = refType;
|
|
2278
|
-
this.elementType = "$";
|
|
2279
|
-
}
|
|
2280
|
-
getExpression(_fs) {
|
|
2281
|
-
return {
|
|
2282
|
-
dataType: this.refType,
|
|
2283
|
-
value: [{ type: "applyVal" }],
|
|
2284
|
-
expressionType: "scalar",
|
|
2285
|
-
};
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
class ConstantFieldSpace {
|
|
2289
|
-
constructor() {
|
|
2290
|
-
this.type = "fieldSpace";
|
|
2291
|
-
}
|
|
2292
|
-
structDef() {
|
|
2293
|
-
throw new Error("ConstantFieldSpace cannot generate a structDef");
|
|
2294
|
-
}
|
|
2295
|
-
emptyStructDef() {
|
|
2296
|
-
throw new Error("ConstantFieldSpace cannot generate a structDef");
|
|
2297
|
-
}
|
|
2298
|
-
lookup(_name) {
|
|
2299
|
-
return {
|
|
2300
|
-
error: "Only constants allowed in parameter expressions",
|
|
2301
|
-
found: undefined,
|
|
2302
|
-
};
|
|
2303
|
-
}
|
|
2304
|
-
dialectObj() {
|
|
2305
|
-
return undefined;
|
|
2306
|
-
}
|
|
2307
|
-
whenComplete(step) {
|
|
2308
|
-
step();
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
class FieldDeclaration extends MalloyElement {
|
|
2312
|
-
constructor(expr, defineName, exprSrc) {
|
|
2313
|
-
super({ expr });
|
|
2314
|
-
this.expr = expr;
|
|
2315
|
-
this.defineName = defineName;
|
|
2316
|
-
this.exprSrc = exprSrc;
|
|
2317
|
-
this.elementType = "fieldDeclaration";
|
|
2318
|
-
}
|
|
2319
|
-
fieldDef(fs, exprName) {
|
|
2320
|
-
/*
|
|
2321
|
-
* In an explore we cannot reference the thing we are defining, you need
|
|
2322
|
-
* to use rename. In a query, the output space is a new thing, and expressions
|
|
2323
|
-
* can reference the outer value in order to make a value with the new name,
|
|
2324
|
-
* and it feels wrong that this is HERE and not somehow in the QueryOperation.
|
|
2325
|
-
* For now, this stops the stack overflow, and passes all tests, but I think
|
|
2326
|
-
* a refactor of QueryFieldSpace might someday be the place where this should
|
|
2327
|
-
* happen.
|
|
2328
|
-
*/
|
|
2329
|
-
return this.queryFieldDef(new DefSpace(fs, this), exprName);
|
|
2330
|
-
}
|
|
2331
|
-
queryFieldDef(exprFS, exprName) {
|
|
2332
|
-
let exprValue;
|
|
2333
|
-
try {
|
|
2334
|
-
exprValue = this.expr.getExpression(exprFS);
|
|
2335
|
-
}
|
|
2336
|
-
catch (error) {
|
|
2337
|
-
this.log(`Cannot define '${exprName}', ${error.message}`);
|
|
2338
|
-
return {
|
|
2339
|
-
name: `error_defining_${exprName}`,
|
|
2340
|
-
type: "string",
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2343
|
-
const compressValue = (0, ast_types_1.compressExpr)(exprValue.value);
|
|
2344
|
-
const retType = exprValue.dataType;
|
|
2345
|
-
if ((0, malloy_types_1.isAtomicFieldType)(retType)) {
|
|
2346
|
-
const template = {
|
|
2347
|
-
name: exprName,
|
|
2348
|
-
type: retType,
|
|
2349
|
-
location: this.location,
|
|
2350
|
-
};
|
|
2351
|
-
if (compressValue.length > 0) {
|
|
2352
|
-
template.e = compressValue;
|
|
2353
|
-
}
|
|
2354
|
-
if (exprValue.expressionType) {
|
|
2355
|
-
template.expressionType = exprValue.expressionType;
|
|
2356
|
-
}
|
|
2357
|
-
if (this.exprSrc) {
|
|
2358
|
-
template.code = this.exprSrc;
|
|
2359
|
-
}
|
|
2360
|
-
// TODO this should work for dates too
|
|
2361
|
-
if ((0, ast_types_1.isGranularResult)(exprValue) && template.type === "timestamp") {
|
|
2362
|
-
template.timeframe = exprValue.timeframe;
|
|
2363
|
-
}
|
|
2364
|
-
return template;
|
|
2365
|
-
}
|
|
2366
|
-
const circularDef = exprFS instanceof DefSpace && exprFS.foundCircle;
|
|
2367
|
-
if (!circularDef) {
|
|
2368
|
-
if (exprValue.dataType == "unknown") {
|
|
2369
|
-
this.log(`Cannot define '${exprName}', value has unknown type`);
|
|
2370
|
-
}
|
|
2371
|
-
else {
|
|
2372
|
-
const badType = ast_types_1.FT.inspect(exprValue);
|
|
2373
|
-
this.log(`Cannot define '${exprName}', unexpected type: ${badType}`);
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
return {
|
|
2377
|
-
name: `error_defining_${exprName}`,
|
|
2378
|
-
type: "string",
|
|
2379
|
-
};
|
|
2380
|
-
}
|
|
2381
|
-
}
|
|
2382
|
-
exports.FieldDeclaration = FieldDeclaration;
|
|
2383
|
-
/**
|
|
2384
|
-
* All of the magic of malloy expressions eventually flows to here,
|
|
2385
|
-
* where an operator is applied to two values. Depending on the
|
|
2386
|
-
* operator and value types this may involve transformations of
|
|
2387
|
-
* the values or even the operator.
|
|
2388
|
-
* @param fs FieldSpace for the symbols
|
|
2389
|
-
* @param left Left value
|
|
2390
|
-
* @param op The operator
|
|
2391
|
-
* @param right Right Value
|
|
2392
|
-
* @returns ExprValue of the expression
|
|
2393
|
-
*/
|
|
2394
|
-
function applyBinary(fs, left, op, right) {
|
|
2395
|
-
if ((0, ast_types_1.isEquality)(op)) {
|
|
2396
|
-
return equality(fs, left, op, right);
|
|
2397
|
-
}
|
|
2398
|
-
if ((0, ast_types_1.isComparison)(op)) {
|
|
2399
|
-
return compare(fs, left, op, right);
|
|
2400
|
-
}
|
|
2401
|
-
if (oneOf(op, "+", "-")) {
|
|
2402
|
-
return delta(fs, left, op, right);
|
|
2403
|
-
}
|
|
2404
|
-
if (oneOf(op, "*", "%")) {
|
|
2405
|
-
return numeric(fs, left, op, right);
|
|
2406
|
-
}
|
|
2407
|
-
if (oneOf(op, "/")) {
|
|
2408
|
-
const num = left.getExpression(fs);
|
|
2409
|
-
const denom = right.getExpression(fs);
|
|
2410
|
-
if (num.dataType != "number") {
|
|
2411
|
-
left.log("Numerator for division must be a number");
|
|
2412
|
-
}
|
|
2413
|
-
else if (denom.dataType != "number") {
|
|
2414
|
-
right.log("Denominator for division must be a number");
|
|
2415
|
-
}
|
|
2416
|
-
else {
|
|
2417
|
-
const div = {
|
|
2418
|
-
type: "dialect",
|
|
2419
|
-
function: "div",
|
|
2420
|
-
numerator: num.value,
|
|
2421
|
-
denominator: denom.value,
|
|
2422
|
-
};
|
|
2423
|
-
return {
|
|
2424
|
-
dataType: "number",
|
|
2425
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(num.expressionType, denom.expressionType),
|
|
2426
|
-
value: [div],
|
|
2427
|
-
};
|
|
2428
|
-
}
|
|
2429
|
-
return (0, ast_types_1.errorFor)("divide type mismatch");
|
|
2430
|
-
}
|
|
2431
|
-
left.log(`Canot use ${op} operator here`);
|
|
2432
|
-
return (0, ast_types_1.errorFor)("applybinary bad operator");
|
|
2433
|
-
}
|
|
2434
|
-
exports.applyBinary = applyBinary;
|
|
2435
|
-
class BinaryBoolean extends ExpressionDef {
|
|
2436
|
-
constructor(left, op, right) {
|
|
2437
|
-
super({ left, right });
|
|
2438
|
-
this.left = left;
|
|
2439
|
-
this.op = op;
|
|
2440
|
-
this.right = right;
|
|
2441
|
-
this.elementType = "abstract boolean binary";
|
|
2442
|
-
this.legalChildTypes = [ast_types_1.FT.boolT];
|
|
2443
|
-
}
|
|
2444
|
-
getExpression(fs) {
|
|
2445
|
-
const left = this.left.getExpression(fs);
|
|
2446
|
-
const right = this.right.getExpression(fs);
|
|
2447
|
-
if (this.typeCheck(this.left, left) && this.typeCheck(this.right, right)) {
|
|
2448
|
-
return {
|
|
2449
|
-
dataType: "boolean",
|
|
2450
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(left.expressionType, right.expressionType),
|
|
2451
|
-
value: (0, ast_types_1.compose)(left.value, this.op, right.value),
|
|
2452
|
-
};
|
|
2453
|
-
}
|
|
2454
|
-
return (0, ast_types_1.errorFor)("logial required boolean");
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
exports.BinaryBoolean = BinaryBoolean;
|
|
2458
|
-
class ExprCompare extends BinaryBoolean {
|
|
2459
|
-
constructor(left, op, right) {
|
|
2460
|
-
super(left, op, right);
|
|
2461
|
-
this.elementType = "a<=>b";
|
|
2462
|
-
this.legalChildTypes = compareTypes[op];
|
|
2463
|
-
}
|
|
2464
|
-
getExpression(fs) {
|
|
2465
|
-
if (!this.right.granular()) {
|
|
2466
|
-
const rhs = this.right.requestExpression(fs);
|
|
2467
|
-
if (rhs && (0, ast_types_1.isGranularResult)(rhs)) {
|
|
2468
|
-
const newRight = new ExprGranularTime(this.right, rhs.timeframe, false);
|
|
2469
|
-
return newRight.apply(fs, this.op, this.left);
|
|
2470
|
-
}
|
|
2471
|
-
}
|
|
2472
|
-
return this.right.apply(fs, this.op, this.left);
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
exports.ExprCompare = ExprCompare;
|
|
2476
|
-
function equality(fs, left, op, right) {
|
|
2477
|
-
const lhs = left.getExpression(fs);
|
|
2478
|
-
const rhs = right.getExpression(fs);
|
|
2479
|
-
let value = timeCompare(lhs, op, rhs) || (0, ast_types_1.compose)(lhs.value, op, rhs.value);
|
|
2480
|
-
if (lhs.dataType != "unknown" && rhs.dataType != "unknown") {
|
|
2481
|
-
switch (op) {
|
|
2482
|
-
case "~":
|
|
2483
|
-
case "!~": {
|
|
2484
|
-
if (lhs.dataType === "string" && rhs.dataType === "string") {
|
|
2485
|
-
value = (0, ast_types_1.compose)(lhs.value, "LIKE", rhs.value);
|
|
2486
|
-
}
|
|
2487
|
-
else {
|
|
2488
|
-
const regexCmp = regexEqual(lhs, rhs);
|
|
2489
|
-
if (regexCmp === undefined) {
|
|
2490
|
-
throw new TypeMistmatch("Incompatible types for match('~') operator");
|
|
2491
|
-
}
|
|
2492
|
-
value = regexCmp;
|
|
2493
|
-
}
|
|
2494
|
-
value = (0, apply_expr_1.nullsafeNot)(value, op);
|
|
2495
|
-
break;
|
|
2496
|
-
}
|
|
2497
|
-
case "=":
|
|
2498
|
-
case "!=": {
|
|
2499
|
-
const nullCmp = nullCompare(lhs, op, rhs);
|
|
2500
|
-
if (nullCmp) {
|
|
2501
|
-
value = nullCmp;
|
|
2502
|
-
}
|
|
2503
|
-
else {
|
|
2504
|
-
value = (0, apply_expr_1.nullsafeNot)(regexEqual(lhs, rhs) || (0, ast_types_1.compose)(lhs.value, "=", rhs.value), op);
|
|
2505
|
-
}
|
|
2506
|
-
break;
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2510
|
-
return {
|
|
2511
|
-
dataType: "boolean",
|
|
2512
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType),
|
|
2513
|
-
value,
|
|
2514
|
-
};
|
|
2515
|
-
}
|
|
2516
|
-
function compare(fs, left, op, right) {
|
|
2517
|
-
const lhs = left.getExpression(fs);
|
|
2518
|
-
const rhs = right.getExpression(fs);
|
|
2519
|
-
const expressionType = (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType);
|
|
2520
|
-
const value = timeCompare(lhs, op, rhs) || (0, ast_types_1.compose)(lhs.value, op, rhs.value);
|
|
2521
|
-
return {
|
|
2522
|
-
dataType: "boolean",
|
|
2523
|
-
expressionType,
|
|
2524
|
-
value: value,
|
|
2525
|
-
};
|
|
2526
|
-
}
|
|
2527
|
-
function oneOf(op, ...operators) {
|
|
2528
|
-
return operators.includes(op);
|
|
2529
|
-
}
|
|
2530
|
-
function delta(fs, left, op, right) {
|
|
2531
|
-
const lhs = left.getExpression(fs);
|
|
2532
|
-
const rhs = right.getExpression(fs);
|
|
2533
|
-
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType)) {
|
|
2534
|
-
let duration = right;
|
|
2535
|
-
if (rhs.dataType !== "duration") {
|
|
2536
|
-
if ((0, ast_types_1.isGranularResult)(lhs)) {
|
|
2537
|
-
duration = new ExprDuration(right, lhs.timeframe);
|
|
2538
|
-
}
|
|
2539
|
-
else if (lhs.dataType === "date") {
|
|
2540
|
-
duration = new ExprDuration(right, "day");
|
|
2541
|
-
}
|
|
2542
|
-
else {
|
|
2543
|
-
left.log(`Can not offset time by '${rhs.dataType}'`);
|
|
2544
|
-
return (0, ast_types_1.errorFor)(`time plus ${rhs.dataType}`);
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
return duration.apply(fs, op, left);
|
|
2548
|
-
}
|
|
2549
|
-
return numeric(fs, left, op, right);
|
|
2550
|
-
}
|
|
2551
|
-
function numeric(fs, left, op, right) {
|
|
2552
|
-
const lhs = left.getExpression(fs);
|
|
2553
|
-
const rhs = right.getExpression(fs);
|
|
2554
|
-
const expressionType = (0, malloy_types_1.maxExpressionType)(lhs.expressionType, rhs.expressionType);
|
|
2555
|
-
if (allAre("number", lhs, rhs)) {
|
|
2556
|
-
return {
|
|
2557
|
-
dataType: "number",
|
|
2558
|
-
expressionType,
|
|
2559
|
-
value: (0, ast_types_1.compose)(lhs.value, op, rhs.value),
|
|
2560
|
-
};
|
|
2561
|
-
}
|
|
2562
|
-
left.log(`Non numeric('${lhs.dataType},${rhs.dataType}') value with '${op}'`);
|
|
2563
|
-
return (0, ast_types_1.errorFor)("numbers required");
|
|
2564
|
-
}
|
|
2565
|
-
const compareTypes = {
|
|
2566
|
-
"~": [ast_types_1.FT.stringT],
|
|
2567
|
-
"!~": [ast_types_1.FT.stringT],
|
|
2568
|
-
"<": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2569
|
-
"<=": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2570
|
-
"=": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2571
|
-
"!=": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2572
|
-
">=": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2573
|
-
">": [ast_types_1.FT.numberT, ast_types_1.FT.stringT, ast_types_1.FT.dateT, ast_types_1.FT.timestampT],
|
|
2574
|
-
};
|
|
2575
|
-
/**
|
|
2576
|
-
* GranularTime is a moment in time which ALSO has a "granularity"
|
|
2577
|
-
* commonly this are created by applying ".datePart" to an expression
|
|
2578
|
-
* 1) They have a value, which is the moment in time
|
|
2579
|
-
* 2) When used in a comparison, they act like a range, for the
|
|
2580
|
-
* duration of 1 unit of granularity
|
|
2581
|
-
*/
|
|
2582
|
-
class ExprGranularTime extends ExpressionDef {
|
|
2583
|
-
constructor(expr, units, truncate) {
|
|
2584
|
-
super({ expr });
|
|
2585
|
-
this.expr = expr;
|
|
2586
|
-
this.units = units;
|
|
2587
|
-
this.truncate = truncate;
|
|
2588
|
-
this.elementType = "granularTime";
|
|
2589
|
-
this.legalChildTypes = [ast_types_1.FT.timestampT, ast_types_1.FT.dateT];
|
|
2590
|
-
}
|
|
2591
|
-
granular() {
|
|
2592
|
-
return true;
|
|
2593
|
-
}
|
|
2594
|
-
getExpression(fs) {
|
|
2595
|
-
const timeframe = this.units;
|
|
2596
|
-
const exprVal = this.expr.getExpression(fs);
|
|
2597
|
-
if ((0, malloy_types_1.isTimeFieldType)(exprVal.dataType)) {
|
|
2598
|
-
const tsVal = {
|
|
2599
|
-
...exprVal,
|
|
2600
|
-
dataType: exprVal.dataType,
|
|
2601
|
-
timeframe: timeframe,
|
|
2602
|
-
};
|
|
2603
|
-
if (this.truncate) {
|
|
2604
|
-
tsVal.value = [
|
|
2605
|
-
{
|
|
2606
|
-
type: "dialect",
|
|
2607
|
-
function: "trunc",
|
|
2608
|
-
expr: { value: exprVal.value, valueType: exprVal.dataType },
|
|
2609
|
-
units: timeframe,
|
|
2610
|
-
},
|
|
2611
|
-
];
|
|
2612
|
-
}
|
|
2613
|
-
return tsVal;
|
|
2614
|
-
}
|
|
2615
|
-
this.log(`Cannot do time truncation on type '${exprVal.dataType}'`);
|
|
2616
|
-
return (0, ast_types_1.errorFor)(`granularity typecheck`);
|
|
2617
|
-
}
|
|
2618
|
-
apply(fs, op, left) {
|
|
2619
|
-
const rangeType = this.getExpression(fs).dataType;
|
|
2620
|
-
const _valueType = left.getExpression(fs).dataType;
|
|
2621
|
-
const granularityType = (0, malloy_types_1.isDateUnit)(this.units) ? "date" : "timestamp";
|
|
2622
|
-
if (rangeType == "date" && granularityType == "date") {
|
|
2623
|
-
return this.dateRange(fs, op, left);
|
|
2624
|
-
}
|
|
2625
|
-
return this.timestampRange(fs, op, left);
|
|
2626
|
-
/*
|
|
2627
|
-
write tests for each of these cases ....
|
|
2628
|
-
|
|
2629
|
-
vt rt gt use
|
|
2630
|
-
dt dt dt dateRange
|
|
2631
|
-
dt dt ts == or timeStampRange
|
|
2632
|
-
dt ts dt timestampRange
|
|
2633
|
-
dt ts ts timeStampRange
|
|
2634
|
-
|
|
2635
|
-
ts ts ts timestampRange
|
|
2636
|
-
ts ts dt timestampRange
|
|
2637
|
-
ts dt ts timestampRange
|
|
2638
|
-
ts dt dt either
|
|
2639
|
-
|
|
2640
|
-
*/
|
|
2641
|
-
}
|
|
2642
|
-
timestampRange(fs, op, expr) {
|
|
2643
|
-
const begin = this.getExpression(fs);
|
|
2644
|
-
const beginTime = ExprTime.fromValue("timestamp", begin);
|
|
2645
|
-
const endTime = new ExprTime("timestamp", (0, time_utils_1.timeOffset)("timestamp", begin.value, "+", (0, malloy_types_1.mkExpr) `1`, this.units), begin.expressionType);
|
|
2646
|
-
const range = new Range(beginTime, endTime);
|
|
2647
|
-
return range.apply(fs, op, expr);
|
|
2648
|
-
}
|
|
2649
|
-
dateRange(fs, op, expr) {
|
|
2650
|
-
const begin = this.getExpression(fs);
|
|
2651
|
-
const beginTime = new ExprTime("date", begin.value, begin.expressionType);
|
|
2652
|
-
const endAt = (0, time_utils_1.timeOffset)("date", begin.value, "+", ["1"], this.units);
|
|
2653
|
-
const end = new ExprTime("date", endAt, begin.expressionType);
|
|
2654
|
-
const range = new Range(beginTime, end);
|
|
2655
|
-
return range.apply(fs, op, expr);
|
|
2656
|
-
}
|
|
2657
|
-
}
|
|
2658
|
-
exports.ExprGranularTime = ExprGranularTime;
|
|
2659
|
-
function timeCompare(lhs, op, rhs) {
|
|
2660
|
-
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType) && (0, malloy_types_1.isTimeFieldType)(rhs.dataType)) {
|
|
2661
|
-
if (lhs.dataType !== rhs.dataType) {
|
|
2662
|
-
let lval = lhs.value;
|
|
2663
|
-
let rval = rhs.value;
|
|
2664
|
-
if (lhs.dataType === "timestamp") {
|
|
2665
|
-
lval = (0, time_utils_1.castTimestampToDate)(lval);
|
|
2666
|
-
}
|
|
2667
|
-
else {
|
|
2668
|
-
rval = (0, time_utils_1.castTimestampToDate)(rval);
|
|
2669
|
-
}
|
|
2670
|
-
return (0, ast_types_1.compose)(lval, op, rval);
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
return undefined;
|
|
2674
|
-
}
|
|
2675
|
-
function regexEqual(left, right) {
|
|
2676
|
-
if (left.dataType === "string") {
|
|
2677
|
-
if (right.dataType === "regular expression") {
|
|
2678
|
-
return [
|
|
2679
|
-
{
|
|
2680
|
-
type: "dialect",
|
|
2681
|
-
function: "regexpMatch",
|
|
2682
|
-
expr: left.value,
|
|
2683
|
-
regexp: right.value[0].replace(/^r'/, "'"),
|
|
2684
|
-
},
|
|
2685
|
-
];
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
else if (right.dataType === "string") {
|
|
2689
|
-
if (left.dataType === "regular expression") {
|
|
2690
|
-
return [
|
|
2691
|
-
{
|
|
2692
|
-
type: "dialect",
|
|
2693
|
-
function: "regexpMatch",
|
|
2694
|
-
expr: right.value,
|
|
2695
|
-
regexp: left.value[0].replace(/^r'/, "'"),
|
|
2696
|
-
},
|
|
2697
|
-
];
|
|
2698
|
-
}
|
|
2699
|
-
}
|
|
2700
|
-
return undefined;
|
|
2701
|
-
}
|
|
2702
|
-
class TypeMistmatch extends Error {
|
|
2703
|
-
}
|
|
2704
|
-
exports.TypeMistmatch = TypeMistmatch;
|
|
2705
|
-
function nullCompare(left, op, right) {
|
|
2706
|
-
const not = op === "!=" || op === "!~";
|
|
2707
|
-
if (left.dataType === "null" || right.dataType === "null") {
|
|
2708
|
-
const maybeNot = not ? " NOT" : "";
|
|
2709
|
-
if (left.dataType !== "null") {
|
|
2710
|
-
return [...left.value, ` IS${maybeNot} NULL`];
|
|
2711
|
-
}
|
|
2712
|
-
if (right.dataType !== "null") {
|
|
2713
|
-
return [...right.value, `IS${maybeNot} NULL`];
|
|
2714
|
-
}
|
|
2715
|
-
return [not ? "false" : "true"];
|
|
2716
|
-
}
|
|
2717
|
-
return undefined;
|
|
2718
|
-
}
|
|
2719
|
-
class ExprDuration extends ExpressionDef {
|
|
2720
|
-
constructor(n, timeframe) {
|
|
2721
|
-
super({ n });
|
|
2722
|
-
this.n = n;
|
|
2723
|
-
this.timeframe = timeframe;
|
|
2724
|
-
this.elementType = "duration";
|
|
2725
|
-
this.legalChildTypes = [ast_types_1.FT.timestampT, ast_types_1.FT.dateT];
|
|
2726
|
-
}
|
|
2727
|
-
apply(fs, op, left) {
|
|
2728
|
-
const lhs = left.getExpression(fs);
|
|
2729
|
-
this.typeCheck(this, lhs);
|
|
2730
|
-
if ((0, malloy_types_1.isTimeFieldType)(lhs.dataType) && (op === "+" || op === "-")) {
|
|
2731
|
-
const num = this.n.getExpression(fs);
|
|
2732
|
-
if (!ast_types_1.FT.typeEq(num, ast_types_1.FT.numberT)) {
|
|
2733
|
-
this.log(`Duration units needs number not '${num.dataType}`);
|
|
2734
|
-
return (0, ast_types_1.errorFor)("illegal unit expression");
|
|
2735
|
-
}
|
|
2736
|
-
let resultGranularity;
|
|
2737
|
-
// Only allow the output of this to be granular if the
|
|
2738
|
-
// granularities match, this is still an area where
|
|
2739
|
-
// more thought is required.
|
|
2740
|
-
if ((0, ast_types_1.isGranularResult)(lhs) && lhs.timeframe == this.timeframe) {
|
|
2741
|
-
resultGranularity = lhs.timeframe;
|
|
2742
|
-
}
|
|
2743
|
-
if (lhs.dataType === "timestamp") {
|
|
2744
|
-
const result = (0, time_utils_1.timeOffset)("timestamp", lhs.value, op, num.value, this.timeframe);
|
|
2745
|
-
return (0, time_utils_1.timeResult)({
|
|
2746
|
-
dataType: "timestamp",
|
|
2747
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(lhs.expressionType, num.expressionType),
|
|
2748
|
-
value: result,
|
|
2749
|
-
}, resultGranularity);
|
|
2750
|
-
}
|
|
2751
|
-
return (0, time_utils_1.timeResult)({
|
|
2752
|
-
dataType: "date",
|
|
2753
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(lhs.expressionType, num.expressionType),
|
|
2754
|
-
value: (0, time_utils_1.timeOffset)("date", lhs.value, op, num.value, this.timeframe),
|
|
2755
|
-
}, resultGranularity);
|
|
2756
|
-
}
|
|
2757
|
-
return super.apply(fs, op, left);
|
|
2758
|
-
}
|
|
2759
|
-
getExpression(_fs) {
|
|
2760
|
-
return {
|
|
2761
|
-
dataType: "duration",
|
|
2762
|
-
expressionType: "scalar",
|
|
2763
|
-
value: ["__ERROR_DURATION_IS_NOT_A_VALUE__"],
|
|
2764
|
-
};
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
exports.ExprDuration = ExprDuration;
|
|
2768
|
-
function allAre(oneType, ...values) {
|
|
2769
|
-
for (const v of values) {
|
|
2770
|
-
if (v.dataType !== oneType) {
|
|
2771
|
-
return false;
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
return true;
|
|
2775
|
-
}
|
|
2776
|
-
class ExprTime extends ExpressionDef {
|
|
2777
|
-
constructor(timeType, value, expressionType = "scalar") {
|
|
2778
|
-
super();
|
|
2779
|
-
this.elementType = "timestampOrDate";
|
|
2780
|
-
this.elementType = timeType;
|
|
2781
|
-
this.translationValue = {
|
|
2782
|
-
dataType: timeType,
|
|
2783
|
-
expressionType,
|
|
2784
|
-
value: typeof value === "string" ? [value] : value,
|
|
2785
|
-
};
|
|
2786
|
-
}
|
|
2787
|
-
getExpression(_fs) {
|
|
2788
|
-
return this.translationValue;
|
|
2789
|
-
}
|
|
2790
|
-
static fromValue(timeType, expr) {
|
|
2791
|
-
let value = expr.value;
|
|
2792
|
-
if (timeType != expr.dataType) {
|
|
2793
|
-
const toTs = {
|
|
2794
|
-
type: "dialect",
|
|
2795
|
-
function: "cast",
|
|
2796
|
-
safe: false,
|
|
2797
|
-
dstType: timeType,
|
|
2798
|
-
expr: expr.value,
|
|
2799
|
-
};
|
|
2800
|
-
if ((0, malloy_types_1.isTimeFieldType)(expr.dataType)) {
|
|
2801
|
-
toTs.srcType = expr.dataType;
|
|
2802
|
-
}
|
|
2803
|
-
value = (0, ast_types_1.compressExpr)([toTs]);
|
|
2804
|
-
}
|
|
2805
|
-
return new ExprTime(timeType, value, expr.expressionType);
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
exports.ExprTime = ExprTime;
|
|
2809
|
-
class Range extends ExpressionDef {
|
|
2810
|
-
constructor(first, last) {
|
|
2811
|
-
super({ first, last });
|
|
2812
|
-
this.first = first;
|
|
2813
|
-
this.last = last;
|
|
2814
|
-
this.elementType = "range";
|
|
2815
|
-
}
|
|
2816
|
-
apply(fs, op, expr) {
|
|
2817
|
-
switch (op) {
|
|
2818
|
-
case "=":
|
|
2819
|
-
case "!=": {
|
|
2820
|
-
const op1 = op === "=" ? ">=" : "<";
|
|
2821
|
-
const op2 = op === "=" ? "and" : "or";
|
|
2822
|
-
const op3 = op === "=" ? "<" : ">=";
|
|
2823
|
-
const fromValue = this.first.apply(fs, op1, expr);
|
|
2824
|
-
const toValue = this.last.apply(fs, op3, expr);
|
|
2825
|
-
return {
|
|
2826
|
-
dataType: "boolean",
|
|
2827
|
-
expressionType: (0, malloy_types_1.maxExpressionType)(fromValue.expressionType, toValue.expressionType),
|
|
2828
|
-
value: (0, ast_types_1.compose)(fromValue.value, op2, toValue.value),
|
|
2829
|
-
};
|
|
2830
|
-
}
|
|
2831
|
-
/**
|
|
2832
|
-
* This is a little surprising, but is actually how you comapre a
|
|
2833
|
-
* value to a range ...
|
|
2834
|
-
*
|
|
2835
|
-
* val > begin to end val >= end
|
|
2836
|
-
* val >= begin to end val >= begin
|
|
2837
|
-
* val < begin to end val < begin
|
|
2838
|
-
* val <= begin to end val < end
|
|
2839
|
-
*/
|
|
2840
|
-
case ">":
|
|
2841
|
-
return this.last.apply(fs, ">=", expr);
|
|
2842
|
-
case ">=":
|
|
2843
|
-
return this.first.apply(fs, ">=", expr);
|
|
2844
|
-
case "<":
|
|
2845
|
-
return this.first.apply(fs, "<", expr);
|
|
2846
|
-
case "<=":
|
|
2847
|
-
return this.last.apply(fs, "<", expr);
|
|
2848
|
-
}
|
|
2849
|
-
throw new Error("mysterious error in range computation");
|
|
2850
|
-
}
|
|
2851
|
-
requestExpression(_fs) {
|
|
2852
|
-
return undefined;
|
|
2853
|
-
}
|
|
2854
|
-
getExpression(_fs) {
|
|
2855
|
-
return (0, ast_types_1.errorFor)("a range is not a value");
|
|
2856
|
-
}
|
|
2857
|
-
}
|
|
2858
|
-
exports.Range = Range;
|
|
2859
|
-
/**
|
|
2860
|
-
* Used to detect references to fields in the statement which defines them
|
|
2861
|
-
*/
|
|
2862
|
-
class DefSpace {
|
|
2863
|
-
constructor(realFS, circular) {
|
|
2864
|
-
this.realFS = realFS;
|
|
2865
|
-
this.circular = circular;
|
|
2866
|
-
this.type = "fieldSpace";
|
|
2867
|
-
this.foundCircle = false;
|
|
2868
|
-
}
|
|
2869
|
-
structDef() {
|
|
2870
|
-
return this.realFS.structDef();
|
|
2871
|
-
}
|
|
2872
|
-
emptyStructDef() {
|
|
2873
|
-
return this.realFS.emptyStructDef();
|
|
2874
|
-
}
|
|
2875
|
-
lookup(symbol) {
|
|
2876
|
-
if (symbol[0] && symbol[0].refString === this.circular.defineName) {
|
|
2877
|
-
this.foundCircle = true;
|
|
2878
|
-
return {
|
|
2879
|
-
error: `Circular reference to '${this.circular.defineName}' in definition`,
|
|
2880
|
-
found: undefined,
|
|
2881
|
-
};
|
|
2882
|
-
}
|
|
2883
|
-
return this.realFS.lookup(symbol);
|
|
2884
|
-
}
|
|
2885
|
-
dialectObj() {
|
|
2886
|
-
return this.realFS.dialectObj();
|
|
2887
|
-
}
|
|
2888
|
-
whenComplete(step) {
|
|
2889
|
-
this.realFS.whenComplete(step);
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
exports.DefSpace = DefSpace;
|
|
2893
|
-
class StaticSpace {
|
|
2894
|
-
constructor(sourceStructDef) {
|
|
2895
|
-
this.type = "fieldSpace";
|
|
2896
|
-
this.fromStruct = sourceStructDef;
|
|
2897
|
-
}
|
|
2898
|
-
whenComplete(step) {
|
|
2899
|
-
step();
|
|
2900
|
-
}
|
|
2901
|
-
dialectObj() {
|
|
2902
|
-
try {
|
|
2903
|
-
return (0, dialect_map_1.getDialect)(this.fromStruct.dialect);
|
|
2904
|
-
}
|
|
2905
|
-
catch {
|
|
2906
|
-
return undefined;
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
fromFieldDef(from) {
|
|
2910
|
-
if (from.type === "struct") {
|
|
2911
|
-
return new StructSpaceField(from);
|
|
2912
|
-
}
|
|
2913
|
-
else if (model.isTurtleDef(from)) {
|
|
2914
|
-
return new QueryFieldStruct(this, from);
|
|
2915
|
-
}
|
|
2916
|
-
// TODO field has a filter and needs to be a filteredalias
|
|
2917
|
-
return new ColumnSpaceField(from);
|
|
2918
|
-
}
|
|
2919
|
-
get map() {
|
|
2920
|
-
if (this.memoMap === undefined) {
|
|
2921
|
-
this.memoMap = {};
|
|
2922
|
-
for (const f of this.fromStruct.fields) {
|
|
2923
|
-
const name = f.as || f.name;
|
|
2924
|
-
this.memoMap[name] = this.fromFieldDef(f);
|
|
2925
|
-
}
|
|
2926
|
-
if (this.fromStruct.parameters) {
|
|
2927
|
-
for (const [paramName, paramDef] of Object.entries(this.fromStruct.parameters)) {
|
|
2928
|
-
if (this.memoMap[paramName]) {
|
|
2929
|
-
throw new Error(`In struct '${this.fromStruct.as || this.fromStruct.name}': ` +
|
|
2930
|
-
` : Field and parameter name conflict '${paramName}`);
|
|
2931
|
-
}
|
|
2932
|
-
this.memoMap[paramName] = new DefinedParameter(paramDef);
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
|
-
return this.memoMap;
|
|
2937
|
-
}
|
|
2938
|
-
dropEntries() {
|
|
2939
|
-
this.memoMap = {};
|
|
2940
|
-
}
|
|
2941
|
-
dropEntry(name) {
|
|
2942
|
-
delete this.map[name];
|
|
2943
|
-
}
|
|
2944
|
-
entry(name) {
|
|
2945
|
-
return this.map[name];
|
|
2946
|
-
}
|
|
2947
|
-
setEntry(name, value) {
|
|
2948
|
-
this.map[name] = value;
|
|
2949
|
-
}
|
|
2950
|
-
entries() {
|
|
2951
|
-
return Object.entries(this.map);
|
|
2952
|
-
}
|
|
2953
|
-
structDef() {
|
|
2954
|
-
return this.fromStruct;
|
|
2955
|
-
}
|
|
2956
|
-
emptyStructDef() {
|
|
2957
|
-
return { ...this.fromStruct, fields: [] };
|
|
2958
|
-
}
|
|
2959
|
-
lookup(path) {
|
|
2960
|
-
const head = path[0];
|
|
2961
|
-
const rest = path.slice(1);
|
|
2962
|
-
const found = this.entry(head.refString);
|
|
2963
|
-
if (!found) {
|
|
2964
|
-
return { error: `'${head}' is not defined`, found };
|
|
2965
|
-
}
|
|
2966
|
-
if (found instanceof SpaceField) {
|
|
2967
|
-
/*
|
|
2968
|
-
* TODO cache defs, post the addReference call to whenComplete
|
|
2969
|
-
*
|
|
2970
|
-
* In the cleanup phase of query space construction, it may check
|
|
2971
|
-
* the output space for ungrouping variables. However if an
|
|
2972
|
-
* ungrouping variable is a measure, the field expression value
|
|
2973
|
-
* needed to get the definition needs to be computed in the
|
|
2974
|
-
* input space of the query. There is a test which failed which
|
|
2975
|
-
* caused this code to be here, but this is really a bandaid.
|
|
2976
|
-
*
|
|
2977
|
-
* Some re-work of how to get the definition of a SpaceField
|
|
2978
|
-
* no matter what it is contained in needs to be thought out.
|
|
2979
|
-
*
|
|
2980
|
-
* ... or this check would look at the finalized output of
|
|
2981
|
-
* the namespace and not re-compile ...
|
|
2982
|
-
*/
|
|
2983
|
-
const definition = found.fieldDef();
|
|
2984
|
-
if (definition) {
|
|
2985
|
-
head.addReference({
|
|
2986
|
-
type: found instanceof StructSpaceField
|
|
2987
|
-
? "joinReference"
|
|
2988
|
-
: "fieldReference",
|
|
2989
|
-
definition,
|
|
2990
|
-
location: head.location,
|
|
2991
|
-
text: head.refString,
|
|
2992
|
-
});
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
if (rest.length) {
|
|
2996
|
-
if (found instanceof StructSpaceField) {
|
|
2997
|
-
return found.fieldSpace.lookup(rest);
|
|
2998
|
-
}
|
|
2999
|
-
return {
|
|
3000
|
-
error: `'${head}' cannot contain a '${rest[0]}'`,
|
|
3001
|
-
found: undefined,
|
|
3002
|
-
};
|
|
3003
|
-
}
|
|
3004
|
-
return { found, error: undefined };
|
|
3005
|
-
}
|
|
3006
|
-
}
|
|
3007
|
-
exports.StaticSpace = StaticSpace;
|
|
3008
|
-
/**
|
|
3009
|
-
* A FieldSpace which may undergo modification
|
|
3010
|
-
*/
|
|
3011
|
-
class DynamicSpace extends StaticSpace {
|
|
3012
|
-
constructor(extending) {
|
|
3013
|
-
const source = new SpaceSeed(extending);
|
|
3014
|
-
super((0, lodash_1.cloneDeep)(source.structDef));
|
|
3015
|
-
this.completions = [];
|
|
3016
|
-
this.complete = false;
|
|
3017
|
-
this.final = undefined;
|
|
3018
|
-
this.source = source;
|
|
3019
|
-
}
|
|
3020
|
-
/**
|
|
3021
|
-
* Factory for DynamicSpace when there are accept/except edits
|
|
3022
|
-
* @param from A structdef which seeds this space
|
|
3023
|
-
* @param choose A accept/except edit of the "from" fields
|
|
3024
|
-
*/
|
|
3025
|
-
static filteredFrom(from, choose) {
|
|
3026
|
-
const edited = new DynamicSpace(from);
|
|
3027
|
-
if (choose) {
|
|
3028
|
-
const names = choose.refs.list;
|
|
3029
|
-
const oldMap = edited.entries();
|
|
3030
|
-
edited.dropEntries();
|
|
3031
|
-
for (const [symbol, value] of oldMap) {
|
|
3032
|
-
const included = !!names.find((f) => f.refString === symbol);
|
|
3033
|
-
const accepting = choose.edit === "accept";
|
|
3034
|
-
if (included === accepting) {
|
|
3035
|
-
edited.setEntry(symbol, value);
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
return edited;
|
|
3040
|
-
}
|
|
3041
|
-
whenComplete(finalizeStep) {
|
|
3042
|
-
if (this.complete) {
|
|
3043
|
-
finalizeStep();
|
|
3044
|
-
}
|
|
3045
|
-
else {
|
|
3046
|
-
this.completions.push(finalizeStep);
|
|
3047
|
-
}
|
|
3048
|
-
}
|
|
3049
|
-
isComplete() {
|
|
3050
|
-
this.complete = true;
|
|
3051
|
-
for (const step of this.completions) {
|
|
3052
|
-
step();
|
|
3053
|
-
}
|
|
3054
|
-
this.completions = [];
|
|
3055
|
-
}
|
|
3056
|
-
setEntry(name, value) {
|
|
3057
|
-
if (this.final) {
|
|
3058
|
-
throw new Error("Space already final");
|
|
3059
|
-
}
|
|
3060
|
-
super.setEntry(name, value);
|
|
3061
|
-
}
|
|
3062
|
-
addParameters(params) {
|
|
3063
|
-
for (const oneP of params) {
|
|
3064
|
-
this.setEntry(oneP.name, new AbstractParameter(oneP));
|
|
3065
|
-
}
|
|
3066
|
-
return this;
|
|
3067
|
-
}
|
|
3068
|
-
newEntry(name, astEl, entry) {
|
|
3069
|
-
if (this.entry(name)) {
|
|
3070
|
-
astEl.log(`Cannot redefine '${name}'`);
|
|
3071
|
-
return;
|
|
3072
|
-
}
|
|
3073
|
-
this.setEntry(name, entry);
|
|
3074
|
-
}
|
|
3075
|
-
addField(...defs) {
|
|
3076
|
-
for (const def of defs) {
|
|
3077
|
-
// TODO express the "three fields kinds" in a typesafe way
|
|
3078
|
-
// one of three kinds of fields are legal in an explore: expressions ...
|
|
3079
|
-
const elseLog = def.log;
|
|
3080
|
-
const elseType = def.elementType;
|
|
3081
|
-
if (def instanceof FieldDeclaration) {
|
|
3082
|
-
const exprField = new ExpressionFieldFromAst(this, def);
|
|
3083
|
-
this.newEntry(exprField.name, def, exprField);
|
|
3084
|
-
// querry (turtle) fields
|
|
3085
|
-
}
|
|
3086
|
-
else if (def instanceof TurtleDecl) {
|
|
3087
|
-
const name = def.name;
|
|
3088
|
-
this.newEntry(name, def, new QueryFieldAST(this, def, name));
|
|
3089
|
-
}
|
|
3090
|
-
else if (def instanceof RenameField) {
|
|
3091
|
-
if (def.oldName.refString === def.newName) {
|
|
3092
|
-
def.log("Can't rename field to itself");
|
|
3093
|
-
continue;
|
|
3094
|
-
}
|
|
3095
|
-
const oldValue = def.oldName.getField(this);
|
|
3096
|
-
if (oldValue.found) {
|
|
3097
|
-
if (oldValue.found instanceof SpaceField) {
|
|
3098
|
-
this.setEntry(def.newName, new RenameSpaceField(oldValue.found, def.newName, def.location));
|
|
3099
|
-
this.dropEntry(def.oldName.refString);
|
|
3100
|
-
}
|
|
3101
|
-
else {
|
|
3102
|
-
def.log(`'${def.oldName}' cannot be renamed`);
|
|
3103
|
-
}
|
|
3104
|
-
}
|
|
3105
|
-
else {
|
|
3106
|
-
def.log(`Can't rename '${def.oldName}', no such field`);
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
else if (def instanceof Join) {
|
|
3110
|
-
this.newEntry(def.name.refString, def, new JoinSpaceField(this, def));
|
|
3111
|
-
}
|
|
3112
|
-
else {
|
|
3113
|
-
elseLog(`Internal error: Expected expression, query, or rename, got '${elseType}'`);
|
|
3114
|
-
}
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
addFieldDef(fd) {
|
|
3118
|
-
this.setEntry((0, field_utils_1.nameOf)(fd), this.fromFieldDef(fd));
|
|
3119
|
-
}
|
|
3120
|
-
structDef() {
|
|
3121
|
-
const parameters = this.fromStruct.parameters || {};
|
|
3122
|
-
if (this.final === undefined) {
|
|
3123
|
-
this.final = {
|
|
3124
|
-
...this.fromStruct,
|
|
3125
|
-
fields: [],
|
|
3126
|
-
};
|
|
3127
|
-
// Need to process the entities in specific order
|
|
3128
|
-
const fields = [];
|
|
3129
|
-
const joins = [];
|
|
3130
|
-
const turtles = [];
|
|
3131
|
-
const fixupJoins = [];
|
|
3132
|
-
for (const [name, spaceEntry] of this.entries()) {
|
|
3133
|
-
if (spaceEntry instanceof StructSpaceField) {
|
|
3134
|
-
joins.push([name, spaceEntry]);
|
|
3135
|
-
}
|
|
3136
|
-
else if (spaceEntry instanceof QueryField) {
|
|
3137
|
-
turtles.push([name, spaceEntry]);
|
|
3138
|
-
}
|
|
3139
|
-
else if (spaceEntry instanceof SpaceField) {
|
|
3140
|
-
fields.push([name, spaceEntry]);
|
|
3141
|
-
}
|
|
3142
|
-
else if (spaceEntry instanceof SpaceParam) {
|
|
3143
|
-
parameters[name] = spaceEntry.parameter();
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3146
|
-
const reorderFields = [...fields, ...joins, ...turtles];
|
|
3147
|
-
for (const [fieldName, field] of reorderFields) {
|
|
3148
|
-
if (field instanceof JoinSpaceField) {
|
|
3149
|
-
const joinStruct = field.join.structDef();
|
|
3150
|
-
if (!ErrorFactory.isErrorStructDef(joinStruct)) {
|
|
3151
|
-
this.final.fields.push(joinStruct);
|
|
3152
|
-
fixupJoins.push([field.join, joinStruct]);
|
|
3153
|
-
}
|
|
3154
|
-
}
|
|
3155
|
-
else {
|
|
3156
|
-
const fieldDef = field.fieldDef();
|
|
3157
|
-
if (fieldDef) {
|
|
3158
|
-
this.final.fields.push(fieldDef);
|
|
3159
|
-
}
|
|
3160
|
-
else {
|
|
3161
|
-
throw new Error(`'${fieldName}' doesn't have a FieldDef`);
|
|
3162
|
-
}
|
|
3163
|
-
}
|
|
3164
|
-
}
|
|
3165
|
-
if (Object.entries(parameters).length > 0) {
|
|
3166
|
-
this.final.parameters = parameters;
|
|
3167
|
-
}
|
|
3168
|
-
// If we have join expressions, we need to now go back and fill them in
|
|
3169
|
-
for (const [join, missingOn] of fixupJoins) {
|
|
3170
|
-
join.fixupJoinOn(this, missingOn);
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
this.isComplete();
|
|
3174
|
-
return this.final;
|
|
3175
|
-
}
|
|
3176
|
-
}
|
|
3177
|
-
exports.DynamicSpace = DynamicSpace;
|
|
3178
|
-
class ResultSpace extends DynamicSpace {
|
|
3179
|
-
constructor(queryInputSpace) {
|
|
3180
|
-
super(queryInputSpace.emptyStructDef());
|
|
3181
|
-
this.queryInputSpace = queryInputSpace;
|
|
3182
|
-
this.exprSpace = new QuerySpace(queryInputSpace, this);
|
|
3183
|
-
}
|
|
3184
|
-
log(s) {
|
|
3185
|
-
if (this.astEl) {
|
|
3186
|
-
this.astEl.log(s);
|
|
3187
|
-
}
|
|
3188
|
-
}
|
|
3189
|
-
addMembers(members) {
|
|
3190
|
-
for (const member of members) {
|
|
3191
|
-
if (member instanceof FieldReference) {
|
|
3192
|
-
this.addReference(member);
|
|
3193
|
-
}
|
|
3194
|
-
else if (member instanceof WildcardFieldReference) {
|
|
3195
|
-
this.addWild(member);
|
|
3196
|
-
}
|
|
3197
|
-
else {
|
|
3198
|
-
this.addField(member);
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
addReference(ref) {
|
|
3203
|
-
const refName = ref.outputName;
|
|
3204
|
-
if (this.entry(refName)) {
|
|
3205
|
-
ref.log(`Output already has a field named '${refName}'`);
|
|
3206
|
-
}
|
|
3207
|
-
else {
|
|
3208
|
-
this.setEntry(refName, new ReferenceField(ref));
|
|
3209
|
-
}
|
|
3210
|
-
}
|
|
3211
|
-
addWild(wild) {
|
|
3212
|
-
this.setEntry(wild.refString, new WildSpaceField(wild.refString));
|
|
3213
|
-
}
|
|
3214
|
-
/**
|
|
3215
|
-
* Check for the definition of an ungrouping reference in the result space,
|
|
3216
|
-
* or in the case of an exclude reference, if this query is nested
|
|
3217
|
-
* in another query, in the result space of a query that this query
|
|
3218
|
-
* is nested inside of.
|
|
3219
|
-
*/
|
|
3220
|
-
checkUngroup(fn, isExclude) {
|
|
3221
|
-
if (!this.entry(fn.refString)) {
|
|
3222
|
-
if (isExclude && this.exprSpace.nestParent) {
|
|
3223
|
-
const parent = this.exprSpace.nestParent;
|
|
3224
|
-
parent.whenComplete(() => {
|
|
3225
|
-
parent.result.checkUngroup(fn, isExclude);
|
|
3226
|
-
});
|
|
3227
|
-
}
|
|
3228
|
-
else {
|
|
3229
|
-
const uName = isExclude ? "exclude()" : "all()";
|
|
3230
|
-
fn.log(`${uName} '${fn.refString}' is missing from query output`);
|
|
3231
|
-
}
|
|
3232
|
-
}
|
|
3233
|
-
}
|
|
3234
|
-
addQueryItems(...qiList) {
|
|
3235
|
-
for (const qi of qiList) {
|
|
3236
|
-
if (qi instanceof FieldReference || qi instanceof NestReference) {
|
|
3237
|
-
this.addReference(qi);
|
|
3238
|
-
}
|
|
3239
|
-
else if (qi instanceof FieldDeclaration) {
|
|
3240
|
-
this.addField(qi);
|
|
3241
|
-
}
|
|
3242
|
-
else if (isNestedQuery(qi)) {
|
|
3243
|
-
const qf = new QueryFieldAST(this, qi, qi.name);
|
|
3244
|
-
qf.nestParent = this.exprSpace;
|
|
3245
|
-
this.setEntry(qi.name, qf);
|
|
3246
|
-
}
|
|
3247
|
-
else {
|
|
3248
|
-
// Compiler will error if we don't handle all cases
|
|
3249
|
-
const _itemNotHandled = qi;
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
}
|
|
3253
|
-
canContain(_qd) {
|
|
3254
|
-
return true;
|
|
3255
|
-
}
|
|
3256
|
-
queryFieldDefs() {
|
|
3257
|
-
const fields = [];
|
|
3258
|
-
for (const [name, field] of this.entries()) {
|
|
3259
|
-
if (field instanceof SpaceField) {
|
|
3260
|
-
const fieldQueryDef = field.getQueryFieldDef(this.exprSpace);
|
|
3261
|
-
if (fieldQueryDef) {
|
|
3262
|
-
if (this.canContain(fieldQueryDef)) {
|
|
3263
|
-
fields.push(fieldQueryDef);
|
|
3264
|
-
}
|
|
3265
|
-
else {
|
|
3266
|
-
this.log(`'${name}' not legal in ${this.segmentType}`);
|
|
3267
|
-
}
|
|
3268
|
-
}
|
|
3269
|
-
else {
|
|
3270
|
-
throw new Error(`'${name}' does not have a QueryFieldDef`);
|
|
3271
|
-
}
|
|
3272
|
-
}
|
|
3273
|
-
}
|
|
3274
|
-
this.isComplete();
|
|
3275
|
-
return fields;
|
|
3276
|
-
}
|
|
3277
|
-
getQuerySegment(rf) {
|
|
3278
|
-
const p = this.getPipeSegment(rf);
|
|
3279
|
-
if (model.isQuerySegment(p)) {
|
|
3280
|
-
return p;
|
|
3281
|
-
}
|
|
3282
|
-
throw new Error("TODO NOT POSSIBLE");
|
|
3283
|
-
}
|
|
3284
|
-
getPipeSegment(refineFrom) {
|
|
3285
|
-
if (this.segmentType == "index") {
|
|
3286
|
-
// TODO ... should make this go away
|
|
3287
|
-
throw new Error("INDEX FIELD PIPE SEGMENT MIS HANDLED");
|
|
3288
|
-
}
|
|
3289
|
-
if (refineFrom === null || refineFrom === void 0 ? void 0 : refineFrom.extendSource) {
|
|
3290
|
-
for (const xField of refineFrom.extendSource) {
|
|
3291
|
-
this.exprSpace.addFieldDef(xField);
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
|
-
const segment = {
|
|
3295
|
-
type: this.segmentType,
|
|
3296
|
-
fields: this.queryFieldDefs(),
|
|
3297
|
-
};
|
|
3298
|
-
segment.fields = (0, field_utils_1.mergeFields)(refineFrom === null || refineFrom === void 0 ? void 0 : refineFrom.fields, segment.fields);
|
|
3299
|
-
if (refineFrom === null || refineFrom === void 0 ? void 0 : refineFrom.extendSource) {
|
|
3300
|
-
segment.extendSource = refineFrom.extendSource;
|
|
3301
|
-
}
|
|
3302
|
-
if (this.exprSpace.extendList.length > 0) {
|
|
3303
|
-
const newExtends = [];
|
|
3304
|
-
const extendedStruct = this.exprSpace.structDef();
|
|
3305
|
-
for (const extendName of this.exprSpace.extendList) {
|
|
3306
|
-
const extendEnt = extendedStruct.fields.find((f) => (0, field_utils_1.nameOf)(f) == extendName);
|
|
3307
|
-
if (extendEnt) {
|
|
3308
|
-
newExtends.push(extendEnt);
|
|
3309
|
-
}
|
|
3310
|
-
}
|
|
3311
|
-
segment.extendSource = (0, field_utils_1.mergeFields)(segment.extendSource, newExtends);
|
|
3312
|
-
}
|
|
3313
|
-
this.isComplete();
|
|
3314
|
-
return segment;
|
|
3315
|
-
}
|
|
3316
|
-
}
|
|
3317
|
-
exports.ResultSpace = ResultSpace;
|
|
3318
|
-
/**
|
|
3319
|
-
* Reduce and project queries use a "QuerySpace"
|
|
3320
|
-
*/
|
|
3321
|
-
class ReduceFieldSpace extends ResultSpace {
|
|
3322
|
-
constructor() {
|
|
3323
|
-
super(...arguments);
|
|
3324
|
-
this.segmentType = "reduce";
|
|
3325
|
-
}
|
|
3326
|
-
}
|
|
3327
|
-
exports.ReduceFieldSpace = ReduceFieldSpace;
|
|
3328
|
-
class ProjectFieldSpace extends ResultSpace {
|
|
3329
|
-
constructor() {
|
|
3330
|
-
super(...arguments);
|
|
3331
|
-
this.segmentType = "project";
|
|
3332
|
-
}
|
|
3333
|
-
canContain(qd) {
|
|
3334
|
-
if (typeof qd !== "string") {
|
|
3335
|
-
if (model.isFilteredAliasedName(qd)) {
|
|
3336
|
-
return true;
|
|
3337
|
-
}
|
|
3338
|
-
if (qd.type === "turtle") {
|
|
3339
|
-
this.log("Cannot nest queries in project");
|
|
3340
|
-
return false;
|
|
3341
|
-
}
|
|
3342
|
-
if (model.expressionIsAggregate(qd.expressionType)) {
|
|
3343
|
-
this.log("Cannot add aggregate measures to project");
|
|
3344
|
-
return false;
|
|
3345
|
-
}
|
|
3346
|
-
}
|
|
3347
|
-
return true;
|
|
3348
|
-
}
|
|
3349
|
-
}
|
|
3350
|
-
exports.ProjectFieldSpace = ProjectFieldSpace;
|
|
3351
|
-
class SpaceEntry {
|
|
3352
|
-
}
|
|
3353
|
-
exports.SpaceEntry = SpaceEntry;
|
|
3354
|
-
class SpaceField extends SpaceEntry {
|
|
3355
|
-
constructor() {
|
|
3356
|
-
super(...arguments);
|
|
3357
|
-
this.refType = "field";
|
|
3358
|
-
}
|
|
3359
|
-
fieldTypeFromFieldDef(def) {
|
|
3360
|
-
const ref = { type: def.type };
|
|
3361
|
-
if (model.isFieldTypeDef(def) && def.expressionType) {
|
|
3362
|
-
ref.expressionType = def.expressionType;
|
|
3363
|
-
}
|
|
3364
|
-
return ref;
|
|
3365
|
-
}
|
|
3366
|
-
getQueryFieldDef(_fs) {
|
|
3367
|
-
return undefined;
|
|
3368
|
-
}
|
|
3369
|
-
fieldDef() {
|
|
3370
|
-
return undefined;
|
|
3371
|
-
}
|
|
3372
|
-
}
|
|
3373
|
-
exports.SpaceField = SpaceField;
|
|
3374
|
-
class StructSpaceField extends SpaceField {
|
|
3375
|
-
constructor(sourceDef) {
|
|
3376
|
-
super();
|
|
3377
|
-
this.sourceDef = sourceDef;
|
|
3378
|
-
}
|
|
3379
|
-
get fieldSpace() {
|
|
3380
|
-
if (!this.space) {
|
|
3381
|
-
this.space = new StaticSpace(this.sourceDef);
|
|
3382
|
-
}
|
|
3383
|
-
return this.space;
|
|
3384
|
-
}
|
|
3385
|
-
fieldDef() {
|
|
3386
|
-
return this.sourceDef;
|
|
3387
|
-
}
|
|
3388
|
-
type() {
|
|
3389
|
-
return { type: "struct" };
|
|
3390
|
-
}
|
|
3391
|
-
}
|
|
3392
|
-
exports.StructSpaceField = StructSpaceField;
|
|
3393
|
-
class QueryField extends SpaceField {
|
|
3394
|
-
constructor(inSpace) {
|
|
3395
|
-
super();
|
|
3396
|
-
this.inSpace = inSpace;
|
|
3397
|
-
}
|
|
3398
|
-
type() {
|
|
3399
|
-
return { type: "turtle" };
|
|
3400
|
-
}
|
|
3401
|
-
}
|
|
3402
|
-
exports.QueryField = QueryField;
|
|
3403
|
-
class QueryFieldStruct extends QueryField {
|
|
3404
|
-
constructor(fs, turtleDef) {
|
|
3405
|
-
super(fs);
|
|
3406
|
-
this.turtleDef = turtleDef;
|
|
3407
|
-
}
|
|
3408
|
-
rename(name) {
|
|
3409
|
-
this.turtleDef = {
|
|
3410
|
-
...this.turtleDef,
|
|
3411
|
-
as: name,
|
|
3412
|
-
};
|
|
3413
|
-
}
|
|
3414
|
-
fieldDef() {
|
|
3415
|
-
return this.turtleDef;
|
|
3416
|
-
}
|
|
3417
|
-
getQueryFieldDef(_fs) {
|
|
3418
|
-
return this.fieldDef();
|
|
3419
|
-
}
|
|
3420
|
-
}
|
|
3421
|
-
exports.QueryFieldStruct = QueryFieldStruct;
|
|
3422
|
-
class ColumnSpaceField extends SpaceField {
|
|
3423
|
-
constructor(def) {
|
|
3424
|
-
super();
|
|
3425
|
-
this.def = def;
|
|
3426
|
-
}
|
|
3427
|
-
fieldDef() {
|
|
3428
|
-
return this.def;
|
|
3429
|
-
}
|
|
3430
|
-
type() {
|
|
3431
|
-
return this.fieldTypeFromFieldDef(this.def);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
exports.ColumnSpaceField = ColumnSpaceField;
|
|
3435
|
-
class SpaceParam extends SpaceEntry {
|
|
3436
|
-
constructor() {
|
|
3437
|
-
super(...arguments);
|
|
3438
|
-
this.refType = "parameter";
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
|
-
exports.SpaceParam = SpaceParam;
|
|
3442
|
-
class DefinedParameter extends SpaceParam {
|
|
3443
|
-
constructor(paramDef) {
|
|
3444
|
-
super();
|
|
3445
|
-
this.paramDef = paramDef;
|
|
3446
|
-
}
|
|
3447
|
-
parameter() {
|
|
3448
|
-
return this.paramDef;
|
|
3449
|
-
}
|
|
3450
|
-
type() {
|
|
3451
|
-
return { type: this.paramDef.type };
|
|
3452
|
-
}
|
|
3453
|
-
}
|
|
3454
|
-
exports.DefinedParameter = DefinedParameter;
|
|
3455
|
-
/**
|
|
3456
|
-
* Based on how things are constructed, the starting field space
|
|
3457
|
-
* can either be another field space or an existing structdef.
|
|
3458
|
-
* Using a SpaceSeed allows a class to accept either one
|
|
3459
|
-
* and use either version at some future time.
|
|
3460
|
-
*/
|
|
3461
|
-
class SpaceSeed {
|
|
3462
|
-
constructor(sourceSpec) {
|
|
3463
|
-
this.sourceSpec = sourceSpec;
|
|
3464
|
-
this.spaceSpec = sourceSpec;
|
|
3465
|
-
}
|
|
3466
|
-
get structDef() {
|
|
3467
|
-
if (isFieldSpace(this.spaceSpec)) {
|
|
3468
|
-
if (!this.asStruct) {
|
|
3469
|
-
this.asStruct = this.spaceSpec.structDef();
|
|
3470
|
-
}
|
|
3471
|
-
return this.asStruct;
|
|
3472
|
-
}
|
|
3473
|
-
return this.spaceSpec;
|
|
3474
|
-
}
|
|
3475
|
-
get fieldSpace() {
|
|
3476
|
-
if (isFieldSpace(this.spaceSpec)) {
|
|
3477
|
-
return this.spaceSpec;
|
|
3478
|
-
}
|
|
3479
|
-
if (!this.asFS) {
|
|
3480
|
-
this.asFS = new StaticSpace(this.spaceSpec);
|
|
3481
|
-
}
|
|
3482
|
-
return this.asFS;
|
|
3483
|
-
}
|
|
3484
|
-
}
|
|
3485
|
-
exports.SpaceSeed = SpaceSeed;
|
|
3486
|
-
function isFieldSpace(x) {
|
|
3487
|
-
return x.type == "fieldSpace";
|
|
3488
|
-
}
|
|
3489
|
-
class AbstractParameter extends SpaceParam {
|
|
3490
|
-
constructor(astParam) {
|
|
3491
|
-
super();
|
|
3492
|
-
this.astParam = astParam;
|
|
3493
|
-
}
|
|
3494
|
-
parameter() {
|
|
3495
|
-
return this.astParam.parameter();
|
|
3496
|
-
}
|
|
3497
|
-
type() {
|
|
3498
|
-
const type = this.astParam.type || "unknown";
|
|
3499
|
-
return { type };
|
|
3500
|
-
}
|
|
3501
|
-
}
|
|
3502
|
-
exports.AbstractParameter = AbstractParameter;
|
|
3503
|
-
class ExpressionFieldFromAst extends SpaceField {
|
|
3504
|
-
constructor(space, exprDef) {
|
|
3505
|
-
super();
|
|
3506
|
-
this.space = space;
|
|
3507
|
-
this.exprDef = exprDef;
|
|
3508
|
-
this.fieldName = exprDef.defineName;
|
|
3509
|
-
}
|
|
3510
|
-
get name() {
|
|
3511
|
-
return this.fieldName;
|
|
3512
|
-
}
|
|
3513
|
-
fieldDef() {
|
|
3514
|
-
const def = this.exprDef.fieldDef(this.space, this.name);
|
|
3515
|
-
this.defType = this.fieldTypeFromFieldDef(def);
|
|
3516
|
-
return def;
|
|
3517
|
-
}
|
|
3518
|
-
getQueryFieldDef(fs) {
|
|
3519
|
-
const def = this.exprDef.queryFieldDef(fs, this.name);
|
|
3520
|
-
this.defType = this.fieldTypeFromFieldDef(def);
|
|
3521
|
-
return def;
|
|
3522
|
-
}
|
|
3523
|
-
type() {
|
|
3524
|
-
if (this.defType) {
|
|
3525
|
-
return this.defType;
|
|
3526
|
-
}
|
|
3527
|
-
return this.fieldTypeFromFieldDef(this.fieldDef());
|
|
3528
|
-
}
|
|
3529
|
-
}
|
|
3530
|
-
exports.ExpressionFieldFromAst = ExpressionFieldFromAst;
|
|
3531
|
-
class QueryFieldAST extends QueryField {
|
|
3532
|
-
constructor(fs, turtle, name) {
|
|
3533
|
-
super(fs);
|
|
3534
|
-
this.turtle = turtle;
|
|
3535
|
-
this.name = name;
|
|
3536
|
-
}
|
|
3537
|
-
getQueryFieldDef(fs) {
|
|
3538
|
-
const def = this.turtle.getFieldDef(fs, this.nestParent);
|
|
3539
|
-
if (this.renameAs) {
|
|
3540
|
-
def.as = this.renameAs;
|
|
3541
|
-
}
|
|
3542
|
-
return def;
|
|
3543
|
-
}
|
|
3544
|
-
fieldDef() {
|
|
3545
|
-
const def = this.turtle.getFieldDef(this.inSpace, this.nestParent);
|
|
3546
|
-
if (this.renameAs) {
|
|
3547
|
-
def.as = this.renameAs;
|
|
3548
|
-
}
|
|
3549
|
-
return def;
|
|
3550
|
-
}
|
|
3551
|
-
}
|
|
3552
|
-
exports.QueryFieldAST = QueryFieldAST;
|
|
3553
|
-
class RenameSpaceField extends SpaceField {
|
|
3554
|
-
constructor(otherField, newName, location) {
|
|
3555
|
-
super();
|
|
3556
|
-
this.otherField = otherField;
|
|
3557
|
-
this.newName = newName;
|
|
3558
|
-
this.location = location;
|
|
3559
|
-
}
|
|
3560
|
-
fieldDef() {
|
|
3561
|
-
const renamedFieldRaw = this.otherField.fieldDef();
|
|
3562
|
-
if (renamedFieldRaw === undefined) {
|
|
3563
|
-
return undefined;
|
|
3564
|
-
}
|
|
3565
|
-
return {
|
|
3566
|
-
...renamedFieldRaw,
|
|
3567
|
-
as: this.newName,
|
|
3568
|
-
location: this.location,
|
|
3569
|
-
};
|
|
3570
|
-
}
|
|
3571
|
-
type() {
|
|
3572
|
-
return this.otherField.type();
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3575
|
-
exports.RenameSpaceField = RenameSpaceField;
|
|
3576
|
-
class JoinSpaceField extends StructSpaceField {
|
|
3577
|
-
constructor(intoFS, join) {
|
|
3578
|
-
super(join.structDef());
|
|
3579
|
-
this.intoFS = intoFS;
|
|
3580
|
-
this.join = join;
|
|
3581
|
-
}
|
|
3582
|
-
}
|
|
3583
|
-
exports.JoinSpaceField = JoinSpaceField;
|
|
3584
|
-
/**
|
|
3585
|
-
* Unlike a source, which is a refinement of a namespace, a query
|
|
3586
|
-
* is creating a new unrelated namespace. The query starts with a
|
|
3587
|
-
* source, which it might modify. This set of fields used to resolve
|
|
3588
|
-
* expressions in the query is called the "input space". There is a
|
|
3589
|
-
* specialized QuerySpace for each type of query operation.
|
|
3590
|
-
*
|
|
3591
|
-
* The query output is managed by an instance of ResultSpace.
|
|
3592
|
-
*/
|
|
3593
|
-
class QuerySpace extends DynamicSpace {
|
|
3594
|
-
constructor(input, result) {
|
|
3595
|
-
const inputSpace = new SpaceSeed(input);
|
|
3596
|
-
super(inputSpace.structDef);
|
|
3597
|
-
this.result = result;
|
|
3598
|
-
this.extendList = [];
|
|
3599
|
-
}
|
|
3600
|
-
extendSource(extendField) {
|
|
3601
|
-
this.addField(extendField);
|
|
3602
|
-
if (extendField instanceof Join) {
|
|
3603
|
-
this.extendList.push(extendField.name.refString);
|
|
3604
|
-
}
|
|
3605
|
-
else {
|
|
3606
|
-
this.extendList.push(extendField.defineName);
|
|
3607
|
-
}
|
|
3608
|
-
}
|
|
3609
|
-
}
|
|
3610
|
-
exports.QuerySpace = QuerySpace;
|
|
3611
|
-
class ReferenceField extends SpaceField {
|
|
3612
|
-
constructor(fieldRef) {
|
|
3613
|
-
super();
|
|
3614
|
-
this.fieldRef = fieldRef;
|
|
3615
|
-
}
|
|
3616
|
-
getQueryFieldDef(fs) {
|
|
3617
|
-
// Lookup string and generate error if it isn't defined.
|
|
3618
|
-
const check = this.fieldRef.getField(fs);
|
|
3619
|
-
if (check.error) {
|
|
3620
|
-
this.fieldRef.log(check.error);
|
|
3621
|
-
}
|
|
3622
|
-
return this.fieldRef.refString;
|
|
3623
|
-
}
|
|
3624
|
-
type() {
|
|
3625
|
-
return { type: "unknown" };
|
|
3626
|
-
}
|
|
3627
|
-
}
|
|
3628
|
-
exports.ReferenceField = ReferenceField;
|
|
3629
|
-
class WildSpaceField extends SpaceField {
|
|
3630
|
-
constructor(wildText) {
|
|
3631
|
-
super();
|
|
3632
|
-
this.wildText = wildText;
|
|
3633
|
-
}
|
|
3634
|
-
type() {
|
|
3635
|
-
throw new Error("should never ask a wild field for its type");
|
|
3636
|
-
}
|
|
3637
|
-
getQueryFieldDef(_fs) {
|
|
3638
|
-
return this.wildText;
|
|
3639
|
-
}
|
|
3640
|
-
}
|
|
3641
|
-
exports.WildSpaceField = WildSpaceField;
|
|
3642
|
-
class IndexFieldSpace extends ResultSpace {
|
|
3643
|
-
constructor() {
|
|
3644
|
-
super(...arguments);
|
|
3645
|
-
this.segmentType = "index";
|
|
3646
|
-
this.fieldList = new Set();
|
|
3647
|
-
}
|
|
3648
|
-
addReference(ref) {
|
|
3649
|
-
if (ref.getField(this.exprSpace).found) {
|
|
3650
|
-
this.fieldList.add(ref.refString);
|
|
3651
|
-
}
|
|
3652
|
-
}
|
|
3653
|
-
addWild(wild) {
|
|
3654
|
-
this.fieldList.add(wild.refString);
|
|
3655
|
-
}
|
|
3656
|
-
getPipeSegment(refineIndex) {
|
|
3657
|
-
if (refineIndex && refineIndex.fields) {
|
|
3658
|
-
for (const exists of refineIndex.fields) {
|
|
3659
|
-
if (typeof exists == "string") {
|
|
3660
|
-
this.fieldList.add(exists);
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
this.isComplete();
|
|
3665
|
-
return {
|
|
3666
|
-
type: "index",
|
|
3667
|
-
fields: Array.from(this.fieldList.values()),
|
|
3668
|
-
};
|
|
3669
|
-
}
|
|
3670
|
-
}
|
|
3671
|
-
exports.IndexFieldSpace = IndexFieldSpace;
|
|
3672
|
-
//# sourceMappingURL=ast-main.js.map
|