@malloydata/malloy 0.0.97-dev231026184251 → 0.0.97

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.
@@ -3,6 +3,8 @@ import { FieldName, FieldSpace } from '../types/field-space';
3
3
  import { MalloyElement } from '../types/malloy-element';
4
4
  import { QOPDesc } from '../query-properties/qop-desc';
5
5
  import { QueryInputSpace } from '../field-space/query-input-space';
6
+ import { ViewFieldReference } from '../query-items/field-references';
7
+ import { Refinement } from '../query-properties/refinements';
6
8
  interface AppendResult {
7
9
  opList: PipeSegment[];
8
10
  structDef: StructDef;
@@ -13,21 +15,19 @@ interface AppendResult {
13
15
  * is refers to the first segment of the composed pipeline.
14
16
  */
15
17
  export declare abstract class PipelineDesc extends MalloyElement {
16
- protected withRefinement?: QOPDesc;
18
+ protected refinements?: Refinement[];
17
19
  protected qops: QOPDesc[];
18
20
  nestedInQuerySpace?: QueryInputSpace;
19
21
  alreadyRefined(): boolean;
20
- refineWith(refinement: QOPDesc): void;
22
+ refineWith(refinements: (QOPDesc | ViewFieldReference)[]): void;
21
23
  addSegments(...segDesc: QOPDesc[]): void;
22
24
  protected appendOps(pipelineOutput: FieldSpace, modelPipe: PipeSegment[]): AppendResult;
23
- private refineSegment;
24
25
  protected refinePipeline(fs: FieldSpace, modelPipe: Pipeline): Pipeline;
25
26
  protected expandTurtle(turtleName: string, fromStruct: StructDef): {
26
27
  pipeline: PipeSegment[];
27
28
  location: DocumentLocation | undefined;
28
29
  annotation: Annotation | undefined;
29
30
  };
30
- protected getFinalStruct(walkStruct: StructDef, pipeline: PipeSegment[]): StructDef;
31
31
  }
32
32
  export declare abstract class TurtleHeadedPipe extends PipelineDesc {
33
33
  _turtleName?: FieldName;
@@ -24,10 +24,8 @@
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.TurtleHeadedPipe = exports.PipelineDesc = void 0;
26
26
  const malloy_element_1 = require("../types/malloy-element");
27
- const qop_desc_1 = require("../query-properties/qop-desc");
28
27
  const struct_utils_1 = require("../struct-utils");
29
- const query_property_interface_1 = require("../types/query-property-interface");
30
- const static_space_1 = require("../field-space/static-space");
28
+ const refinements_1 = require("../query-properties/refinements");
31
29
  /**
32
30
  * Generic abstract for all pipelines, the first segment might be a reference
33
31
  * to an existing pipeline (query or turtle), and if there is a refinement it
@@ -39,11 +37,12 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
39
37
  this.qops = [];
40
38
  }
41
39
  alreadyRefined() {
42
- return this.withRefinement !== undefined;
40
+ return this.refinements !== undefined;
43
41
  }
44
- refineWith(refinement) {
45
- this.withRefinement = refinement;
46
- this.has({ withRefinement: refinement });
42
+ refineWith(refinements) {
43
+ const ref = refinements.map(refinement => refinements_1.Refinement.from(refinement));
44
+ this.refinements = ref;
45
+ this.has({ refinements: ref });
47
46
  }
48
47
  addSegments(...segDesc) {
49
48
  this.qops.push(...segDesc);
@@ -63,12 +62,8 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
63
62
  structDef: nextFS.structDef(),
64
63
  };
65
64
  }
66
- refineSegment(fs, refinement, seg) {
67
- refinement.refineFrom(seg);
68
- return refinement.getOp(fs, this.nestedInQuerySpace).segment;
69
- }
70
65
  refinePipeline(fs, modelPipe) {
71
- if (!this.withRefinement) {
66
+ if (!this.refinements) {
72
67
  return modelPipe;
73
68
  }
74
69
  let pipeline = [];
@@ -77,43 +72,10 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
77
72
  pipeline.push(...turtlePipe);
78
73
  }
79
74
  pipeline.push(...modelPipe.pipeline);
80
- const firstSeg = pipeline[0];
81
- if (pipeline.length === 1) {
82
- // I could let everything fall through to the head/tail case, it should be the
83
- // same, but this does less computation and is the most common case.
84
- pipeline = [this.refineSegment(fs, this.withRefinement, firstSeg)];
85
- this.withRefinement = undefined;
86
- }
87
- else {
88
- const headRefinements = new qop_desc_1.QOPDesc([]);
89
- const tailRefinements = new qop_desc_1.QOPDesc([]);
90
- for (const qop of this.withRefinement.list) {
91
- switch (qop.queryRefinementStage) {
92
- case query_property_interface_1.LegalRefinementStage.Head:
93
- headRefinements.push(qop);
94
- break;
95
- case query_property_interface_1.LegalRefinementStage.Single:
96
- qop.log('Illegal in refinement of a query with more than one stage');
97
- break;
98
- case query_property_interface_1.LegalRefinementStage.Tail:
99
- tailRefinements.push(qop);
100
- break;
101
- default:
102
- qop.log('Illegal query refinement');
103
- }
104
- }
105
- if (headRefinements.notEmpty()) {
106
- this.has({ headRefinements });
107
- pipeline[0] = this.refineSegment(fs, headRefinements, firstSeg);
108
- }
109
- if (tailRefinements.notEmpty()) {
110
- const last = pipeline.length - 1;
111
- this.has({ tailRefinements });
112
- const finalIn = this.getFinalStruct(fs.structDef(), pipeline.slice(-1));
113
- pipeline[last] = this.refineSegment(new static_space_1.StaticSpace(finalIn), tailRefinements, pipeline[last]);
114
- }
75
+ for (const refinement of this.refinements) {
76
+ pipeline = refinement.refine(fs, pipeline);
115
77
  }
116
- this.withRefinement = undefined;
78
+ this.refinements = undefined;
117
79
  return { pipeline };
118
80
  }
119
81
  expandTurtle(turtleName, fromStruct) {
@@ -133,12 +95,6 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
133
95
  }
134
96
  return { pipeline: [], location: undefined, annotation };
135
97
  }
136
- getFinalStruct(walkStruct, pipeline) {
137
- for (const modelQop of pipeline) {
138
- walkStruct = (0, struct_utils_1.opOutputStruct)(this, walkStruct, modelQop);
139
- }
140
- return walkStruct;
141
- }
142
98
  }
143
99
  exports.PipelineDesc = PipelineDesc;
144
100
  class TurtleHeadedPipe extends PipelineDesc {
@@ -49,9 +49,9 @@ export declare class SQAppendView extends SourceQueryNode {
49
49
  }
50
50
  export declare class SQRefinedQuery extends SourceQueryNode {
51
51
  readonly toRefine: SourceQueryNode;
52
- readonly refine: QOPDesc;
52
+ readonly refine: QOPDesc | ViewFieldReference;
53
53
  elementType: string;
54
- constructor(toRefine: SourceQueryNode, refine: QOPDesc);
54
+ constructor(toRefine: SourceQueryNode, refine: QOPDesc | ViewFieldReference);
55
55
  getQuery(): QueryElement | undefined;
56
56
  getSource(): QuerySource | undefined;
57
57
  }
@@ -118,7 +118,7 @@ class SQLegacyModify extends source_query_1.SourceQueryNode {
118
118
  stmt.log('Unable to add this refinement to query');
119
119
  }
120
120
  }
121
- asQuery.refineWith(new qop_desc_1.QOPDesc(stmts));
121
+ asQuery.refineWith([new qop_desc_1.QOPDesc(stmts)]);
122
122
  this.has({ asQuery });
123
123
  return asQuery;
124
124
  }
@@ -219,34 +219,15 @@ class SQAppendView extends source_query_1.SourceQueryNode {
219
219
  theQuery = new full_query_1.FullQuery(querySrc);
220
220
  this.has({ theQuery });
221
221
  const head = views[0];
222
+ const refinements = views.slice(1);
222
223
  if (head instanceof field_references_1.ViewFieldReference) {
223
224
  theQuery.turtleName = head.list[0];
224
- if (views.length === 1) {
225
- return theQuery;
226
- }
227
- if (views.length === 2) {
228
- if (views[1] instanceof qop_desc_1.QOPDesc) {
229
- theQuery.refineWith(views[1]);
230
- return theQuery;
231
- }
232
- else {
233
- this.sqLog('Cannot refine with a named view');
234
- return;
235
- }
236
- }
237
- else {
238
- this.sqLog('Cannot have multiple refinements');
239
- }
240
225
  }
241
- else if (views.length === 1) {
242
- if (head instanceof qop_desc_1.QOPDesc) {
243
- theQuery.addSegments(head);
244
- return theQuery;
245
- }
226
+ else if (head instanceof qop_desc_1.QOPDesc) {
227
+ theQuery.addSegments(head);
246
228
  }
247
- if (views.length > 0) {
248
- this.sqLog('Cannot have multiple refinements');
249
- return;
229
+ if (refinements) {
230
+ theQuery.refineWith(refinements);
250
231
  }
251
232
  return theQuery;
252
233
  }
@@ -309,7 +290,7 @@ class SQRefinedQuery extends source_query_1.SourceQueryNode {
309
290
  this.sqLog('Cannot refine a refined query');
310
291
  return;
311
292
  }
312
- refinedQuery.refineWith(this.refine);
293
+ refinedQuery.refineWith([this.refine]);
313
294
  this.has({ query: refinedQuery });
314
295
  return refinedQuery;
315
296
  }
@@ -26,6 +26,7 @@ exports.ExistingQuery = void 0;
26
26
  const pipeline_desc_1 = require("../elements/pipeline-desc");
27
27
  const error_factory_1 = require("../error-factory");
28
28
  const static_space_1 = require("../field-space/static-space");
29
+ const struct_utils_1 = require("../struct-utils");
29
30
  const query_head_struct_1 = require("./query-head-struct");
30
31
  class ExistingQuery extends pipeline_desc_1.PipelineDesc {
31
32
  constructor() {
@@ -63,7 +64,7 @@ class ExistingQuery extends pipeline_desc_1.PipelineDesc {
63
64
  const exploreStruct = queryHead.structDef();
64
65
  const exploreFS = new static_space_1.StaticSpace(exploreStruct);
65
66
  const sourcePipe = this.refinePipeline(exploreFS, head);
66
- const walkStruct = this.getFinalStruct(exploreStruct, sourcePipe.pipeline);
67
+ const walkStruct = (0, struct_utils_1.getFinalStruct)(this, exploreStruct, sourcePipe.pipeline);
67
68
  const appended = this.appendOps(new static_space_1.StaticSpace(walkStruct), sourcePipe.pipeline);
68
69
  const destPipe = { ...sourcePipe, pipeline: appended.opList };
69
70
  const query = {
@@ -27,6 +27,7 @@ const malloy_types_1 = require("../../../model/malloy_types");
27
27
  const error_factory_1 = require("../error-factory");
28
28
  const static_space_1 = require("../field-space/static-space");
29
29
  const pipeline_desc_1 = require("../elements/pipeline-desc");
30
+ const struct_utils_1 = require("../struct-utils");
30
31
  class FullQuery extends pipeline_desc_1.TurtleHeadedPipe {
31
32
  constructor(explore) {
32
33
  super({ explore: explore });
@@ -76,7 +77,9 @@ class FullQuery extends pipeline_desc_1.TurtleHeadedPipe {
76
77
  const { pipeline, location, annotation } = this.expandTurtle(name, structDef);
77
78
  destQuery.location = location;
78
79
  let walkPipe = pipeline;
79
- if (this.withRefinement) {
80
+ if (this.refinements &&
81
+ this.refinements.length > 0 &&
82
+ pipeline.length !== 0) {
80
83
  const refined = this.refinePipeline(pipeFS, { pipeline }).pipeline;
81
84
  // TODO there is an issue with losing the name of the turtle
82
85
  // which we need to fix, possibly adding a "name:" field to a segment
@@ -90,12 +93,22 @@ class FullQuery extends pipeline_desc_1.TurtleHeadedPipe {
90
93
  if (annotation) {
91
94
  destQuery.annotation = annotation;
92
95
  }
93
- const pipeOutput = this.getFinalStruct(structDef, walkPipe);
96
+ const pipeOutput = (0, struct_utils_1.getFinalStruct)(this, structDef, walkPipe);
94
97
  pipeFS = new static_space_1.StaticSpace(pipeOutput);
95
98
  }
96
99
  const appended = this.appendOps(pipeFS, destQuery.pipeline);
97
100
  destQuery.pipeline = appended.opList;
98
- return { outputStruct: appended.structDef, query: destQuery };
101
+ if (!this.turtleName && this.refinements) {
102
+ const refined = this.refinePipeline(pipeFS, {
103
+ pipeline: destQuery.pipeline,
104
+ }).pipeline;
105
+ destQuery.pipeline = refined;
106
+ const pipeOutput = (0, struct_utils_1.getFinalStruct)(this, structDef, refined);
107
+ return { outputStruct: pipeOutput, query: destQuery };
108
+ }
109
+ else {
110
+ return { outputStruct: appended.structDef, query: destQuery };
111
+ }
99
112
  }
100
113
  query() {
101
114
  return this.queryComp(true).query;
@@ -181,9 +181,7 @@ class ViewFieldReference extends FieldReference {
181
181
  super(...arguments);
182
182
  this.elementType = 'viewFieldRefernce';
183
183
  }
184
- typecheck(_type) {
185
- this.log('Cannot use a view field in an expression');
186
- }
184
+ typecheck(_type) { }
187
185
  }
188
186
  exports.ViewFieldReference = ViewFieldReference;
189
187
  class WildcardFieldReference extends malloy_element_1.MalloyElement {
@@ -31,6 +31,7 @@ const query_property_interface_1 = require("../types/query-property-interface");
31
31
  const query_spaces_1 = require("../field-space/query-spaces");
32
32
  const model_1 = require("../../../model");
33
33
  const field_references_1 = require("../query-items/field-references");
34
+ const struct_utils_1 = require("../struct-utils");
34
35
  function isTurtle(fd) {
35
36
  const ret = fd && typeof fd !== 'string' && fd.type === 'turtle';
36
37
  return !!ret;
@@ -66,16 +67,22 @@ class TurtleDeclRoot extends pipeline_desc_1.TurtleHeadedPipe {
66
67
  this.log(`Expected '${this.turtleName}' to be a query`);
67
68
  }
68
69
  }
69
- else if (this.withRefinement) {
70
- throw this.internalError("Can't refine the head of a view in its definition");
71
- }
72
70
  let pipeOutFS = fs;
73
71
  if (modelPipe.pipeline.length > 0) {
74
- const lastOut = this.getFinalStruct(fs.structDef(), modelPipe.pipeline);
72
+ const lastOut = (0, struct_utils_1.getFinalStruct)(this, fs.structDef(), modelPipe.pipeline);
75
73
  pipeOutFS = new static_space_1.StaticSpace(lastOut);
76
74
  }
77
75
  const appended = this.appendOps(pipeOutFS, modelPipe.pipeline);
78
76
  modelPipe.pipeline = appended.opList;
77
+ if (this.refinements &&
78
+ this.refinements.length > 0 &&
79
+ this.turtleName === undefined) {
80
+ const refined = this.refinePipeline(fs, {
81
+ pipeline: modelPipe.pipeline,
82
+ }).pipeline;
83
+ modelPipe.pipeline = refined;
84
+ return modelPipe;
85
+ }
79
86
  return modelPipe;
80
87
  }
81
88
  getFieldDef(fs, nestParent) {
@@ -0,0 +1,25 @@
1
+ import { PipeSegment } from '../../../model/malloy_types';
2
+ import { FieldSpace } from '../types/field-space';
3
+ import { MalloyElement } from '../types/malloy-element';
4
+ import { OpDesc } from '../types/op-desc';
5
+ import { ViewFieldReference } from '../query-items/field-references';
6
+ import { QOPDesc } from './qop-desc';
7
+ export declare abstract class Refinement extends MalloyElement {
8
+ abstract refine(inputFS: FieldSpace, pipeline: PipeSegment[]): PipeSegment[];
9
+ static from(base: QOPDesc | ViewFieldReference): QOPDescRefinement | NamedRefinement;
10
+ }
11
+ export declare class NamedRefinement extends Refinement {
12
+ private readonly name;
13
+ elementType: string;
14
+ constructor(name: ViewFieldReference);
15
+ private getRefinementSegment;
16
+ refine(inputFS: FieldSpace, pipeline: PipeSegment[]): PipeSegment[];
17
+ getOp(inputFS: FieldSpace, _to: PipeSegment): OpDesc;
18
+ }
19
+ export declare class QOPDescRefinement extends Refinement {
20
+ private readonly qOpDesc;
21
+ elementType: string;
22
+ constructor(qOpDesc: QOPDesc);
23
+ private getOp;
24
+ refine(inputFS: FieldSpace, _pipeline: PipeSegment[]): PipeSegment[];
25
+ }
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2023 Google LLC
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files
7
+ * (the "Software"), to deal in the Software without restriction,
8
+ * including without limitation the rights to use, copy, modify, merge,
9
+ * publish, distribute, sublicense, and/or sell copies of the Software,
10
+ * and to permit persons to whom the Software is furnished to do so,
11
+ * subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.QOPDescRefinement = exports.NamedRefinement = exports.Refinement = void 0;
26
+ const malloy_element_1 = require("../types/malloy-element");
27
+ const struct_utils_1 = require("../struct-utils");
28
+ const static_space_1 = require("../field-space/static-space");
29
+ const query_property_interface_1 = require("../types/query-property-interface");
30
+ const qop_desc_1 = require("./qop-desc");
31
+ const space_field_1 = require("../types/space-field");
32
+ class Refinement extends malloy_element_1.MalloyElement {
33
+ static from(base) {
34
+ return base instanceof qop_desc_1.QOPDesc
35
+ ? new QOPDescRefinement(base)
36
+ : new NamedRefinement(base);
37
+ }
38
+ }
39
+ exports.Refinement = Refinement;
40
+ class NamedRefinement extends Refinement {
41
+ constructor(name) {
42
+ super({ name });
43
+ this.name = name;
44
+ this.elementType = 'namedRefinement';
45
+ }
46
+ getRefinementSegment(fs) {
47
+ const res = this.name.getField(fs);
48
+ if (!res.found) {
49
+ this.name.log(`no such view \`${this.name.refString}\``);
50
+ return;
51
+ }
52
+ if (res.found instanceof space_field_1.SpaceField) {
53
+ const fieldDef = res.found.fieldDef();
54
+ if ((fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.type) === 'turtle') {
55
+ if (fieldDef.pipeline.length > 1 || fieldDef.pipeHead !== undefined) {
56
+ this.name.log(`named refinement \`${this.name.refString}\` must have exactly one stage`);
57
+ return;
58
+ }
59
+ return fieldDef.pipeline[0];
60
+ }
61
+ }
62
+ this.name.log(`named refinement \`${this.name.refString}\` must be a view, found a ${res.found.describeType().dataType}`);
63
+ }
64
+ refine(inputFS, pipeline) {
65
+ if (pipeline.length === 1) {
66
+ return [this.getOp(inputFS, pipeline[0]).segment];
67
+ }
68
+ else {
69
+ this.name.log('Named refinements of multi-stage views are not supported');
70
+ // TODO better error pipeline?
71
+ return pipeline;
72
+ }
73
+ }
74
+ getOp(inputFS, _to) {
75
+ var _a, _b;
76
+ const to = { ..._to };
77
+ const from = this.getRefinementSegment(inputFS);
78
+ if (from) {
79
+ if (from.type !== to.type) {
80
+ this.log(`cannot refine ${to.type} view with ${from.type} view`);
81
+ }
82
+ if (from.type !== 'index' && to.type !== 'index') {
83
+ if (from.orderBy !== undefined || from.by !== undefined) {
84
+ if (to.orderBy === undefined && to.by === undefined) {
85
+ if (from.orderBy) {
86
+ to.orderBy = from.orderBy;
87
+ }
88
+ else if (from.by) {
89
+ to.by = from.by;
90
+ }
91
+ }
92
+ else {
93
+ this.log('refinement cannot override existing ordering');
94
+ }
95
+ }
96
+ if (from.limit !== undefined) {
97
+ if (to.limit === undefined) {
98
+ to.limit = from.limit;
99
+ }
100
+ else {
101
+ this.log('refinement cannot override existing limit');
102
+ }
103
+ }
104
+ }
105
+ to.filterList =
106
+ to.filterList !== undefined || from.filterList !== undefined
107
+ ? [...((_a = to.filterList) !== null && _a !== void 0 ? _a : []), ...((_b = from.filterList) !== null && _b !== void 0 ? _b : [])]
108
+ : undefined;
109
+ const overlappingFields = [];
110
+ const nonOverlappingFields = [];
111
+ const existingNames = new Map(to.fields.map((f) => [
112
+ extractName(f),
113
+ f,
114
+ ]));
115
+ for (const field of from.fields) {
116
+ if (existingNames.has(extractName(field))) {
117
+ overlappingFields.push(field);
118
+ }
119
+ else {
120
+ nonOverlappingFields.push(field);
121
+ }
122
+ }
123
+ to.fields = [...to.fields, ...nonOverlappingFields];
124
+ if (overlappingFields.length > 0) {
125
+ this.log(`overlapping fields in refinement: ${overlappingFields.map(extractName)}`);
126
+ }
127
+ }
128
+ return {
129
+ segment: to,
130
+ outputSpace: () => new static_space_1.StaticSpace((0, struct_utils_1.opOutputStruct)(this.name, inputFS.structDef(), to)),
131
+ };
132
+ }
133
+ }
134
+ exports.NamedRefinement = NamedRefinement;
135
+ function extractName(f1) {
136
+ var _a;
137
+ return typeof f1 === 'string' ? f1 : (_a = f1.as) !== null && _a !== void 0 ? _a : f1.name;
138
+ }
139
+ class QOPDescRefinement extends Refinement {
140
+ constructor(qOpDesc) {
141
+ super({ qOpDesc });
142
+ this.qOpDesc = qOpDesc;
143
+ this.elementType = 'qopdescRefinement';
144
+ }
145
+ getOp(inputFS, headFS, qOpDesc, refineThis) {
146
+ qOpDesc.refineFrom(refineThis);
147
+ return qOpDesc.getOp(inputFS, headFS).segment;
148
+ }
149
+ refine(inputFS, _pipeline) {
150
+ const pipeline = [..._pipeline];
151
+ if (pipeline.length === 1) {
152
+ this.qOpDesc.refineFrom(pipeline[0]);
153
+ return [this.getOp(inputFS, undefined, this.qOpDesc, pipeline[0])];
154
+ }
155
+ const headRefinements = new qop_desc_1.QOPDesc([]);
156
+ const tailRefinements = new qop_desc_1.QOPDesc([]);
157
+ for (const qop of this.qOpDesc.list) {
158
+ switch (qop.queryRefinementStage) {
159
+ case query_property_interface_1.LegalRefinementStage.Head:
160
+ headRefinements.push(qop);
161
+ break;
162
+ case query_property_interface_1.LegalRefinementStage.Single:
163
+ qop.log('Illegal in refinement of a query with more than one stage');
164
+ break;
165
+ case query_property_interface_1.LegalRefinementStage.Tail:
166
+ tailRefinements.push(qop);
167
+ break;
168
+ default:
169
+ qop.log('Illegal query refinement');
170
+ }
171
+ }
172
+ if (headRefinements.notEmpty()) {
173
+ this.has({ headRefinements });
174
+ pipeline[0] = this.getOp(inputFS, undefined, headRefinements, pipeline[0]);
175
+ }
176
+ if (tailRefinements.notEmpty()) {
177
+ const last = pipeline.length - 1;
178
+ this.has({ tailRefinements });
179
+ const finalIn = (0, struct_utils_1.getFinalStruct)(this, inputFS.structDef(), pipeline.slice(-1));
180
+ pipeline[last] = this.getOp(new static_space_1.StaticSpace(finalIn), undefined, tailRefinements, pipeline[last]);
181
+ }
182
+ return pipeline;
183
+ }
184
+ }
185
+ exports.QOPDescRefinement = QOPDescRefinement;
186
+ //# sourceMappingURL=refinements.js.map
@@ -1,4 +1,5 @@
1
1
  import { FieldDef, PipeSegment, StructDef } from '../../model/malloy_types';
2
2
  import { MalloyElement } from './types/malloy-element';
3
3
  export declare function opOutputStruct(logTo: MalloyElement, inputStruct: StructDef, opDesc: PipeSegment): StructDef;
4
+ export declare function getFinalStruct(logTo: MalloyElement, walkStruct: StructDef, pipeline: PipeSegment[]): StructDef;
4
5
  export declare function getStructFieldDef(s: StructDef, fn: string): FieldDef | undefined;
@@ -22,7 +22,7 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.getStructFieldDef = exports.opOutputStruct = void 0;
25
+ exports.getStructFieldDef = exports.getFinalStruct = exports.opOutputStruct = void 0;
26
26
  const util_1 = require("util");
27
27
  const malloy_query_1 = require("../../model/malloy_query");
28
28
  const error_factory_1 = require("./error-factory");
@@ -41,6 +41,13 @@ function opOutputStruct(logTo, inputStruct, opDesc) {
41
41
  return { ...error_factory_1.ErrorFactory.structDef, dialect: inputStruct.dialect };
42
42
  }
43
43
  exports.opOutputStruct = opOutputStruct;
44
+ function getFinalStruct(logTo, walkStruct, pipeline) {
45
+ for (const modelQop of pipeline) {
46
+ walkStruct = opOutputStruct(logTo, walkStruct, modelQop);
47
+ }
48
+ return walkStruct;
49
+ }
50
+ exports.getFinalStruct = getFinalStruct;
44
51
  function getStructFieldDef(s, fn) {
45
52
  return s.fields.find(fld => (fld.as || fld.name) === fn);
46
53
  }
@@ -53,7 +53,7 @@ export declare abstract class MalloyElement {
53
53
  private varInfo;
54
54
  protected internalError(msg: string): Error;
55
55
  needs(doc: Document): ModelDataRequest | undefined;
56
- inExperiment(experimentID: string): boolean;
56
+ inExperiment(experimentID: string, silent?: boolean): boolean;
57
57
  }
58
58
  export declare class Unimplemented extends MalloyElement {
59
59
  elementType: string;
@@ -262,14 +262,16 @@ class MalloyElement {
262
262
  return childNeeds;
263
263
  }
264
264
  }
265
- inExperiment(experimentID) {
265
+ inExperiment(experimentID, silent = false) {
266
266
  var _a;
267
267
  const experimental = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.compilerFlags.tag('experimental');
268
268
  const enabled = experimental && (experimental.bare() || experimental.has(experimentID));
269
269
  if (enabled) {
270
270
  return true;
271
271
  }
272
- this.log(`Experimental flag '${experimentID}' is not set, feature not available`);
272
+ if (!silent) {
273
+ this.log(`Experimental flag '${experimentID}' is not set, feature not available`);
274
+ }
273
275
  return false;
274
276
  }
275
277
  }