@malloydata/malloy 0.0.104-dev231116200719 → 0.0.104-dev231117214047

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 (33) hide show
  1. package/dist/lang/ast/elements/pipeline-desc.d.ts +13 -2
  2. package/dist/lang/ast/elements/pipeline-desc.js +15 -2
  3. package/dist/lang/ast/expressions/constant-sub-expression.js +0 -3
  4. package/dist/lang/ast/expressions/expr-ungroup.js +24 -19
  5. package/dist/lang/ast/field-space/dynamic-space.d.ts +0 -1
  6. package/dist/lang/ast/field-space/dynamic-space.js +0 -12
  7. package/dist/lang/ast/field-space/query-input-space.d.ts +0 -1
  8. package/dist/lang/ast/field-space/query-spaces.d.ts +1 -7
  9. package/dist/lang/ast/field-space/query-spaces.js +0 -27
  10. package/dist/lang/ast/field-space/static-space.d.ts +0 -1
  11. package/dist/lang/ast/field-space/static-space.js +0 -19
  12. package/dist/lang/ast/query-items/field-declaration.d.ts +0 -1
  13. package/dist/lang/ast/query-items/field-declaration.js +0 -3
  14. package/dist/lang/ast/query-properties/nest.d.ts +6 -4
  15. package/dist/lang/ast/query-properties/nest.js +16 -14
  16. package/dist/lang/ast/query-properties/qop-desc.d.ts +2 -2
  17. package/dist/lang/ast/query-properties/qop-desc.js +3 -3
  18. package/dist/lang/ast/query-properties/refinements.d.ts +10 -4
  19. package/dist/lang/ast/query-properties/refinements.js +7 -7
  20. package/dist/lang/ast/types/field-space.d.ts +0 -1
  21. package/dist/lang/parse-malloy.d.ts +9 -1
  22. package/dist/lang/parse-malloy.js +28 -0
  23. package/dist/lang/parse-tree-walkers/model-annotation-walker.d.ts +5 -0
  24. package/dist/lang/parse-tree-walkers/model-annotation-walker.js +60 -0
  25. package/dist/lang/test/model-annotation-walker.spec.d.ts +1 -0
  26. package/dist/lang/test/model-annotation-walker.spec.js +46 -0
  27. package/dist/lang/test/query.spec.js +20 -0
  28. package/dist/lang/translate-response.d.ts +5 -1
  29. package/dist/malloy.d.ts +3 -1
  30. package/dist/malloy.js +36 -4
  31. package/dist/run_sql_options.d.ts +3 -0
  32. package/dist/runtime_types.d.ts +2 -1
  33. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { Annotation, DocumentLocation, PipeSegment, Pipeline, StructDef } from '
2
2
  import { FieldSpace } from '../types/field-space';
3
3
  import { MalloyElement } from '../types/malloy-element';
4
4
  import { QOPDesc } from '../query-properties/qop-desc';
5
- import { QueryInputSpace } from '../field-space/query-input-space';
5
+ import { QuerySpace } from '../field-space/query-spaces';
6
6
  import { ViewFieldReference } from '../query-items/field-references';
7
7
  import { Refinement } from '../query-properties/refinements';
