@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.
- package/dist/lang/ast/elements/pipeline-desc.d.ts +13 -2
- package/dist/lang/ast/elements/pipeline-desc.js +15 -2
- package/dist/lang/ast/expressions/constant-sub-expression.js +0 -3
- package/dist/lang/ast/expressions/expr-ungroup.js +24 -19
- package/dist/lang/ast/field-space/dynamic-space.d.ts +0 -1
- package/dist/lang/ast/field-space/dynamic-space.js +0 -12
- package/dist/lang/ast/field-space/query-input-space.d.ts +0 -1
- package/dist/lang/ast/field-space/query-spaces.d.ts +1 -7
- package/dist/lang/ast/field-space/query-spaces.js +0 -27
- package/dist/lang/ast/field-space/static-space.d.ts +0 -1
- package/dist/lang/ast/field-space/static-space.js +0 -19
- package/dist/lang/ast/query-items/field-declaration.d.ts +0 -1
- package/dist/lang/ast/query-items/field-declaration.js +0 -3
- package/dist/lang/ast/query-properties/nest.d.ts +6 -4
- package/dist/lang/ast/query-properties/nest.js +16 -14
- package/dist/lang/ast/query-properties/qop-desc.d.ts +2 -2
- package/dist/lang/ast/query-properties/qop-desc.js +3 -3
- package/dist/lang/ast/query-properties/refinements.d.ts +10 -4
- package/dist/lang/ast/query-properties/refinements.js +7 -7
- package/dist/lang/ast/types/field-space.d.ts +0 -1
- package/dist/lang/parse-malloy.d.ts +9 -1
- package/dist/lang/parse-malloy.js +28 -0
- package/dist/lang/parse-tree-walkers/model-annotation-walker.d.ts +5 -0
- package/dist/lang/parse-tree-walkers/model-annotation-walker.js +60 -0
- package/dist/lang/test/model-annotation-walker.spec.d.ts +1 -0
- package/dist/lang/test/model-annotation-walker.spec.js +46 -0
- package/dist/lang/test/query.spec.js +20 -0
- package/dist/lang/translate-response.d.ts +5 -1
- package/dist/malloy.d.ts +3 -1
- package/dist/malloy.js +36 -4
- package/dist/run_sql_options.d.ts +3 -0
- package/dist/runtime_types.d.ts +2 -1
- 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 {
|
|
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
|
-
|
|
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.
|
|
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
|
}
|
|
@@ -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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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;
|
|
@@ -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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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 {
|
|
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,
|
|
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,
|
|
89
|
+
getOp(inputFS, isNestIn) {
|
|
90
90
|
const build = this.getBuilder(inputFS);
|
|
91
|
-
if (
|
|
92
|
-
build.
|
|
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
|
-
|
|
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,
|
|
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,
|
|
83
|
+
getOp(inputFS, refineTo) {
|
|
84
84
|
var _a, _b;
|
|
85
|
-
const 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,
|
|
158
|
+
getOp(inputFS, isNestIn, qOpDesc, refineThis) {
|
|
159
159
|
qOpDesc.refineFrom(refineThis);
|
|
160
|
-
return qOpDesc.getOp(inputFS,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
}
|
package/dist/runtime_types.d.ts
CHANGED
|
@@ -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.
|