@malloydata/malloy 0.0.86-dev230922233440 → 0.0.86-dev230927172239
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/field-space/reference-field.js +1 -1
- package/dist/lang/malloy-to-ast.js +6 -0
- package/dist/lang/test/annotation.spec.js +26 -0
- package/dist/lang/test/parse.spec.js +3 -3
- package/dist/lang/test/query.spec.js +74 -72
- package/dist/lang/test/source.spec.js +15 -8
- package/package.json +1 -1
|
@@ -84,7 +84,7 @@ class ReferenceField extends space_field_1.SpaceField {
|
|
|
84
84
|
// and annotate the expression.
|
|
85
85
|
if ((0, malloy_types_1.isAtomicFieldType)(origFd.type)) {
|
|
86
86
|
const newField = {
|
|
87
|
-
name: this.fieldRef.list[-1].refString,
|
|
87
|
+
name: this.fieldRef.list[this.fieldRef.list.length - 1].refString,
|
|
88
88
|
type: origFd.type,
|
|
89
89
|
e: [{ type: 'field', path }],
|
|
90
90
|
annotation,
|
|
@@ -598,6 +598,9 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
|
598
598
|
const queryDefs = this.visitSubQueryDefList(pcx.subQueryDefList());
|
|
599
599
|
const blockNotes = this.getNotes(pcx.tags());
|
|
600
600
|
queryDefs.extendNote({ blockNotes });
|
|
601
|
+
if (this.m4WarningsEnabled() && pcx.QUERY()) {
|
|
602
|
+
this.contextError(pcx, 'Use view: inside of a source instead of query:', 'warn');
|
|
603
|
+
}
|
|
601
604
|
return queryDefs;
|
|
602
605
|
}
|
|
603
606
|
visitDefExplorePrimaryKey(pcx) {
|
|
@@ -817,6 +820,9 @@ class MalloyToAST extends AbstractParseTreeVisitor_1.AbstractParseTreeVisitor {
|
|
|
817
820
|
}
|
|
818
821
|
buildPipelineFromName(pipe, pipeCx) {
|
|
819
822
|
const firstCx = pipeCx.firstSegment();
|
|
823
|
+
if (this.m4WarningsEnabled() && firstCx.ARROW()) {
|
|
824
|
+
this.contextError(firstCx, "Leading '->' in a view or nest definition is no longer needed.", 'warn');
|
|
825
|
+
}
|
|
820
826
|
const nameCx = firstCx.exploreQueryName();
|
|
821
827
|
if (nameCx) {
|
|
822
828
|
pipe.turtleName = this.getFieldName(nameCx);
|
|
@@ -601,5 +601,31 @@ describe('query operation annotations', () => {
|
|
|
601
601
|
expect(note_b === null || note_b === void 0 ? void 0 : note_b.annotation).matchesAnnotation({ inherits: defaultTags });
|
|
602
602
|
}
|
|
603
603
|
});
|
|
604
|
+
test('annotations preserved from path references', () => {
|
|
605
|
+
const m = (0, test_translator_1.model) `
|
|
606
|
+
run: a -> {
|
|
607
|
+
extend: {
|
|
608
|
+
join_one: x is
|
|
609
|
+
a extend {
|
|
610
|
+
# blockNote
|
|
611
|
+
dimension:
|
|
612
|
+
# note
|
|
613
|
+
xdim
|
|
614
|
+
# b4-is
|
|
615
|
+
is
|
|
616
|
+
# after-is
|
|
617
|
+
1
|
|
618
|
+
} on x.ai = ai
|
|
619
|
+
}
|
|
620
|
+
group_by: x.xdim
|
|
621
|
+
}`;
|
|
622
|
+
expect(m).toTranslate();
|
|
623
|
+
const foundYou = m.translator.getQuery(0);
|
|
624
|
+
expect(foundYou).toBeDefined();
|
|
625
|
+
if (foundYou) {
|
|
626
|
+
const note_b = (0, test_translator_1.getFieldDef)(foundYou.pipeline[0], 'xdim');
|
|
627
|
+
expect(note_b === null || note_b === void 0 ? void 0 : note_b.annotation).matchesAnnotation({ inherits: defaultTags });
|
|
628
|
+
}
|
|
629
|
+
});
|
|
604
630
|
});
|
|
605
631
|
//# sourceMappingURL=annotation.spec.js.map
|
|
@@ -797,7 +797,7 @@ describe('extend and refine', () => {
|
|
|
797
797
|
test('implicit refine in nest', () => {
|
|
798
798
|
expect(`##! m4warnings
|
|
799
799
|
source: c is a extend {
|
|
800
|
-
|
|
800
|
+
view: x is { select: * }
|
|
801
801
|
}
|
|
802
802
|
|
|
803
803
|
run: c -> {
|
|
@@ -807,8 +807,8 @@ describe('extend and refine', () => {
|
|
|
807
807
|
test('implicit refine in turtle works', () => {
|
|
808
808
|
expect(`##! m4warnings
|
|
809
809
|
source: c is a extend {
|
|
810
|
-
|
|
811
|
-
|
|
810
|
+
view: x is { select: * }
|
|
811
|
+
view: y is x { limit: 1 }
|
|
812
812
|
}`).toTranslateWithWarnings('Implicit query refinement is deprecated, use the `refine` operator.');
|
|
813
813
|
});
|
|
814
814
|
test('implicit query refinement', () => {
|
|
@@ -26,52 +26,53 @@ const test_translator_1 = require("./test-translator");
|
|
|
26
26
|
require("./parse-expects");
|
|
27
27
|
const model_1 = require("../../model");
|
|
28
28
|
describe('query:', () => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
describe('basic query syntax', () => {
|
|
30
|
+
test('anonymous query', () => {
|
|
31
|
+
expect((0, test_translator_1.markSource) `query: ${"table('aTable') -> { group_by: astr }"}`).toTranslate();
|
|
32
|
+
});
|
|
33
|
+
test('anonymous query', () => {
|
|
34
|
+
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
34
35
|
query: ${"conn.table('aTable') -> { group_by: astr }"}`).toTranslateWithWarnings('Anonymous `query:` statements are deprecated, use `run:` instead');
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
});
|
|
37
|
+
test('run query', () => expect("run: table('aTable') -> { group_by: astr }").toTranslate());
|
|
38
|
+
test('run query ref', () => expect(`
|
|
38
39
|
query: foo is table('aTable') -> { group_by: astr }
|
|
39
40
|
run: foo
|
|
40
41
|
`).toTranslate());
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
test('query', () => expect("query: name is table('aTable') -> { group_by: astr }").toTranslate());
|
|
43
|
+
test('query', () => {
|
|
44
|
+
expect("query: name is table('aTable') -> { group_by: astr }").toTranslate();
|
|
45
|
+
});
|
|
46
|
+
test('query from query', () => {
|
|
47
|
+
expect(`
|
|
47
48
|
query: q1 is ab->{ group_by: astr limit: 10 }
|
|
48
49
|
query: q2 is ->q1
|
|
49
50
|
`).toTranslate();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
});
|
|
52
|
+
test('query with refinements from query', () => {
|
|
53
|
+
expect(`
|
|
53
54
|
query: q1 is ab->{ group_by: astr limit: 10 }
|
|
54
55
|
query: q2 is ->q1 { aggregate: acount }
|
|
55
56
|
`).toTranslate();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
});
|
|
58
|
+
test('chained query operations', () => {
|
|
59
|
+
expect(`
|
|
59
60
|
query: ab
|
|
60
61
|
-> { group_by: astr; aggregate: acount }
|
|
61
62
|
-> { top: 5; where: astr ~ 'a%' group_by: astr }
|
|
62
63
|
`).toTranslate();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
});
|
|
65
|
+
test('from(query) refined into query', () => {
|
|
66
|
+
expect('query: from(ab -> {group_by: astr}) { dimension: bigstr is upper(astr) } -> { group_by: bigstr }').toTranslate();
|
|
67
|
+
});
|
|
68
|
+
test('query with shortcut filtered turtle', () => {
|
|
69
|
+
expect("query: allA is ab -> aturtle {? astr ~ 'a%' }").toTranslate();
|
|
70
|
+
});
|
|
71
|
+
test('query with filtered turtle', () => {
|
|
72
|
+
expect("query: allA is ab -> aturtle { where: astr ~ 'a%' }").toTranslate();
|
|
73
|
+
});
|
|
74
|
+
test('nest: in group_by:', () => {
|
|
75
|
+
expect(`
|
|
75
76
|
query: ab -> {
|
|
76
77
|
group_by: astr;
|
|
77
78
|
nest: nested_count is {
|
|
@@ -79,45 +80,45 @@ describe('query:', () => {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
`).toTranslate();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
});
|
|
84
|
+
test('reduce pipe project', () => {
|
|
85
|
+
expect(`
|
|
85
86
|
query: a -> { aggregate: f is count() } -> { project: f2 is f + 1 }
|
|
86
87
|
`).toTranslate();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
});
|
|
89
|
+
test('refine and extend query', () => {
|
|
90
|
+
expect(`
|
|
90
91
|
query: a_by_str is a -> { group_by: astr }
|
|
91
92
|
query: -> a_by_str { aggregate: str_count is count() }
|
|
92
93
|
`).toTranslate();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
});
|
|
95
|
+
test('query refinement preserves original', () => {
|
|
96
|
+
const x = new test_translator_1.TestTranslator(`
|
|
96
97
|
query: q is a -> { aggregate: acount is count() }
|
|
97
98
|
query: nq is -> q + { group_by: astr }
|
|
98
99
|
`);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
expect(x).toTranslate();
|
|
101
|
+
const q = x.getQuery('q');
|
|
102
|
+
expect(q).toBeDefined();
|
|
103
|
+
if (q) {
|
|
104
|
+
const qFields = q.pipeline[0].fields;
|
|
105
|
+
expect(qFields.length).toBe(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
test('query composition preserves original', () => {
|
|
109
|
+
const x = new test_translator_1.TestTranslator(`
|
|
109
110
|
query: q is ab -> { aggregate: acount }
|
|
110
111
|
query: nq is -> q -> { project: * }
|
|
111
112
|
`);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
113
|
+
expect(x).toTranslate();
|
|
114
|
+
const q = x.getQuery('q');
|
|
115
|
+
expect(q).toBeDefined();
|
|
116
|
+
if (q) {
|
|
117
|
+
expect(q.pipeline.length).toBe(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
test('all ungroup with args', () => {
|
|
121
|
+
expect(`
|
|
121
122
|
query: a -> {
|
|
122
123
|
group_by: astr
|
|
123
124
|
nest: by_int is {
|
|
@@ -126,9 +127,9 @@ describe('query:', () => {
|
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
`).toTranslate();
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
});
|
|
131
|
+
test('all ungroup checks args', () => {
|
|
132
|
+
expect(`
|
|
132
133
|
query: a -> {
|
|
133
134
|
group_by: astr
|
|
134
135
|
nest: by_int is {
|
|
@@ -137,9 +138,9 @@ describe('query:', () => {
|
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
`).translationToFailWith("all() 'afloat' is missing from query output");
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
});
|
|
142
|
+
test('exclude ungroup with args', () => {
|
|
143
|
+
expect(`
|
|
143
144
|
query: a -> {
|
|
144
145
|
group_by: aa is 'a'
|
|
145
146
|
nest: by_b is {
|
|
@@ -151,9 +152,9 @@ describe('query:', () => {
|
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
154
|
`).toTranslate();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
});
|
|
156
|
+
test('exclude ungroup checks args', () => {
|
|
157
|
+
expect(`
|
|
157
158
|
query: a -> {
|
|
158
159
|
group_by: aa is 'a'
|
|
159
160
|
nest: by_b is {
|
|
@@ -165,9 +166,9 @@ describe('query:', () => {
|
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
`).translationToFailWith("exclude() 'aaa' is missing from query output");
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
});
|
|
170
|
+
test('exclude problem revealed by production models', () => {
|
|
171
|
+
expect(`
|
|
171
172
|
source: carriers is table('malloytest.carriers') {
|
|
172
173
|
primary_key: code
|
|
173
174
|
}
|
|
@@ -185,6 +186,7 @@ describe('query:', () => {
|
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
`).toTranslate();
|
|
189
|
+
});
|
|
188
190
|
});
|
|
189
191
|
describe('query operation typechecking', () => {
|
|
190
192
|
describe('field declarations', () => {
|
|
@@ -112,7 +112,7 @@ describe('source:', () => {
|
|
|
112
112
|
test('where clause can use the join namespace in source refined query', () => {
|
|
113
113
|
expect(`
|
|
114
114
|
source: flights is table('malloytest.flights') + {
|
|
115
|
-
|
|
115
|
+
view: boo is {
|
|
116
116
|
join_one: carriers is table('malloytest.carriers') on carrier = carriers.code
|
|
117
117
|
where: carriers.code = 'WN' | 'AA'
|
|
118
118
|
group_by: carriers.nickname
|
|
@@ -198,15 +198,22 @@ describe('source:', () => {
|
|
|
198
198
|
expect('source: c is a { except: astr, af }').toTranslate();
|
|
199
199
|
});
|
|
200
200
|
test('turtle in a source can be called view', () => {
|
|
201
|
-
expect('source: c is a {view: q is { group_by: astr } }').toTranslate();
|
|
201
|
+
expect('source: c is a extend {view: q is { group_by: astr } }').toTranslate();
|
|
202
202
|
});
|
|
203
|
-
test('turtle in source can be called query', () => {
|
|
204
|
-
expect(
|
|
203
|
+
test('turtle in source can be called query with m4 warning', () => {
|
|
204
|
+
expect(`##! m4warnings
|
|
205
|
+
source: c is a extend {query: q is { group_by: astr } }
|
|
206
|
+
`).toTranslateWithWarnings('Use view: inside of a source instead of query:');
|
|
207
|
+
});
|
|
208
|
+
test('turtle in source m4 warning on arrow', () => {
|
|
209
|
+
expect(`##! m4warnings
|
|
210
|
+
source: c is a extend {view: q is -> { group_by: astr } }
|
|
211
|
+
`).toTranslateWithWarnings("Leading '->' in a view or nest definition is no longer needed.");
|
|
205
212
|
});
|
|
206
213
|
test('refined explore-query', () => {
|
|
207
214
|
expect(`
|
|
208
215
|
source: abNew is ab {
|
|
209
|
-
|
|
216
|
+
view: for1 is aturtle {? ai = 1 }
|
|
210
217
|
}
|
|
211
218
|
`).toTranslate();
|
|
212
219
|
});
|
|
@@ -214,14 +221,14 @@ describe('source:', () => {
|
|
|
214
221
|
expect(`
|
|
215
222
|
##! m4warnings
|
|
216
223
|
source: abNew is ab extend {
|
|
217
|
-
|
|
224
|
+
view: for1 is aturtle refine {? ai = 1 }
|
|
218
225
|
}
|
|
219
226
|
`).toTranslateWithWarnings('Filter shortcut `{? condition }` is deprecated; use `{ where: condition } instead');
|
|
220
227
|
});
|
|
221
228
|
test('chained explore-query', () => {
|
|
222
229
|
expect(`
|
|
223
230
|
source: c is a {
|
|
224
|
-
|
|
231
|
+
view: chain is {
|
|
225
232
|
group_by: astr
|
|
226
233
|
} -> {
|
|
227
234
|
top: 10; order_by: astr
|
|
@@ -233,7 +240,7 @@ describe('source:', () => {
|
|
|
233
240
|
test('multiple explore-query', () => {
|
|
234
241
|
expect(`
|
|
235
242
|
source: abNew is ab {
|
|
236
|
-
|
|
243
|
+
view:
|
|
237
244
|
q1 is { group_by: astr },
|
|
238
245
|
q2 is { group_by: ai }
|
|
239
246
|
}
|