@malloydata/malloy 0.0.304 → 0.0.306

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.
Files changed (74) hide show
  1. package/dist/dialect/dialect.d.ts +1 -1
  2. package/dist/dialect/duckdb/duckdb.d.ts +1 -1
  3. package/dist/dialect/duckdb/duckdb.js +2 -6
  4. package/dist/dialect/mysql/mysql.d.ts +1 -1
  5. package/dist/dialect/mysql/mysql.js +2 -6
  6. package/dist/dialect/postgres/postgres.d.ts +1 -1
  7. package/dist/dialect/postgres/postgres.js +2 -6
  8. package/dist/dialect/snowflake/snowflake.d.ts +1 -1
  9. package/dist/dialect/snowflake/snowflake.js +2 -5
  10. package/dist/dialect/standardsql/standardsql.d.ts +1 -1
  11. package/dist/dialect/standardsql/standardsql.js +2 -6
  12. package/dist/dialect/trino/trino.d.ts +1 -1
  13. package/dist/dialect/trino/trino.js +2 -6
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +2 -3
  16. package/dist/lang/ast/expressions/expr-aggregate-function.js +12 -2
  17. package/dist/lang/ast/expressions/expr-count.js +3 -1
  18. package/dist/lang/ast/expressions/expr-func.js +34 -10
  19. package/dist/lang/ast/expressions/expr-props.js +1 -1
  20. package/dist/lang/ast/expressions/expr-ungroup.js +7 -3
  21. package/dist/lang/ast/expressions/function-ordering.d.ts +19 -5
  22. package/dist/lang/ast/expressions/function-ordering.js +61 -9
  23. package/dist/lang/ast/field-space/include-utils.js +1 -1
  24. package/dist/lang/ast/field-space/index-field-space.js +3 -1
  25. package/dist/lang/ast/field-space/query-spaces.js +20 -11
  26. package/dist/lang/ast/query-builders/index-builder.js +1 -1
  27. package/dist/lang/ast/query-builders/reduce-builder.js +1 -1
  28. package/dist/lang/ast/query-elements/query-arrow.js +14 -4
  29. package/dist/lang/ast/query-elements/query-base.d.ts +1 -0
  30. package/dist/lang/ast/query-elements/query-base.js +14 -4
  31. package/dist/lang/ast/query-elements/query-refine.js +2 -0
  32. package/dist/lang/ast/query-properties/drill.js +1 -1
  33. package/dist/lang/ast/source-properties/join.js +6 -2
  34. package/dist/lang/ast/statements/define-source.js +1 -1
  35. package/dist/lang/ast/types/expr-value.js +1 -1
  36. package/dist/lang/ast/view-elements/reference-view.js +4 -1
  37. package/dist/lang/ast/view-elements/refine-utils.js +1 -1
  38. package/dist/{model/composite_source_utils.d.ts → lang/composite-source-utils.d.ts} +4 -17
  39. package/dist/{model/composite_source_utils.js → lang/composite-source-utils.js} +274 -44
  40. package/dist/lang/test/parse-expects.d.ts +1 -1
  41. package/dist/lang/test/parse-expects.js +6 -2
  42. package/dist/lang/test/test-translator.js +1 -1
  43. package/dist/malloy.js +1 -1
  44. package/dist/model/expression_compiler.d.ts +26 -0
  45. package/dist/model/expression_compiler.js +774 -0
  46. package/dist/model/field_instance.d.ts +108 -0
  47. package/dist/model/field_instance.js +520 -0
  48. package/dist/model/index.d.ts +5 -1
  49. package/dist/model/index.js +25 -4
  50. package/dist/model/join_instance.d.ts +18 -0
  51. package/dist/model/join_instance.js +71 -0
  52. package/dist/model/malloy_types.d.ts +48 -2
  53. package/dist/model/malloy_types.js +39 -1
  54. package/dist/model/query_model.d.ts +2 -0
  55. package/dist/model/query_model.js +7 -0
  56. package/dist/model/query_model_contract.d.ts +32 -0
  57. package/dist/model/query_model_contract.js +7 -0
  58. package/dist/model/query_model_impl.d.ts +30 -0
  59. package/dist/model/query_model_impl.js +266 -0
  60. package/dist/model/query_node.d.ts +132 -0
  61. package/dist/model/query_node.js +638 -0
  62. package/dist/model/query_query.d.ts +86 -0
  63. package/dist/model/query_query.js +1724 -0
  64. package/dist/model/sql_block.js +2 -2
  65. package/dist/model/stage_writer.d.ts +25 -0
  66. package/dist/model/stage_writer.js +120 -0
  67. package/dist/model/utils.d.ts +18 -1
  68. package/dist/model/utils.js +66 -1
  69. package/dist/to_stable.js +3 -4
  70. package/dist/version.d.ts +1 -1
  71. package/dist/version.js +1 -1
  72. package/package.json +4 -4
  73. package/dist/model/malloy_query.d.ts +0 -391
  74. package/dist/model/malloy_query.js +0 -3926