8
8
  interface AppendResult {
@@ -17,7 +17,18 @@ interface AppendResult {
17
17
  export declare abstract class PipelineDesc extends MalloyElement {
18
18
  protected refinements?: Refinement[];
19
19
  protected qops: QOPDesc[];
20
- nestedInQuerySpace?: QueryInputSpace;
20
+ private isNestIn?;
21
+ /**
22
+ * This pipeline is actually a nest statement, and the passed query space
23
+ * is the space for the query which contains the nest statement. This is
24
+ * used so that nest queries can walk up a nest chain to check
25
+ * "ungrouping" expressions.
26
+ *
27
+ * This is only here so that it can be used when a Builder is created
28
+ * so the query space created by the builder can also know that it is
29
+ * nested.
30
+ */
31
+ declareAsNestInside(qs: QuerySpace): void;
21
32
  alreadyRefined(): boolean;
22
33
  refineWith(refinements: (QOPDesc | ViewFieldReference)[]): void;
23
34
  addSegments(...segDesc: QOPDesc[]): void;
@@ -40,6 +40,19 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
40
40
  super(...arguments);
41
41
  this.qops = [];
42
42
  }
43
+ /**
44
+ * This pipeline is actually a nest statement, and the passed query space
45
+ * is the space for the query which contains the nest statement. This is
46
+ * used so that nest queries can walk up a nest chain to check
47
+ * "ungrouping" expressions.
48
+ *
49
+ * This is only here so that it can be used when a Builder is created
50
+ * so the query space created by the builder can also know that it is
51
+ * nested.
52
+ */
53
+ declareAsNestInside(qs) {
54
+ this.isNestIn = qs;
55
+ }
43
56
  alreadyRefined() {
44
57
  return this.refinements !== undefined;
45
58
  }
@@ -54,7 +67,7 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
54
67
  }
55
68
  appendOps(pipelineOutput, modelPipe) {
56
69
  const returnPipe = [...modelPipe];
57
- const nestedIn = modelPipe.length === 0 ? this.nestedInQuerySpace : undefined;
70
+ const nestedIn = modelPipe.length === 0 ? this.isNestIn : undefined;
58
71
  let nextFS = () => pipelineOutput;
59
72
  for (const qop of this.qops) {
60
73
  const next = qop.getOp(nextFS(), nestedIn);
@@ -81,7 +94,7 @@ class PipelineDesc extends malloy_element_1.MalloyElement {
81
94
  }
82
95
  pipeline.push(...modelPipe.pipeline);
83
96
  for (const refinement of this.refinements) {
84
- pipeline = refinement.refine(fs, pipeline);
97
+ pipeline = refinement.refine(fs, pipeline, this.isNestIn);
85
98
  }
86
99
  return { pipeline };
87
100
  }
@@ -52,9 +52,6 @@ class ConstantFieldSpace {
52
52
  dialectObj() {
53
53
  return undefined;
54
54
  }
55
- whenComplete(step) {
56
- step();
57
- }
58
55
  isQueryFieldSpace() {
59
56
  return false;
60
57
  }
@@ -55,28 +55,33 @@ class ExprUngroup extends expression_def_1.ExpressionDef {
55
55
  e: exprVal.value,
56
56
  };
57
57
  if (this.typeCheck(this.expr, { ...exprVal, expressionType: 'scalar' })) {
58
- if (this.fields.length > 0) {
59
- if (!fs.isQueryFieldSpace()) {
60
- this.log(`${this.control}() must be in a query -- weird internal error`);
61
- return (0, ast_utils_1.errorFor)('ungroup query check');
62
- }
63
- const output = fs.outputSpace();
64
- if (!(output instanceof query_spaces_1.QuerySpace)) {
65
- // TODO maybe make OutputSpace return an interface which has checkUngroup
66
- this.log(`${this.control}() must be in a query -- weird internal error`);
67
- return (0, ast_utils_1.errorFor)('ungroup query check');
68
- }
58
+ // Now every mentioned field must be in the output space of one of the queries
59
+ // of the nest tree leading to this query. If this is a source definition,
60
+ // this is not checked until sql generation time.
61
+ if (fs.isQueryFieldSpace() && this.fields.length > 0) {
69
62
  const dstFields = [];
70
63
  const isExclude = this.control === 'exclude';
71
- for (const mustBeInOutput of this.fields) {
72
- output.whenComplete(() => {
73
- output.checkUngroup(mustBeInOutput, isExclude);
74
- });
75
- dstFields.push(mustBeInOutput.refString);
64
+ for (const mentionedField of this.fields) {
65
+ let ofs = fs.outputSpace();
66
+ let notFound = true;
67
+ while (ofs) {
68
+ const entryInfo = ofs.lookup([mentionedField]);
69
+ if (entryInfo.found && entryInfo.isOutputField) {
70
+ dstFields.push(mentionedField.refString);
71
+ notFound = false;
72
+ }
73
+ else if (ofs instanceof query_spaces_1.QuerySpace) {
74
+ // should always be true, but don't have types right, thus the if
75
+ ofs = ofs.nestParent;
76
+ continue;
77
+ }
78
+ break;
79
+ }
80
+ if (notFound) {
81
+ const uName = isExclude ? 'exclude()' : 'all()';
82
+ mentionedField.log(`${uName} '${mentionedField.refString}' is missing from query output`);
83
+ }
76
84
  }
77
- // TODO maybe now we can just look up the fields in the output space now and ensure
78
- // they're all there, rather than waiting until the query is finished to do it?
79
- // See `order_by` for an example of how this could work.
80
85
  ungroup.fields = dstFields;
81
86
  }
82
87
  return {
@@ -11,7 +11,6 @@ export declare abstract class DynamicSpace extends StaticSpace {
11
11
  private complete;
12
12
  protected newTimezone?: string;
13
13
  constructor(extending: SourceSpec);
14
- whenComplete(finalizeStep: () => void): void;
15
14
  isComplete(): void;
16
15
  protected setEntry(name: string, value: SpaceEntry): void;
17
16
  addParameters(params: HasParameter[]): DynamicSpace;
@@ -45,20 +45,8 @@ class DynamicSpace extends static_space_1.StaticSpace {
45
45
  this.final = undefined;
46
46
  this.source = source;
47
47
  }
48
- whenComplete(finalizeStep) {
49
- if (this.complete) {
50
- finalizeStep();
51
- }
52
- else {
53
- this.completions.push(finalizeStep);
54
- }
55
- }
56
48
  isComplete() {
57
49
  this.complete = true;
58
- for (const step of this.completions) {
59
- step();
60
- }
61
- this.completions = [];
62
50
  }
63
51
  setEntry(name, value) {
64
52
  if (this.final) {
@@ -12,7 +12,6 @@ import { FieldSpace, QueryFieldSpace } from '../types/field-space';
12
12
  import { RefinedSpace } from './refined-space';
13
13
  export declare class QueryInputSpace extends RefinedSpace implements QueryFieldSpace {
14
14
  private queryOutput;
15
- nestParent?: QueryInputSpace;
16
15
  extendList: string[];
17
16
  /**
18
17
  * Because of circularity concerns this constructor is not typed
@@ -17,18 +17,12 @@ export declare abstract class QuerySpace extends RefinedSpace implements QueryFi
17
17
  astEl?: MalloyElement | undefined;
18
18
  abstract readonly segmentType: 'reduce' | 'project' | 'index';
19
19
  expandedWild: Record<string, string[]>;
20
+ nestParent?: QuerySpace;
20
21
  constructor(queryInputSpace: FieldSpace, refineThis: model.PipeSegment | undefined);
21
22
  private addRefineFromFields;
22
23
  log(s: string): void;
23
24
  pushFields(...defs: MalloyElement[]): void;
24
25
  protected addWild(wild: WildcardFieldReference): void;
25
- /**
26
- * Check for the definition of an ungrouping reference in the result space,
27
- * or in the case of an exclude reference, if this query is nested
28
- * in another query, in the result space of a query that this query
29
- * is nested inside of.
30
- */
31
- checkUngroup(fn: FieldName, isExclude: boolean): void;
32
26
  canContain(_typeDesc: model.TypeDesc): boolean;
33
27
  protected queryFieldDefs(): model.QueryFieldDef[];
34
28
  getQuerySegment(rf: model.QuerySegment | undefined): model.QuerySegment;
@@ -155,33 +155,6 @@ class QuerySpace extends refined_space_1.RefinedSpace {
155
155
  }
156
156
  }
157
157
  }
158
- /**
159
- * Check for the definition of an ungrouping reference in the result space,
160
- * or in the case of an exclude reference, if this query is nested
161
- * in another query, in the result space of a query that this query
162
- * is nested inside of.
163
- */
164
- checkUngroup(fn, isExclude) {
165
- if (!this.entry(fn.refString)) {
166
- const parent = this.exprSpace.nestParent;
167
- if (isExclude && parent) {
168
- parent.whenComplete(() => {
169
- const pOut = parent.outputSpace();
170
- // a little ugly, but it breaks a circularity problem
171
- if (pOut instanceof QuerySpace) {
172
- pOut.checkUngroup(fn, isExclude);
173
- }
174
- else {
175
- throw new Error('OUCH');
176
- }
177
- });
178
- }
179
- else {
180
- const uName = isExclude ? 'exclude()' : 'all()';
181
- fn.log(`${uName} '${fn.refString}' is missing from query output`);
182
- }
183
- }
184
- }
185
158
  canContain(_typeDesc) {
186
159
  return true;
187
160
  }
@@ -10,7 +10,6 @@ export declare class StaticSpace implements FieldSpace {
10
10
  private memoMap?;
11
11
  protected fromStruct: StructDef;
12
12
  constructor(sourceStructDef: StructDef);
13
- whenComplete(step: () => void): void;
14
13
  dialectObj(): Dialect | undefined;
15
14
  defToSpaceField(from: FieldDef): SpaceField;
16
15
  private get map();
@@ -35,9 +35,6 @@ class StaticSpace {
35
35
  this.type = 'fieldSpace';
36
36
  this.fromStruct = sourceStructDef;
37
37
  }
38
- whenComplete(step) {
39
- step();
40
- }
41
38
  dialectObj() {
42
39
  try {
43
40
  return (0, dialect_map_1.getDialect)(this.fromStruct.dialect);
@@ -104,22 +101,6 @@ class StaticSpace {
104
101
  return { error: `'${head}' is not defined`, found };
105
102
  }
106
103
  if (found instanceof space_field_1.SpaceField) {
107
- /*
108
- * TODO cache defs, post the addReference call to whenComplete
109
- *
110
- * In the cleanup phase of query space construction, it may check
111
- * the output space for ungrouping variables. However if an
112
- * ungrouping variable is a measure, the field expression value
113
- * needed to get the definition needs to be computed in the
114
- * input space of the query. There is a test which failed which
115
- * caused this code to be here, but this is really a bandaid.
116
- *
117
- * Some re-work of how to get the definition of a SpaceField
118
- * no matter what it is contained in needs to be thought out.
119
- *
120
- * ... or this check would look at the finalized output of
121
- * the namespace and not re-compile ...
122
- */
123
104
  const definition = found.fieldDef();
124
105
  if (definition) {
125
106
  head.addReference({
@@ -68,7 +68,6 @@ export declare class DefSpace implements FieldSpace {
68
68
  lookup(symbol: FieldName[]): LookupResult;
69
69
  entries(): [string, SpaceEntry][];
70
70
  dialectObj(): Dialect | undefined;
71
- whenComplete(step: () => void): void;
72
71
  isQueryFieldSpace(): this is QueryFieldSpace;
73
72
  outputSpace(): FieldSpace;
74
73
  inputSpace(): FieldSpace;
@@ -226,9 +226,6 @@ class DefSpace {
226
226
  dialectObj() {
227
227
  return this.realFS.dialectObj();
228
228
  }
229
- whenComplete(step) {
230
- this.realFS.whenComplete(step);
231
- }
232
229
  isQueryFieldSpace() {
233
230
  return this.realFS.isQueryFieldSpace();
234
231
  }
@@ -4,11 +4,11 @@ import { MalloyElement } from '../types/malloy-element';
4
4
  import { Noteable, extendNoteMethod } from '../types/noteable';
5
5
  import { QueryField } from '../field-space/query-space-field';
6
6
  import { TurtleHeadedPipe } from '../elements/pipeline-desc';
7
- import { QueryInputSpace } from '../field-space/query-input-space';
8
7
  import { LegalRefinementStage, QueryClass, QueryPropertyInterface } from '../types/query-property-interface';
9
8
  import { QueryBuilder } from '../types/query-builder';
10
9
  import { MakeEntry } from '../types/space-entry';
11
10
  import { DynamicSpace } from '../field-space/dynamic-space';
11
+ import { QuerySpace } from '../field-space/query-spaces';
12
12
  import { TypeDesc } from '../../../model';
13
13
  import { FieldReference, ViewFieldReference } from '../query-items/field-references';
14
14
  declare abstract class TurtleDeclRoot extends TurtleHeadedPipe implements Noteable, MakeEntry {
@@ -18,7 +18,7 @@ declare abstract class TurtleDeclRoot extends TurtleHeadedPipe implements Noteab
18
18
  note?: model.Annotation;
19
19
  constructor(name: string);
20
20
  getPipeline(fs: FieldSpace): model.Pipeline;
21
- getFieldDef(fs: FieldSpace, nestParent: QueryInputSpace | undefined): model.TurtleDef;
21
+ getFieldDef(fs: FieldSpace): model.TurtleDef;
22
22
  makeEntry(fs: DynamicSpace): void;
23
23
  }
24
24
  export declare class TurtleDecl extends TurtleDeclRoot {
@@ -41,15 +41,17 @@ export declare class NestDefinition extends TurtleDeclRoot implements QueryPrope
41
41
  makeEntry(fs: DynamicSpace): void;
42
42
  }
43
43
  export declare function isNestedQuery(me: MalloyElement): me is NestedQuery;
44
- export declare class QueryFieldAST extends QueryField {
44
+ export declare class ViewField extends QueryField {
45
45
  readonly turtle: TurtleDecl;
46
46
  protected name: string;
47
47
  renameAs?: string;
48
- nestParent?: QueryInputSpace;
49
48
  constructor(fs: FieldSpace, turtle: TurtleDecl, name: string);
50
49
  getQueryFieldDef(fs: FieldSpace): model.QueryFieldDef;
51
50
  fieldDef(): model.TurtleDef;
52
51
  }
52
+ export declare class NestField extends ViewField {
53
+ constructor(fs: FieldSpace, turtle: TurtleDecl, name: string, spaceContainingNest: QuerySpace);
54
+ }
53
55
  export declare class NestReference extends FieldReference implements QueryPropertyInterface, MakeEntry {
54
56
  readonly name: FieldReference;
55
57
  elementType: string;
@@ -45,7 +45,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
45
45
  return result;
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.NestReference = exports.QueryFieldAST = exports.isNestedQuery = exports.NestDefinition = exports.NestRefinement = exports.TurtleDecl = void 0;
48
+ exports.NestReference = exports.NestField = exports.ViewField = exports.isNestedQuery = exports.NestDefinition = exports.NestRefinement = exports.TurtleDecl = void 0;
49
49
  const model = __importStar(require("../../../model/malloy_types"));
50
50
  const noteable_1 = require("../types/noteable");
51
51
  const query_space_field_1 = require("../field-space/query-space-field");
@@ -126,10 +126,7 @@ class TurtleDeclRoot extends pipeline_desc_1.TurtleHeadedPipe {
126
126
  }
127
127
  return modelPipe;
128
128
  }
129
- getFieldDef(fs, nestParent) {
130
- if (nestParent) {
131
- this.nestedInQuerySpace = nestParent;
132
- }
129
+ getFieldDef(fs) {
133
130
  const pipe = this.getPipeline(fs);
134
131
  const turtle = {
135
132
  type: 'turtle',
@@ -148,7 +145,7 @@ class TurtleDeclRoot extends pipeline_desc_1.TurtleHeadedPipe {
148
145
  return turtle;
149
146
  }
150
147
  makeEntry(fs) {
151
- fs.newEntry(this.name, this, new QueryFieldAST(fs, this, this.name));
148
+ fs.newEntry(this.name, this, new ViewField(fs, this, this.name));
152
149
  }
153
150
  }
154
151
  class TurtleDecl extends TurtleDeclRoot {
@@ -171,8 +168,7 @@ class NestRefinement extends TurtleDeclRoot {
171
168
  }
172
169
  makeEntry(fs) {
173
170
  if (fs instanceof query_spaces_1.QuerySpace) {
174
- const qf = new QueryFieldAST(fs, this, this.name);
175
- qf.nestParent = fs.inputSpace();
171
+ const qf = new NestField(fs, this, this.name, fs);
176
172
  fs.newEntry(this.name, this, qf);
177
173
  return;
178
174
  }
@@ -192,8 +188,7 @@ class NestDefinition extends TurtleDeclRoot {
192
188
  }
193
189
  makeEntry(fs) {
194
190
  if (fs instanceof query_spaces_1.QuerySpace) {
195
- const qf = new QueryFieldAST(fs, this, this.name);
196
- qf.nestParent = fs.inputSpace();
191
+ const qf = new NestField(fs, this, this.name, fs);
197
192
  fs.newEntry(this.name, this, qf);
198
193
  return;
199
194
  }
@@ -207,28 +202,35 @@ function isNestedQuery(me) {
207
202
  me instanceof NestDefinition);
208
203
  }
209
204
  exports.isNestedQuery = isNestedQuery;
210
- class QueryFieldAST extends query_space_field_1.QueryField {
205
+ class ViewField extends query_space_field_1.QueryField {
211
206
  constructor(fs, turtle, name) {
212
207
  super(fs);
213
208
  this.turtle = turtle;
214
209
  this.name = name;
215
210
  }
216
211
  getQueryFieldDef(fs) {
217
- const def = this.turtle.getFieldDef(fs, this.nestParent);
212
+ const def = this.turtle.getFieldDef(fs);
218
213
  if (this.renameAs) {
219
214
  def.as = this.renameAs;
220
215
  }
221
216
  return def;
222
217
  }
223
218
  fieldDef() {
224
- const def = this.turtle.getFieldDef(this.inSpace, this.nestParent);
219
+ const def = this.turtle.getFieldDef(this.inSpace);
225
220
  if (this.renameAs) {
226
221
  def.as = this.renameAs;
227
222
  }
228
223
  return def;
229
224
  }
230
225
  }
231
- exports.QueryFieldAST = QueryFieldAST;
226
+ exports.ViewField = ViewField;
227
+ class NestField extends ViewField {
228
+ constructor(fs, turtle, name, spaceContainingNest) {
229
+ super(fs, turtle, name);
230
+ turtle.declareAsNestInside(spaceContainingNest);
231
+ }
232
+ }
233
+ exports.NestField = NestField;
232
234
  class NestReference extends field_references_1.FieldReference {
233
235
  constructor(name) {
234
236
  super([...name.list]);
@@ -4,7 +4,7 @@ import { ListOf } from '../types/malloy-element';
4
4
  import { OpDesc } from '../types/op-desc';
5
5
  import { QueryProperty } from '../types/query-property';
6
6
  import { QueryClass } from '../types/query-property-interface';
7
- import { QueryInputSpace } from '../field-space/query-input-space';
7
+ import { QuerySpace } from '../field-space/query-spaces';
8
8
  export declare class QOPDesc extends ListOf<QueryProperty> {
9
9
  elementType: string;
10
10
  opClass: QueryClass | undefined;
@@ -12,5 +12,5 @@ export declare class QOPDesc extends ListOf<QueryProperty> {
12
12
  protected computeType(): QueryClass | undefined;
13
13
  refineFrom(existing: PipeSegment): void;
14
14
  private getBuilder;
15
- getOp(inputFS: FieldSpace, headFieldSpace: QueryInputSpace | undefined): OpDesc;
15
+ getOp(inputFS: FieldSpace, isNestIn: QuerySpace | undefined): OpDesc;
16
16
  }
@@ -86,10 +86,10 @@ class QOPDesc extends malloy_element_1.ListOf {
86
86
  return new partial_builder_1.PartialBuilder(baseFS, this.refineThis);
87
87
  }
88
88
  }
89
- getOp(inputFS, headFieldSpace) {
89
+ getOp(inputFS, isNestIn) {
90
90
  const build = this.getBuilder(inputFS);
91
- if (headFieldSpace) {
92
- build.inputFS.nestParent = headFieldSpace;
91
+ if (isNestIn) {
92
+ build.resultFS.nestParent = isNestIn;
93
93
  }
94
94
  build.resultFS.astEl = this;
95
95
  for (const qp of this.list) {
@@ -4,8 +4,14 @@ import { MalloyElement } from '../types/malloy-element';
4
4
  import { OpDesc } from '../types/op-desc';
5
5
  import { ViewFieldReference } from '../query-items/field-references';
6
6
  import { QOPDesc } from './qop-desc';
7
+ import { QuerySpace } from '../field-space/query-spaces';
7
8
  export declare abstract class Refinement extends MalloyElement {
8
- abstract refine(inputFS: FieldSpace, pipeline: PipeSegment[]): PipeSegment[];
9
+ /**
10
+ * @param inputFS
11
+ * @param pipeline
12
+ * @param isNestIn The pipeline being refined is a nest, and this is the space which contains the nest statement
13
+ */
14
+ abstract refine(inputFS: FieldSpace, pipeline: PipeSegment[], isNestIn: QuerySpace | undefined): PipeSegment[];
9
15
  static from(base: QOPDesc | ViewFieldReference): QOPDescRefinement | NamedRefinement;
10
16
  }
11
17
  export declare class NamedRefinement extends Refinement {
@@ -13,13 +19,13 @@ export declare class NamedRefinement extends Refinement {
13
19
  elementType: string;
14
20
  constructor(name: ViewFieldReference);
15
21
  private getRefinementSegment;
16
- refine(inputFS: FieldSpace, pipeline: PipeSegment[]): PipeSegment[];
17
- getOp(inputFS: FieldSpace, _to: PipeSegment): OpDesc;
22
+ refine(inputFS: FieldSpace, pipeline: PipeSegment[], _isNestIn: QuerySpace | undefined): PipeSegment[];
23
+ getOp(inputFS: FieldSpace, refineTo: PipeSegment): OpDesc;
18
24
  }
19
25
  export declare class QOPDescRefinement extends Refinement {
20
26
  private readonly qOpDesc;
21
27
  elementType: string;
22
28
  constructor(qOpDesc: QOPDesc);
23
29
  private getOp;
24
- refine(inputFS: FieldSpace, _pipeline: PipeSegment[]): PipeSegment[];
30
+ refine(inputFS: FieldSpace, _pipeline: PipeSegment[], isNestIn: QuerySpace | undefined): PipeSegment[];
25
31
  }
@@ -70,7 +70,7 @@ class NamedRefinement extends Refinement {
70
70
  }
71
71
  this.name.log(`named refinement \`${this.name.refString}\` must be a view, found a ${res.found.typeDesc().dataType}`);
72
72
  }
73
- refine(inputFS, pipeline) {
73
+ refine(inputFS, pipeline, _isNestIn) {
74
74
  if (pipeline.length === 1) {
75
75
  return [this.getOp(inputFS, pipeline[0]).segment];
76
76
  }
@@ -80,9 +80,9 @@ class NamedRefinement extends Refinement {
80
80
  return pipeline;
81
81
  }
82
82
  }
83
- getOp(inputFS, _to) {
83
+ getOp(inputFS, refineTo) {
84
84
  var _a, _b;
85
- const to = { ..._to };
85
+ const to = { ...refineTo };
86
86
  const from = this.getRefinementSegment(inputFS);
87
87
  if (from) {
88
88
  // TODO need to disallow partial + index for now to make the types happy
@@ -155,15 +155,15 @@ class QOPDescRefinement extends Refinement {
155
155
  this.qOpDesc = qOpDesc;
156
156
  this.elementType = 'qopdescRefinement';
157
157
  }
158
- getOp(inputFS, headFS, qOpDesc, refineThis) {
158
+ getOp(inputFS, isNestIn, qOpDesc, refineThis) {
159
159
  qOpDesc.refineFrom(refineThis);
160
- return qOpDesc.getOp(inputFS, headFS).segment;
160
+ return qOpDesc.getOp(inputFS, isNestIn).segment;
161
161
  }
162
- refine(inputFS, _pipeline) {
162
+ refine(inputFS, _pipeline, isNestIn) {
163
163
  const pipeline = [..._pipeline];
164
164
  if (pipeline.length === 1) {
165
165
  this.qOpDesc.refineFrom(pipeline[0]);
166
- return [this.getOp(inputFS, undefined, this.qOpDesc, pipeline[0])];
166
+ return [this.getOp(inputFS, isNestIn, this.qOpDesc, pipeline[0])];
167
167
  }
168
168
  const headRefinements = new qop_desc_1.QOPDesc([]);
169
169
  const tailRefinements = new qop_desc_1.QOPDesc([]);
@@ -15,7 +15,6 @@ export interface FieldSpace {
15
15
  entry(symbol: string): SpaceEntry | undefined;
16
16
  entries(): [string, SpaceEntry][];
17
17
  dialectObj(): Dialect | undefined;
18
- whenComplete: (step: () => void) => void;
19
18
  isQueryFieldSpace(): this is QueryFieldSpace;
20
19
  }
21
20
  export interface QueryFieldSpace extends FieldSpace {
@@ -3,7 +3,7 @@ import { DocumentLocation, DocumentPosition, DocumentRange, DocumentReference, I
3
3
  import { LogMessage, MessageLog, MessageLogger } from './parse-log';
4
4
  import { Zone, ZoneData } from './zone';
5
5
  import { ReferenceList } from './reference-list';
6
- import { ASTResponse, CompletionsResponse, DataRequestResponse, ProblemResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse } from './translate-response';
6
+ import { ASTResponse, CompletionsResponse, DataRequestResponse, ProblemResponse, FatalResponse, FinalResponse, HelpContextResponse, MetadataResponse, ModelDataRequest, NeedURLData, TranslateResponse, ModelAnnotationResponse } from './translate-response';
7
7
  import { Tag } from '../tags';
8
8
  import { MalloyParseInfo } from './malloy-parse-info';
9
9
  export type StepResponses = DataRequestResponse | ASTResponse | TranslateResponse | ParseResponse | MetadataResponse;
@@ -83,6 +83,12 @@ declare class HelpContextStep implements TranslationStep {
83
83
  character: number;
84
84
  }): HelpContextResponse;
85
85
  }
86
+ declare class ModelAnnotationStep implements TranslationStep {
87
+ readonly parseStep: ParseStep;
88
+ response?: ModelAnnotationResponse;
89
+ constructor(parseStep: ParseStep);
90
+ step(that: MalloyTranslation, extendingModel?: ModelDef): ModelAnnotationResponse;
91
+ }
86
92
  declare class TranslateStep implements TranslationStep {
87
93
  readonly astStep: ASTStep;
88
94
  response?: TranslateResponse;
@@ -103,6 +109,7 @@ export declare abstract class MalloyTranslation {
103
109
  imports: ImportLocation[];
104
110
  compilerFlags: Tag;
105
111
  readonly parseStep: ParseStep;
112
+ readonly modelAnnotationStep: ModelAnnotationStep;
106
113
  readonly importsAndTablesStep: ImportsAndTablesStep;
107
114
  readonly astStep: ASTStep;
108
115
  readonly metadataStep: MetadataStep;
@@ -136,6 +143,7 @@ export declare abstract class MalloyTranslation {
136
143
  translate(extendingModel?: ModelDef): TranslateResponse;
137
144
  importAt(position: DocumentPosition): ImportLocation | undefined;
138
145
  metadata(): MetadataResponse;
146
+ modelAnnotation(extendingModel?: ModelDef): ModelAnnotationResponse;
139
147
  completions(position: {
140
148
  line: number;
141
149
  character: number;
@@ -62,6 +62,7 @@ const reference_list_1 = require("./reference-list");
62
62
  const translate_response_1 = require("./translate-response");
63
63
  const utils_1 = require("./utils");
64
64
  const tags_1 = require("../tags");
65
+ const model_annotation_walker_1 = require("./parse-tree-walkers/model-annotation-walker");
65
66
  /**
66
67
  * This ignores a -> popMode when the mode stack is empty, which is a hack,
67
68
  * but it let's us parse }%
@@ -451,6 +452,29 @@ class HelpContextStep {
451
452
  }
452
453
  }
453
454
  }
455
+ class ModelAnnotationStep {
456
+ constructor(parseStep) {
457
+ this.parseStep = parseStep;
458
+ }
459
+ step(that, extendingModel) {
460
+ if (!this.response) {
461
+ const tryParse = this.parseStep.step(that);
462
+ if (!tryParse.parse || tryParse.final) {
463
+ return tryParse;
464
+ }
465
+ else {
466
+ const modelAnnotation = (0, model_annotation_walker_1.walkForModelAnnotation)(that, tryParse.parse.tokenStream, tryParse.parse);
467
+ this.response = {
468
+ modelAnnotation: {
469
+ ...modelAnnotation,
470
+ inherits: extendingModel === null || extendingModel === void 0 ? void 0 : extendingModel.annotation,
471
+ },
472
+ };
473
+ }
474
+ }
475
+ return this.response;
476
+ }
477
+ }
454
478
  class TranslateStep {
455
479
  constructor(astStep) {
456
480
  this.astStep = astStep;
@@ -545,6 +569,7 @@ class MalloyTranslation {
545
569
  * things will happen automatically.
546
570
  */
547
571
  this.parseStep = new ParseStep();
572
+ this.modelAnnotationStep = new ModelAnnotationStep(this.parseStep);
548
573
  this.metadataStep = new MetadataStep(this.parseStep);
549
574
  this.completionsStep = new CompletionsStep(this.parseStep);
550
575
  this.helpContextStep = new HelpContextStep(this.parseStep);
@@ -703,6 +728,9 @@ class MalloyTranslation {
703
728
  metadata() {
704
729
  return this.metadataStep.step(this);
705
730
  }
731
+ modelAnnotation(extendingModel) {
732
+ return this.modelAnnotationStep.step(this, extendingModel);
733
+ }
706
734
  completions(position) {
707
735
  return this.completionsStep.step(this, position);
708
736
  }
@@ -0,0 +1,5 @@
1
+ import { CommonTokenStream } from 'antlr4ts';
2
+ import { MalloyTranslation } from '../parse-malloy';
3
+ import { Annotation } from '../../model/malloy_types';
4
+ import { MalloyParseInfo } from '../malloy-parse-info';
5
+ export declare function walkForModelAnnotation(forParse: MalloyTranslation, tokens: CommonTokenStream, parseInfo: MalloyParseInfo): Annotation;
@@ -0,0 +1,60 @@
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.walkForModelAnnotation = void 0;
26
+ const ParseTreeWalker_1 = require("antlr4ts/tree/ParseTreeWalker");
27
+ class ModelAnnotationWalker {
28
+ constructor(translator, tokens, parseInfo) {
29
+ this.translator = translator;
30
+ this.tokens = tokens;
31
+ this.parseInfo = parseInfo;
32
+ this.notes = [];
33
+ }
34
+ getLocation(cx) {
35
+ return {
36
+ url: this.parseInfo.sourceURL,
37
+ range: this.parseInfo.rangeFromContext(cx),
38
+ };
39
+ }
40
+ enterDocAnnotations(pcx) {
41
+ const allNotes = pcx.DOC_ANNOTATION().map(note => {
42
+ return {
43
+ text: note.text,
44
+ at: this.getLocation(pcx),
45
+ };
46
+ });
47
+ this.notes.push(...allNotes);
48
+ }
49
+ get annotation() {
50
+ return { notes: this.notes };
51
+ }
52
+ }
53
+ function walkForModelAnnotation(forParse, tokens, parseInfo) {
54
+ const finder = new ModelAnnotationWalker(forParse, tokens, parseInfo);
55
+ const listener = finder;
56
+ ParseTreeWalker_1.ParseTreeWalker.DEFAULT.walk(listener, parseInfo.root);
57
+ return finder.annotation;
58
+ }
59
+ exports.walkForModelAnnotation = walkForModelAnnotation;
60
+ //# sourceMappingURL=model-annotation-walker.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
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
+ const test_translator_1 = require("./test-translator");
26
+ test('model annotations can be retrieved', () => {
27
+ var _a, _b;
28
+ const src = (0, test_translator_1.markSource) `${'## foo'}`;
29
+ const doc = new test_translator_1.TestTranslator(src.code);
30
+ const { modelAnnotation } = doc.modelAnnotation();
31
+ expect((_a = modelAnnotation === null || modelAnnotation === void 0 ? void 0 : modelAnnotation.notes) === null || _a === void 0 ? void 0 : _a.length).toBe(1);
32
+ const notes = (_b = modelAnnotation === null || modelAnnotation === void 0 ? void 0 : modelAnnotation.notes) !== null && _b !== void 0 ? _b : [];
33
+ expect(notes[0].text).toBe('## foo');
34
+ expect(notes[0].at).toMatchObject(src.locations[0]);
35
+ });
36
+ test('does not explode if bad parse', () => {
37
+ const src = (0, test_translator_1.markSource) `
38
+ ${'## foo'}
39
+ asd afsjei ; duavby {{}}}
40
+ `;
41
+ const doc = new test_translator_1.TestTranslator(src.code);
42
+ const response = doc.modelAnnotation();
43
+ expect(response.modelAnnotation).toBe(undefined);
44
+ expect(response.final).toBe(true);
45
+ });
46
+ //# sourceMappingURL=model-annotation-walker.spec.js.map
@@ -187,6 +187,26 @@ describe('query:', () => {
187
187
  }
188
188
  `).toTranslate();
189
189
  });
190
+ test('exclude output checking survives refinement', () => {
191
+ // This was https://github.com/malloydata/malloy/issues/1474
192
+ const nestExclude = (0, test_translator_1.model) `
193
+ source: flights is a extend {
194
+ dimension: carrier is astr, destination is astr
195
+ measure: flight_count is count()
196
+ view: by_dest is {
197
+ group_by: destination
198
+ aggregate: flight_count
199
+ }
200
+ }
201
+ run: flights -> {
202
+ group_by: carrier
203
+ nest: broken is by_dest + {
204
+ top: 5
205
+ aggregate: flights_to_dest_all_carriers is exclude(flight_count, carrier)
206
+ }
207
+ }`;
208
+ expect(nestExclude).toTranslate();
209
+ });
190
210
  });
191
211
  describe('query operation typechecking', () => {
192
212
  describe('field declarations', () => {
@@ -1,4 +1,4 @@
1
- import { ModelDef, Query, SQLBlockSource, SQLBlockStructDef } from '../model/malloy_types';
1
+ import { Annotation, ModelDef, Query, SQLBlockSource, SQLBlockStructDef } from '../model/malloy_types';
2
2
  import { MalloyElement } from './ast';
3
3
  import { LogMessage } from './parse-log';
4
4
  import { DocumentSymbol } from './parse-tree-walkers/document-symbol-walker';
@@ -43,6 +43,10 @@ interface Metadata extends NeededData, ProblemResponse, FinalResponse {
43
43
  highlights: DocumentHighlight[];
44
44
  }
45
45
  export type MetadataResponse = Partial<Metadata>;
46
+ interface ModelAnnotationData extends NeededData, ProblemResponse, FinalResponse {
47
+ modelAnnotation: Annotation;
48
+ }
49
+ export type ModelAnnotationResponse = Partial<ModelAnnotationData>;
46
50
  interface Completions extends NeededData, ProblemResponse, FinalResponse {
47
51
  completions: DocumentCompletion[];
48
52
  }
package/dist/malloy.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { RunSQLOptions } from './run_sql_options';
3
3
  import { DocumentCompletion as DocumentCompletionDefinition, DocumentHighlight as DocumentHighlightDefinition, DocumentSymbol as DocumentSymbolDefinition, LogMessage, MalloyTranslator } from './lang';
4
4
  import { DocumentHelpContext } from './lang/parse-tree-walkers/document-help-context-walker';
5
- import { CompiledQuery, DocumentLocation, DocumentReference, FieldBooleanDef, FieldDateDef, FieldJSONDef, FieldNumberDef, FieldStringDef, FieldTimestampDef, FieldTypeDef, FilterExpression, Query as InternalQuery, ModelDef, DocumentPosition as ModelDocumentPosition, NamedQuery, QueryData, QueryDataRow, QueryResult, SQLBlock, SQLBlockStructDef, SearchIndexResult, SearchValueMapResult, StructDef, TurtleDef, FieldUnsupportedDef, QueryRunStats, ImportLocation } from './model';
5
+ import { CompiledQuery, DocumentLocation, DocumentReference, FieldBooleanDef, FieldDateDef, FieldJSONDef, FieldNumberDef, FieldStringDef, FieldTimestampDef, FieldTypeDef, FilterExpression, Query as InternalQuery, ModelDef, DocumentPosition as ModelDocumentPosition, NamedQuery, QueryData, QueryDataRow, QueryResult, SQLBlock, SQLBlockStructDef, SearchIndexResult, SearchValueMapResult, StructDef, TurtleDef, FieldUnsupportedDef, QueryRunStats, ImportLocation, Annotation } from './model';
6
6
  import { Connection, InfoConnection, LookupConnection, ModelString, ModelURL, QueryString, QueryURL, URLReader } from './runtime_types';
7
7
  import { Tag, TagParse, TagParseSpec, Taggable } from './tags';
8
8
  export interface Loggable {
@@ -425,6 +425,8 @@ export declare class PreparedResult implements Taggable {
425
425
  constructor(query: CompiledQuery, modelDef: ModelDef);
426
426
  tagParse(spec?: TagParseSpec): TagParse;
427
427
  getTaglines(prefix?: RegExp): string[];
428
+ get annotation(): Annotation | undefined;
429
+ get modelAnnotation(): Annotation | undefined;
428
430
  /**
429
431
  * @return The name of the connection this query should be run against.
430
432
  */
package/dist/malloy.js CHANGED
@@ -129,6 +129,7 @@ class Malloy {
129
129
  }
130
130
  }
131
131
  }
132
+ const { modelAnnotation } = translator.modelAnnotation(model === null || model === void 0 ? void 0 : model._modelDef);
132
133
  if (result.tables) {
133
134
  // collect tables by connection name since there may be multiple connections
134
135
  const tablesByConnection = new Map();
@@ -151,6 +152,7 @@ class Malloy {
151
152
  // the translator runs into an infinite loop fetching tables.
152
153
  const { schemas: tables, errors } = await connection.fetchSchemaForTables(tablePathByKey, {
153
154
  refreshTimestamp,
155
+ modelAnnotation,
154
156
  });
155
157
  translator.update({ tables, errors: { tables: errors } });
156
158
  }
@@ -175,6 +177,7 @@ class Malloy {
175
177
  const expanded = Malloy.compileSQLBlock(result.partialModel, toCompile);
176
178
  const resolved = await conn.fetchSchemaForSQLBlock(expanded, {
177
179
  refreshTimestamp,
180
+ modelAnnotation,
178
181
  });
179
182
  if (resolved.error) {
180
183
  translator.update({
@@ -747,6 +750,12 @@ class PreparedResult {
747
750
  getTaglines(prefix) {
748
751
  return tags_1.Tag.annotationToTaglines(this.inner.annotation, prefix);
749
752
  }
753
+ get annotation() {
754
+ return this.inner.annotation;
755
+ }
756
+ get modelAnnotation() {
757
+ return this.modelDef.annotation;
758
+ }
750
759
  /**
751
760
  * @return The name of the connection this query should be run against.
752
761
  */
@@ -2033,12 +2042,18 @@ class QueryMaterializer extends FluentState {
2033
2042
  async run(options) {
2034
2043
  const connections = this.runtime.connections;
2035
2044
  const preparedResult = await this.getPreparedResult();
2036
- return Malloy.run({ connections, preparedResult, options });
2045
+ const finalOptions = runSQLOptionsWithAnnotations(preparedResult, options);
2046
+ return Malloy.run({ connections, preparedResult, options: finalOptions });
2037
2047
  }
2038
2048
  async *runStream(options) {
2039
2049
  const preparedResult = await this.getPreparedResult();
2040
2050
  const connections = this.runtime.connections;
2041
- const stream = Malloy.runStream({ connections, preparedResult, options });
2051
+ const finalOptions = runSQLOptionsWithAnnotations(preparedResult, options);
2052
+ const stream = Malloy.runStream({
2053
+ connections,
2054
+ preparedResult,
2055
+ options: finalOptions,
2056
+ });
2042
2057
  for await (const row of stream) {
2043
2058
  yield row;
2044
2059
  }
@@ -2090,6 +2105,13 @@ class QueryMaterializer extends FluentState {
2090
2105
  }
2091
2106
  }
2092
2107
  exports.QueryMaterializer = QueryMaterializer;
2108
+ function runSQLOptionsWithAnnotations(preparedResult, givenOptions) {
2109
+ return {
2110
+ queryAnnotation: preparedResult.annotation,
2111
+ modelAnnotation: preparedResult.modelAnnotation,
2112
+ ...givenOptions,
2113
+ };
2114
+ }
2093
2115
  /**
2094
2116
  * An object representing the task of loading a `PreparedResult`, capable of
2095
2117
  * materializing the prepared result (via `getPreparedResult()`) or extending the task run
@@ -2104,12 +2126,22 @@ class PreparedResultMaterializer extends FluentState {
2104
2126
  async run(options) {
2105
2127
  const preparedResult = await this.getPreparedResult();
2106
2128
  const connections = this.runtime.connections;
2107
- return Malloy.run({ connections, preparedResult, options });
2129
+ const finalOptions = runSQLOptionsWithAnnotations(preparedResult, options);
2130
+ return Malloy.run({
2131
+ connections,
2132
+ preparedResult,
2133
+ options: finalOptions,
2134
+ });
2108
2135
  }
2109
2136
  async *runStream(options) {
2110
2137
  const preparedResult = await this.getPreparedResult();
2111
2138
  const connections = this.runtime.connections;
2112
- const stream = Malloy.runStream({ connections, preparedResult, options });
2139
+ const finalOptions = runSQLOptionsWithAnnotations(preparedResult, options);
2140
+ const stream = Malloy.runStream({
2141
+ connections,
2142
+ preparedResult,
2143
+ options: finalOptions,
2144
+ });
2113
2145
  for await (const row of stream) {
2114
2146
  yield row;
2115
2147
  }
@@ -1,4 +1,7 @@
1
+ import { Annotation } from './model/malloy_types';
1
2
  export interface RunSQLOptions {
2
3
  rowLimit?: number;
3
4
  abortSignal?: AbortSignal;
5
+ modelAnnotation?: Annotation;
6
+ queryAnnotation?: Annotation;
4
7
  }
@@ -1,5 +1,5 @@
1
1
  import { RunSQLOptions } from './run_sql_options';
2
- import { MalloyQueryData, QueryDataRow, QueryRunStats, SQLBlock, StructDef } from './model/malloy_types';
2
+ import { Annotation, MalloyQueryData, QueryDataRow, QueryRunStats, SQLBlock, StructDef } from './model/malloy_types';
3
3
  import { Dialect } from './dialect';
4
4
  /**
5
5
  * The contents of a Malloy query document.
@@ -34,6 +34,7 @@ export interface URLReader {
34
34
  */
35
35
  export interface FetchSchemaOptions {
36
36
  refreshTimestamp?: number;
37
+ modelAnnotation?: Annotation;
37
38
  }
38
39
  /**
39
40
  * An object capable of reading schemas for given table names.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/malloy",
3
- "version": "0.0.104-dev231116200719",
3
+ "version": "0.0.104-dev231117214047",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",