@@ -0,0 +1,638 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Contributors to the Malloy project
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.QueryStruct = exports.QueryFieldUnsupported = exports.QueryFieldTimestamp = exports.QueryFieldStruct = exports.QueryFieldString = exports.QueryFieldNumber = exports.QueryFieldJSON = exports.QueryFieldDistinctKey = exports.QueryFieldDate = exports.QueryFieldBoolean = exports.QueryAtomicField = exports.QueryField = void 0;
8
+ exports.isAggregateField = isAggregateField;
9
+ exports.isCalculatedField = isCalculatedField;
10
+ exports.isScalarField = isScalarField;
11
+ exports.isBasicAggregate = isBasicAggregate;
12
+ exports.isBasicCalculation = isBasicCalculation;
13
+ exports.isBasicScalar = isBasicScalar;
14
+ const uuid_1 = require("uuid");
15
+ const malloy_types_1 = require("./malloy_types");
16
+ const annotation_1 = require("../annotation");
17
+ const dialect_1 = require("../dialect");
18
+ const utils_1 = require("./utils");
19
+ class QueryNode {
20
+ constructor(referenceId) {
21
+ this.referenceId = referenceId !== null && referenceId !== void 0 ? referenceId : (0, uuid_1.v4)();
22
+ }
23
+ getChildByName(_name) {
24
+ return undefined;
25
+ }
26
+ }
27
+ class QueryField extends QueryNode {
28
+ constructor(fieldDef, parent, referenceId) {
29
+ super(referenceId);
30
+ this.fieldDef = fieldDef;
31
+ this.parent = parent;
32
+ this.fieldDef = fieldDef;
33
+ }
34
+ getIdentifier() {
35
+ return (0, malloy_types_1.getIdentifier)(this.fieldDef);
36
+ }
37
+ getJoinableParent() {
38
+ const parent = this.parent;
39
+ if (parent.structDef.type === 'record') {
40
+ return parent.getJoinableParent();
41
+ }
42
+ return parent;
43
+ }
44
+ isAtomic() {
45
+ return (0, malloy_types_1.isAtomic)(this.fieldDef);
46
+ }
47
+ getFullOutputName() {
48
+ return this.parent.getFullOutputName() + this.getIdentifier();
49
+ }
50
+ isNestedInParent(parentDef) {
51
+ switch (parentDef.type) {
52
+ case 'record':
53
+ case 'array':
54
+ return true;
55
+ return true;
56
+ default:
57
+ return false;
58
+ }
59
+ }
60
+ isArrayElement(parentDef) {
61
+ return (parentDef.type === 'array' &&
62
+ parentDef.elementTypeDef.type !== 'record_element');
63
+ }
64
+ includeInWildcard() {
65
+ return false;
66
+ }
67
+ }
68
+ exports.QueryField = QueryField;
69
+ class QueryAtomicField extends QueryField {
70
+ constructor(fieldDef, parent, refId) {
71
+ super(fieldDef, parent, refId);
72
+ this.fieldDef = fieldDef; // wish I didn't have to do this
73
+ }
74
+ includeInWildcard() {
75
+ return this.fieldDef.name !== '__distinct_key';
76
+ }
77
+ getFilterList() {
78
+ return [];
79
+ }
80
+ }
81
+ exports.QueryAtomicField = QueryAtomicField;
82
+ class QueryFieldBoolean extends QueryAtomicField {
83
+ }
84
+ exports.QueryFieldBoolean = QueryFieldBoolean;
85
+ class QueryFieldDate extends QueryAtomicField {
86
+ }
87
+ exports.QueryFieldDate = QueryFieldDate;
88
+ class QueryFieldDistinctKey extends QueryAtomicField {
89
+ }
90
+ exports.QueryFieldDistinctKey = QueryFieldDistinctKey;
91
+ class QueryFieldJSON extends QueryAtomicField {
92
+ }
93
+ exports.QueryFieldJSON = QueryFieldJSON;
94
+ class QueryFieldNumber extends QueryAtomicField {
95
+ }
96
+ exports.QueryFieldNumber = QueryFieldNumber;
97
+ class QueryFieldString extends QueryAtomicField {
98
+ }
99
+ exports.QueryFieldString = QueryFieldString;
100
+ /*
101
+ * The input to a query will always be a QueryStruct. A QueryStruct is also a namespace
102
+ * for tracking joins, and so a QueryFieldStruct is a QueryField which has a QueryStruct.
103
+ *
104
+ * This is a result of it being impossible to inherit both from QueryStruct and QueryField
105
+ * for array and record types.
106
+ */
107
+ class QueryFieldStruct extends QueryField {
108
+ constructor(jfd, sourceArguments, parent, prepareResultOptions, referenceId) {
109
+ super(jfd, parent, referenceId);
110
+ this.fieldDef = jfd;
111
+ this.queryStruct = new QueryStruct(jfd, sourceArguments, { struct: parent }, prepareResultOptions);
112
+ }
113
+ /*
114
+ * Proxy the field-like methods that QueryStruct implements, eventually
115
+ * those probably should be in here ... I thought this would be important
116
+ * but maybe it isn't, it doesn't fix the problem I am working on ...
117
+ */
118
+ getJoinableParent() {
119
+ return this.queryStruct.getJoinableParent();
120
+ }
121
+ getFullOutputName() {
122
+ return this.queryStruct.getFullOutputName();
123
+ }
124
+ includeInWildcard() {
125
+ return this.isAtomic();
126
+ }
127
+ }
128
+ exports.QueryFieldStruct = QueryFieldStruct;
129
+ class QueryFieldTimestamp extends QueryAtomicField {
130
+ }
131
+ exports.QueryFieldTimestamp = QueryFieldTimestamp;
132
+ class QueryFieldUnsupported extends QueryAtomicField {
133
+ }
134
+ exports.QueryFieldUnsupported = QueryFieldUnsupported;
135
+ // ============================================================================
136
+ // QueryField utility functions (consolidated from is_* files)
137
+ // ============================================================================
138
+ function isAggregateField(f) {
139
+ if (f.isAtomic() && (0, malloy_types_1.hasExpression)(f.fieldDef)) {
140
+ return (0, malloy_types_1.expressionIsAggregate)(f.fieldDef.expressionType);
141
+ }
142
+ return false;
143
+ }
144
+ function isCalculatedField(f) {
145
+ if (f.isAtomic() && (0, malloy_types_1.hasExpression)(f.fieldDef)) {
146
+ return (0, malloy_types_1.expressionIsCalculation)(f.fieldDef.expressionType);
147
+ }
148
+ return false;
149
+ }
150
+ function isScalarField(f) {
151
+ if (f.isAtomic()) {
152
+ if ((0, malloy_types_1.hasExpression)(f.fieldDef)) {
153
+ const et = f.fieldDef.expressionType;
154
+ if ((0, malloy_types_1.expressionIsCalculation)(et) || (0, malloy_types_1.expressionIsAggregate)(et)) {
155
+ return false;
156
+ }
157
+ }
158
+ return true;
159
+ }
160
+ return false;
161
+ }
162
+ function isBasicAggregate(f) {
163
+ return f instanceof QueryAtomicField && isAggregateField(f);
164
+ }
165
+ function isBasicCalculation(f) {
166
+ return f instanceof QueryAtomicField && isCalculatedField(f);
167
+ }
168
+ function isBasicScalar(f) {
169
+ return f instanceof QueryAtomicField && isScalarField(f);
170
+ }
171
+ function identifierNormalize(s) {
172
+ return s.replace(/[^a-zA-Z0-9_]/g, '_o_');
173
+ }
174
+ /** Structure object as it is used to build a query */
175
+ class QueryStruct {
176
+ constructor(structDef, sourceArguments, parent, prepareResultOptions) {
177
+ this.structDef = structDef;
178
+ this.sourceArguments = sourceArguments;
179
+ this.prepareResultOptions = prepareResultOptions;
180
+ this.nameMap = new Map();
181
+ this._modelTag = undefined;
182
+ this._arguments = undefined;
183
+ this.setParent(parent);
184
+ if ('model' in parent) {
185
+ this.model = parent.model;
186
+ this.pathAliasMap = new Map();
187
+ if ((0, malloy_types_1.isSourceDef)(structDef)) {
188
+ this.connectionName = structDef.connection;
189
+ }
190
+ else {
191
+ throw new Error('All root StructDefs should be a baseTable');
192
+ }
193
+ }
194
+ else {
195
+ this.model = this.getModel();
196
+ this.pathAliasMap = this.root().pathAliasMap;
197
+ this.connectionName = this.root().connectionName;
198
+ }
199
+ this.dialect = (0, dialect_1.getDialect)(this.findFirstDialect());
200
+ this.addFieldsFromFieldList(structDef.fields);
201
+ }
202
+ static registerTurtleFieldMaker(maker) {
203
+ QueryStruct.turtleFieldMaker = maker;
204
+ }
205
+ modelCompilerFlags() {
206
+ if (this._modelTag === undefined) {
207
+ const annotation = this.structDef.modelAnnotation;
208
+ const { tag } = (0, annotation_1.annotationToTag)(annotation, { prefix: /^##!\s*/ });
209
+ this._modelTag = tag;
210
+ }
211
+ return this._modelTag;
212
+ }
213
+ findFirstDialect() {
214
+ if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
215
+ return this.structDef.dialect;
216
+ }
217
+ if (this.parent) {
218
+ return this.parent.findFirstDialect();
219
+ }
220
+ throw new Error('Cannot create QueryStruct from record with model parent');
221
+ }
222
+ informOfAliasValue(av) {
223
+ this.recordAlias = av;
224
+ }
225
+ maybeEmitParameterizedSourceUsage() {
226
+ var _a;
227
+ if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
228
+ const paramsAndArgs = {
229
+ ...this.structDef.parameters,
230
+ ...this.structDef.arguments,
231
+ };
232
+ if (Object.values(paramsAndArgs).length === 0)
233
+ return;
234
+ (_a = this.eventStream) === null || _a === void 0 ? void 0 : _a.emit('parameterized-source-compiled', {
235
+ parameters: paramsAndArgs,
236
+ });
237
+ }
238
+ }
239
+ resolveParentParameterReferences(param) {
240
+ return {
241
+ ...param,
242
+ value: param.value === null
243
+ ? null
244
+ : (0, utils_1.exprMap)(param.value, frag => {
245
+ if (frag.node === 'parameter') {
246
+ const resolved1 = (this.parent ? this.parent.arguments() : this.arguments())[frag.path[0]];
247
+ const resolved2 = this.parent
248
+ ? this.parent.resolveParentParameterReferences(resolved1)
249
+ : resolved1;
250
+ if (resolved2.value === null) {
251
+ throw new Error('Invalid parameter value');
252
+ }
253
+ else {
254
+ return resolved2.value;
255
+ }
256
+ }
257
+ return frag;
258
+ }),
259
+ };
260
+ }
261
+ arguments() {
262
+ var _a;
263
+ if (this._arguments !== undefined) {
264
+ return this._arguments;
265
+ }
266
+ this._arguments = {};
267
+ if ((0, malloy_types_1.isSourceDef)(this.structDef)) {
268
+ // First, copy over all parameters, to get default values
269
+ const params = (_a = this.structDef.parameters) !== null && _a !== void 0 ? _a : {};
270
+ for (const parameterName in params) {
271
+ this._arguments[parameterName] = params[parameterName];
272
+ }
273
+ // Then, copy over arguments to override default values
274
+ const args = { ...this.structDef.arguments, ...this.sourceArguments };
275
+ for (const parameterName in args) {
276
+ const orig = args[parameterName];
277
+ this._arguments[parameterName] =
278
+ this.resolveParentParameterReferences(orig);
279
+ }
280
+ }
281
+ return this._arguments;
282
+ }
283
+ addFieldsFromFieldList(fields) {
284
+ for (const field of fields) {
285
+ const as = (0, malloy_types_1.getIdentifier)(field);
286
+ if (field.type === 'turtle') {
287
+ if (!QueryStruct.turtleFieldMaker) {
288
+ throw new Error('INTERNAL ERROR: QueryQuery must initialize QueryStruct nested factory method');
289
+ }
290
+ this.addFieldToNameMap(as, QueryStruct.turtleFieldMaker(field, this));
291
+ }
292
+ else if ((0, malloy_types_1.isAtomic)(field) || (0, malloy_types_1.isJoinedSource)(field)) {
293
+ this.addFieldToNameMap(as, this.makeQueryField(field));
294
+ }
295
+ else {
296
+ throw new Error('mtoy did nit add field');
297
+ }
298
+ }
299
+ // if we don't have distinct key yet for this struct, add it.
300
+ if (!this.nameMap.has('__distinct_key')) {
301
+ this.addFieldToNameMap('__distinct_key', new QueryFieldDistinctKey({ type: 'string', name: '__distinct_key' }, this));
302
+ }
303
+ }
304
+ // generate unique string for the alias.
305
+ // return a string that can be used to represent the full
306
+ // join path to a struct.
307
+ getAliasIdentifier() {
308
+ const path = this.getFullOutputName();
309
+ const ret = this.pathAliasMap.get(path);
310
+ // make a unique alias name
311
+ if (ret === undefined) {
312
+ const aliases = Array.from(this.pathAliasMap.values());
313
+ const base = identifierNormalize((0, malloy_types_1.getIdentifier)(this.structDef));
314
+ let name = `${base}_0`;
315
+ let n = 1;
316
+ while (aliases.includes(name) && n < 1000) {
317
+ n++;
318
+ name = `${base}_${n}`;
319
+ }
320
+ if (n < 1000) {
321
+ this.pathAliasMap.set(path, name);
322
+ return name;
323
+ }
324
+ else {
325
+ throw new Error('Internal Error: cannot create unique alias name');
326
+ }
327
+ // get the malloy name for this struct (will include a trailing dot)
328
+ // return this.getFullOutputName().replace(/\.$/, "").replace(/\./g, "_o_");
329
+ }
330
+ else {
331
+ return ret;
332
+ }
333
+ }
334
+ getSQLIdentifier() {
335
+ if (this.unnestWithNumbers() && this.parent !== undefined) {
336
+ const x = this.parent.getSQLIdentifier() +
337
+ '.' +
338
+ (0, malloy_types_1.getIdentifier)(this.structDef) +
339
+ `[${this.getIdentifier()}.__row_id]`;
340
+ return x;
341
+ }
342
+ else {
343
+ return this.getIdentifier();
344
+ }
345
+ }
346
+ sqlSimpleChildReference(name) {
347
+ const parentRef = this.getSQLIdentifier();
348
+ let refType = 'table';
349
+ if (this.structDef.type === 'record') {
350
+ refType = 'record';
351
+ }
352
+ else if (this.structDef.type === 'array') {
353
+ refType =
354
+ this.structDef.elementTypeDef.type === 'record_element'
355
+ ? 'array[record]'
356
+ : 'array[scalar]';
357
+ }
358
+ else if (this.structDef.type === 'nest_source') {
359
+ refType = 'nest source';
360
+ }
361
+ const child = this.getChildByName(name);
362
+ const childType = (child === null || child === void 0 ? void 0 : child.fieldDef.type) || 'unknown';
363
+ return this.dialect.sqlFieldReference(parentRef, refType, name, childType);
364
+ }
365
+ // return the name of the field in SQL
366
+ getIdentifier() {
367
+ // if it is the root table, use provided alias if we have one.
368
+ if ((0, malloy_types_1.isBaseTable)(this.structDef)) {
369
+ return 'base';
370
+ }
371
+ // If this is a synthetic column, return the expression rather than the name
372
+ // because the name will not exist. Only for records because the other types
373
+ // will have joins and thus be in the namespace. We can't compute it here
374
+ // because we don't have access to the Query to call exprToSQL.
375
+ if (this.structDef.type === 'record' && (0, malloy_types_1.hasExpression)(this.structDef)) {
376
+ if (this.recordAlias) {
377
+ return this.recordAlias;
378
+ }
379
+ throw new Error('INTERNAL ERROR, record field alias not pre-computed');
380
+ }
381
+ // if this is an inline object, include the parents alias.
382
+ if (this.structDef.type === 'record' && this.parent) {
383
+ return this.parent.sqlSimpleChildReference((0, malloy_types_1.getIdentifier)(this.structDef));
384
+ }
385
+ // we are somewhere in the join tree. Make sure the alias is unique.
386
+ return this.getAliasIdentifier();
387
+ }
388
+ // return the name of the field in Malloy
389
+ getFullOutputName() {
390
+ if (this.parent) {
391
+ return (this.parent.getFullOutputName() + (0, malloy_types_1.getIdentifier)(this.structDef) + '.');
392
+ }
393
+ else {
394
+ return '';
395
+ }
396
+ }
397
+ unnestWithNumbers() {
398
+ return this.dialect.unnestWithNumbers && this.structDef.type === 'array';
399
+ }
400
+ getJoinableParent() {
401
+ // if it is inline it should always have a parent
402
+ if (this.structDef.type === 'record') {
403
+ if (this.parent) {
404
+ return this.parent.getJoinableParent();
405
+ }
406
+ else {
407
+ throw new Error('Internal Error: inline struct cannot be root');
408
+ }
409
+ }
410
+ return this;
411
+ }
412
+ addFieldToNameMap(as, n) {
413
+ if (this.nameMap.has(as)) {
414
+ throw new Error(`Redefinition of ${as}`);
415
+ }
416
+ this.nameMap.set(as, n);
417
+ }
418
+ /** the the primary key or throw an error. */
419
+ getPrimaryKeyField(fieldDef) {
420
+ let pk;
421
+ if ((pk = this.primaryKey())) {
422
+ return pk;
423
+ }
424
+ else {
425
+ throw new Error(`Missing primary key for ${fieldDef}`);
426
+ }
427
+ }
428
+ /**
429
+ * called after all structure has been loaded. Examine this structure to see
430
+ * if if it is based on a query and if it is, add the output fields (unless
431
+ * they exist) to the structure.
432
+ *
433
+ * finalOutputStruct exists so that query_node doesn't need to
434
+ * to import query_query
435
+ */
436
+ resolveQueryFields(finalOutputStruct) {
437
+ if (this.structDef.type === 'query_source' && finalOutputStruct) {
438
+ const resultStruct = finalOutputStruct(this.structDef.query, this.prepareResultOptions);
439
+ // should never happen.
440
+ if (!resultStruct) {
441
+ throw new Error("Internal Error, query didn't produce a struct");
442
+ }
443
+ const structDef = { ...this.structDef };
444
+ for (const f of resultStruct.fields) {
445
+ const as = (0, malloy_types_1.getIdentifier)(f);
446
+ if (!this.nameMap.has(as)) {
447
+ structDef.fields.push(f);
448
+ this.nameMap.set(as, this.makeQueryField(f));
449
+ }
450
+ }
451
+ this.structDef = structDef;
452
+ if (!this.structDef.primaryKey && resultStruct.primaryKey) {
453
+ this.structDef.primaryKey = resultStruct.primaryKey;
454
+ }
455
+ }
456
+ for (const [, v] of this.nameMap) {
457
+ if (v instanceof QueryFieldStruct) {
458
+ v.queryStruct.resolveQueryFields(finalOutputStruct);
459
+ }
460
+ }
461
+ }
462
+ getModel() {
463
+ if (this.model) {
464
+ return this.model;
465
+ }
466
+ else {
467
+ if (this.parent === undefined) {
468
+ throw new Error('Expected this query struct to have a parent, as no model was present.');
469
+ }
470
+ return this.parent.getModel();
471
+ }
472
+ }
473
+ get eventStream() {
474
+ return this.getModel().eventStream;
475
+ }
476
+ setParent(parent) {
477
+ if ('struct' in parent) {
478
+ this.parent = parent.struct;
479
+ }
480
+ if ('model' in parent) {
481
+ this.model = parent.model;
482
+ }
483
+ else {
484
+ this.model = this.getModel();
485
+ }
486
+ }
487
+ /** makes a new queryable field object from a fieldDef */
488
+ makeQueryField(field, referenceId) {
489
+ switch (field.type) {
490
+ case 'array':
491
+ case 'record':
492
+ case 'query_source':
493
+ case 'table':
494
+ case 'sql_select':
495
+ case 'composite':
496
+ return new QueryFieldStruct(field, undefined, this, this.prepareResultOptions);
497
+ case 'string':
498
+ return new QueryFieldString(field, this, referenceId);
499
+ case 'date':
500
+ return new QueryFieldDate(field, this, referenceId);
501
+ case 'timestamp':
502
+ return new QueryFieldTimestamp(field, this, referenceId);
503
+ case 'number':
504
+ return new QueryFieldNumber(field, this, referenceId);
505
+ case 'boolean':
506
+ return new QueryFieldBoolean(field, this, referenceId);
507
+ case 'json':
508
+ return new QueryFieldJSON(field, this, referenceId);
509
+ case 'sql native':
510
+ return new QueryFieldUnsupported(field, this, referenceId);
511
+ case 'turtle':
512
+ if (!QueryStruct.turtleFieldMaker) {
513
+ throw new Error('INTERNAL ERROR: QueryQuery must initialize QueryStruct nested factory method');
514
+ }
515
+ return QueryStruct.turtleFieldMaker(field, this);
516
+ default:
517
+ throw new Error(`unknown field definition ${(JSON.stringify(field), undefined, 2)}`);
518
+ }
519
+ }
520
+ root() {
521
+ return this.parent ? this.parent.root() : this;
522
+ }
523
+ primaryKey() {
524
+ if ((0, malloy_types_1.isSourceDef)(this.structDef) && this.structDef.primaryKey) {
525
+ return this.getDimensionByName([this.structDef.primaryKey]);
526
+ }
527
+ else {
528
+ return undefined;
529
+ }
530
+ }
531
+ getChildByName(name) {
532
+ return this.nameMap.get(name);
533
+ }
534
+ /** convert a path into a field reference */
535
+ getFieldByName(path) {
536
+ let found = undefined;
537
+ let lookIn = this;
538
+ let notFound = path[0];
539
+ for (const n of path) {
540
+ found = lookIn === null || lookIn === void 0 ? void 0 : lookIn.getChildByName(n);
541
+ if (!found) {
542
+ notFound = n;
543
+ break;
544
+ }
545
+ lookIn =
546
+ found instanceof QueryFieldStruct ? found.queryStruct : undefined;
547
+ }
548
+ if (found === undefined) {
549
+ const pathErr = path.length > 1 ? ` in ${path.join('.')}` : '';
550
+ throw new Error(`${notFound} not found${pathErr}`);
551
+ }
552
+ return found;
553
+ }
554
+ // structs referenced in queries are converted to fields.
555
+ getQueryFieldByName(name) {
556
+ const field = this.getFieldByName(name);
557
+ if (field instanceof QueryFieldStruct) {
558
+ throw new Error(`Cannot reference ${name.join('.')} as a scalar'`);
559
+ }
560
+ return field;
561
+ }
562
+ getQueryFieldReference(f) {
563
+ const { path, annotation, drillExpression } = f;
564
+ const field = this.getFieldByName(path);
565
+ if (annotation || drillExpression) {
566
+ if (field.parent === undefined) {
567
+ throw new Error('Inconcievable, field reference to orphaned query field');
568
+ }
569
+ // Made a field object from the source, but the annotations were computed by the compiler
570
+ // when it generated the reference, and has both the source and reference annotations included.
571
+ if (field instanceof QueryFieldStruct) {
572
+ const newDef = { ...field.fieldDef, annotation, drillExpression };
573
+ return new QueryFieldStruct(newDef, undefined, field.parent, field.parent.prepareResultOptions, field.referenceId);
574
+ }
575
+ else {
576
+ const newDef = { ...field.fieldDef, annotation, drillExpression };
577
+ return field.parent.makeQueryField(newDef, field.referenceId);
578
+ }
579
+ }
580
+ return field;
581
+ }
582
+ getDimensionOrMeasureByName(name) {
583
+ const field = this.getFieldByName(name);
584
+ if (!field.isAtomic()) {
585
+ throw new Error(`${name} is not an atomic field? Inconceivable!`);
586
+ }
587
+ return field;
588
+ }
589
+ /** returns a query object for the given name */
590
+ getDimensionByName(name) {
591
+ const field = this.getFieldByName(name);
592
+ if (isBasicScalar(field)) {
593
+ return field;
594
+ }
595
+ throw new Error(`${name} is not an atomic scalar field? Inconceivable!`);
596
+ }
597
+ /** returns a query object for the given name */
598
+ getStructByName(name) {
599
+ if (name.length === 0) {
600
+ return this;
601
+ }
602
+ const struct = this.getFieldByName(name);
603
+ if (struct instanceof QueryFieldStruct) {
604
+ return struct.queryStruct;
605
+ }
606
+ throw new Error(`Error: Path to structure not found '${name.join('.')}'`);
607
+ }
608
+ getDistinctKey() {
609
+ if (this.structDef.type !== 'record') {
610
+ return this.getDimensionByName(['__distinct_key']);
611
+ }
612
+ else if (this.parent) {
613
+ return this.parent.getDistinctKey();
614
+ }
615
+ else {
616
+ throw new Error('Asking a record for a primary key? Inconceivable!');
617
+ }
618
+ }
619
+ applyStructFiltersToTurtleDef(turtleDef) {
620
+ const pipeline = [...turtleDef.pipeline];
621
+ const annotation = turtleDef.annotation;
622
+ const addedFilters = turtleDef.filterList || [];
623
+ pipeline[0] = {
624
+ ...pipeline[0],
625
+ filterList: addedFilters.concat(pipeline[0].filterList || [], (0, malloy_types_1.isSourceDef)(this.structDef) ? this.structDef.filterList || [] : []),
626
+ };
627
+ const flatTurtleDef = {
628
+ type: 'turtle',
629
+ name: turtleDef.name,
630
+ pipeline,
631
+ annotation,
632
+ location: turtleDef.location,
633
+ };
634
+ return flatTurtleDef;
635
+ }
636
+ }
637
+ exports.QueryStruct = QueryStruct;
638
+ //# sourceMappingURL=query_node.js.map