@malloydata/malloy 0.0.88-dev231002231014 → 0.0.88-dev231003001139
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/dialect/dialect_map.js +1 -0
- package/dist/dialect/functions/util.d.ts +1 -0
- package/dist/lang/ast/elements/define-query.d.ts +3 -3
- package/dist/lang/ast/elements/define-query.js +9 -4
- package/dist/lang/ast/elements/define-source.d.ts +3 -3
- package/dist/lang/ast/elements/define-source.js +12 -4
- package/dist/lang/ast/elements/pipeline-desc.d.ts +1 -0
- package/dist/lang/ast/elements/pipeline-desc.js +3 -0
- package/dist/lang/ast/elements/source-query-nodes.d.ts +72 -0
- package/dist/lang/ast/elements/source-query-nodes.js +368 -0
- package/dist/lang/ast/elements/source-query.d.ts +11 -0
- package/dist/lang/ast/{query-elements/run-query.js → elements/source-query.js} +32 -21
- package/dist/lang/ast/index.d.ts +2 -2
- package/dist/lang/ast/index.js +2 -2
- package/dist/lang/ast/query-elements/anonymous-query.d.ts +3 -3
- package/dist/lang/ast/query-elements/anonymous-query.js +15 -8
- package/dist/lang/ast/query-elements/existing-query.js +1 -1
- package/dist/lang/ast/query-items/field-references.d.ts +4 -0
- package/dist/lang/ast/query-items/field-references.js +11 -1
- package/dist/lang/ast/query-items/typecheck_utils.js +5 -5
- package/dist/lang/ast/query-properties/joins.d.ts +7 -5
- package/dist/lang/ast/query-properties/joins.js +22 -8
- package/dist/lang/ast/sources/sql-source.js +5 -0
- package/dist/lang/ast/sql-elements/sql-string.d.ts +2 -2
- package/dist/lang/ast/sql-elements/sql-string.js +19 -9
- package/dist/lang/ast/types/malloy-element.d.ts +3 -1
- package/dist/lang/ast/types/malloy-element.js +16 -5
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +179 -184
- package/dist/lang/lib/Malloy/MalloyParser.js +3141 -2928
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +147 -199
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +88 -120
- package/dist/lang/malloy-to-ast.d.ts +16 -15
- package/dist/lang/malloy-to-ast.js +147 -141
- package/dist/lang/parse-tree-walkers/document-symbol-walker.js +1 -1
- package/dist/lang/parse-utils.js +2 -2
- package/dist/lang/test/annotation.spec.js +35 -46
- package/dist/lang/test/document-symbol-walker.spec.js +2 -2
- package/dist/lang/test/expressions.spec.js +16 -16
- package/dist/lang/test/imports.spec.js +10 -8
- package/dist/lang/test/literals.spec.js +4 -4
- package/dist/lang/test/locations.spec.js +82 -80
- package/dist/lang/test/parse-expects.js +5 -1
- package/dist/lang/test/parse.spec.js +173 -117
- package/dist/lang/test/query.spec.js +199 -203
- package/dist/lang/test/source.spec.js +54 -45
- package/dist/lang/test/sql-block.spec.js +19 -12
- package/dist/lang/test/test-translator.js +8 -5
- package/dist/malloy.js +2 -2
- package/dist/model/malloy_query.js +3 -0
- package/dist/model/malloy_types.d.ts +1 -0
- package/package.json +1 -2
- package/dist/lang/ast/query-elements/run-query.d.ts +0 -13
- package/dist/lang/ast/sources/named-source-or-query.d.ts +0 -10
- package/dist/lang/ast/sources/named-source-or-query.js +0 -71
|
@@ -27,53 +27,54 @@ require("./parse-expects");
|
|
|
27
27
|
const model_1 = require("../../model");
|
|
28
28
|
describe('query:', () => {
|
|
29
29
|
describe('basic query syntax', () => {
|
|
30
|
-
test('anonymous query', () => {
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
test('anonymous query', () => {
|
|
30
|
+
test('run:anonymous query', () => expect('run: a -> { group_by: astr }').toTranslate());
|
|
31
|
+
test('query:anonymous query m4 warning', () => {
|
|
34
32
|
expect((0, test_translator_1.markSource) `##! m4warnings
|
|
35
|
-
|
|
33
|
+
query: ${'a -> { group_by: astr }'}`).toTranslateWithWarnings('Anonymous `query:` statements are deprecated, use `run:` instead');
|
|
36
34
|
});
|
|
37
|
-
test('
|
|
35
|
+
test('named query:', () => expect('query: aq is a -> { group_by: astr }').toTranslate());
|
|
38
36
|
test('run query ref', () => expect(`
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
query: foo is a -> { group_by: astr }
|
|
38
|
+
run: foo
|
|
41
39
|
`).toTranslate());
|
|
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
40
|
test('query from query', () => {
|
|
47
41
|
expect(`
|
|
48
42
|
query: q1 is ab->{ group_by: astr limit: 10 }
|
|
49
|
-
query: q2 is
|
|
43
|
+
query: q2 is q1
|
|
50
44
|
`).toTranslate();
|
|
51
45
|
});
|
|
52
46
|
test('query with refinements from query', () => {
|
|
53
47
|
expect(`
|
|
54
48
|
query: q1 is ab->{ group_by: astr limit: 10 }
|
|
55
|
-
query: q2 is
|
|
49
|
+
query: q2 is q1 + { aggregate: acount }
|
|
56
50
|
`).toTranslate();
|
|
57
51
|
});
|
|
58
52
|
test('chained query operations', () => {
|
|
59
53
|
expect(`
|
|
60
|
-
|
|
54
|
+
run: ab
|
|
61
55
|
-> { group_by: astr; aggregate: acount }
|
|
62
56
|
-> { top: 5; where: astr ~ 'a%' group_by: astr }
|
|
63
57
|
`).toTranslate();
|
|
64
58
|
});
|
|
65
|
-
test('
|
|
66
|
-
expect(
|
|
59
|
+
test('query output refined into another query pre-m4', () => {
|
|
60
|
+
expect(`
|
|
61
|
+
##! -m4warnings
|
|
62
|
+
run: from(ab -> {group_by: astr}) extend { dimension: bigstr is upper(astr) } -> { group_by: bigstr }
|
|
63
|
+
`).toTranslate();
|
|
64
|
+
});
|
|
65
|
+
test('query output refined into another query', () => {
|
|
66
|
+
expect('run: ab -> {group_by: astr} extend { dimension: bigstr is upper(astr) } -> { group_by: bigstr }').toTranslate();
|
|
67
67
|
});
|
|
68
68
|
test('query with shortcut filtered turtle', () => {
|
|
69
|
-
expect(
|
|
69
|
+
expect(`##! -m4warnings
|
|
70
|
+
query: allA is ab -> aturtle + {? astr ~ 'a%' }`).toTranslate();
|
|
70
71
|
});
|
|
71
72
|
test('query with filtered turtle', () => {
|
|
72
|
-
expect("query: allA is ab -> aturtle { where: astr ~ 'a%' }").toTranslate();
|
|
73
|
+
expect("query: allA is ab -> aturtle + { where: astr ~ 'a%' }").toTranslate();
|
|
73
74
|
});
|
|
74
75
|
test('nest: in group_by:', () => {
|
|
75
76
|
expect(`
|
|
76
|
-
|
|
77
|
+
run: ab -> {
|
|
77
78
|
group_by: astr;
|
|
78
79
|
nest: nested_count is {
|
|
79
80
|
aggregate: acount
|
|
@@ -83,19 +84,19 @@ describe('query:', () => {
|
|
|
83
84
|
});
|
|
84
85
|
test('reduce pipe project', () => {
|
|
85
86
|
expect(`
|
|
86
|
-
|
|
87
|
+
run: a -> { aggregate: f is count() } -> { select: f2 is f + 1 }
|
|
87
88
|
`).toTranslate();
|
|
88
89
|
});
|
|
89
90
|
test('refine and extend query', () => {
|
|
90
91
|
expect(`
|
|
91
92
|
query: a_by_str is a -> { group_by: astr }
|
|
92
|
-
|
|
93
|
+
run: a_by_str + { aggregate: str_count is count() }
|
|
93
94
|
`).toTranslate();
|
|
94
95
|
});
|
|
95
96
|
test('query refinement preserves original', () => {
|
|
96
97
|
const x = new test_translator_1.TestTranslator(`
|
|
97
98
|
query: q is a -> { aggregate: acount is count() }
|
|
98
|
-
query: nq is
|
|
99
|
+
query: nq is q + { group_by: astr }
|
|
99
100
|
`);
|
|
100
101
|
expect(x).toTranslate();
|
|
101
102
|
const q = x.getQuery('q');
|
|
@@ -108,7 +109,7 @@ describe('query:', () => {
|
|
|
108
109
|
test('query composition preserves original', () => {
|
|
109
110
|
const x = new test_translator_1.TestTranslator(`
|
|
110
111
|
query: q is ab -> { aggregate: acount }
|
|
111
|
-
query: nq is
|
|
112
|
+
query: nq is q -> { select: * }
|
|
112
113
|
`);
|
|
113
114
|
expect(x).toTranslate();
|
|
114
115
|
const q = x.getQuery('q');
|
|
@@ -119,7 +120,7 @@ describe('query:', () => {
|
|
|
119
120
|
});
|
|
120
121
|
test('all ungroup with args', () => {
|
|
121
122
|
expect(`
|
|
122
|
-
|
|
123
|
+
run: a -> {
|
|
123
124
|
group_by: astr
|
|
124
125
|
nest: by_int is {
|
|
125
126
|
group_by: ai
|
|
@@ -130,18 +131,17 @@ describe('query:', () => {
|
|
|
130
131
|
});
|
|
131
132
|
test('all ungroup checks args', () => {
|
|
132
133
|
expect(`
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
`).translationToFailWith("all() 'afloat' is missing from query output");
|
|
134
|
+
run: a -> {
|
|
135
|
+
group_by: astr
|
|
136
|
+
nest: by_int is {
|
|
137
|
+
group_by: ai
|
|
138
|
+
aggregate: bi_count is all(count(), afloat)
|
|
139
|
+
}
|
|
140
|
+
}`).translationToFailWith("all() 'afloat' is missing from query output");
|
|
141
141
|
});
|
|
142
142
|
test('exclude ungroup with args', () => {
|
|
143
143
|
expect(`
|
|
144
|
-
|
|
144
|
+
run: a -> {
|
|
145
145
|
group_by: aa is 'a'
|
|
146
146
|
nest: by_b is {
|
|
147
147
|
group_by: bb is 'b'
|
|
@@ -155,7 +155,7 @@ describe('query:', () => {
|
|
|
155
155
|
});
|
|
156
156
|
test('exclude ungroup checks args', () => {
|
|
157
157
|
expect(`
|
|
158
|
-
|
|
158
|
+
run: a -> {
|
|
159
159
|
group_by: aa is 'a'
|
|
160
160
|
nest: by_b is {
|
|
161
161
|
group_by: bb is 'b'
|
|
@@ -169,14 +169,14 @@ describe('query:', () => {
|
|
|
169
169
|
});
|
|
170
170
|
test('exclude problem revealed by production models', () => {
|
|
171
171
|
expect(`
|
|
172
|
-
source: carriers is table('malloytest.carriers') {
|
|
172
|
+
source: carriers is _db_.table('malloytest.carriers') extend {
|
|
173
173
|
primary_key: code
|
|
174
174
|
}
|
|
175
|
-
source: flights is table('malloytest.flights') {
|
|
175
|
+
source: flights is _db_.table('malloytest.flights') extend {
|
|
176
176
|
primary_key: id2
|
|
177
177
|
join_one: carriers with carrier
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
view: carrier_overview is {
|
|
180
180
|
group_by: carrier_name is carriers.nickname
|
|
181
181
|
nest: top_destinations is {
|
|
182
182
|
group_by: destination
|
|
@@ -191,93 +191,94 @@ describe('query:', () => {
|
|
|
191
191
|
describe('query operation typechecking', () => {
|
|
192
192
|
describe('field declarations', () => {
|
|
193
193
|
test('cannot use aggregate in group_by', () => {
|
|
194
|
-
expect('
|
|
194
|
+
expect('run: a -> { group_by: s is count()}').translationToFailWith('Cannot use an aggregate field in a group_by operation, did you mean to use an aggregate operation instead?');
|
|
195
195
|
});
|
|
196
196
|
test('cannot use ungrouped_aggregate in group_by', () => {
|
|
197
|
-
expect('
|
|
197
|
+
expect('run: a -> { group_by: s is all(count())}').translationToFailWith('Cannot use an aggregate field in a group_by operation, did you mean to use an aggregate operation instead?');
|
|
198
198
|
});
|
|
199
199
|
test('cannot use analytic in group_by', () => {
|
|
200
|
-
expect('
|
|
200
|
+
expect('run: a -> { group_by: s is row_number()}').translationToFailWith('Cannot use an analytic field in a group_by operation, did you mean to use a calculate operation instead?');
|
|
201
201
|
});
|
|
202
202
|
test('cannot use aggregate in dimension', () => {
|
|
203
|
-
expect('source: a1 is a { dimension: s is count()}').translationToFailWith('Cannot use an aggregate field in a dimension declaration, did you mean to use a measure declaration instead?');
|
|
203
|
+
expect('source: a1 is a extend { dimension: s is count()}').translationToFailWith('Cannot use an aggregate field in a dimension declaration, did you mean to use a measure declaration instead?');
|
|
204
204
|
});
|
|
205
205
|
test('cannot use ungrouped_aggregate in dimension', () => {
|
|
206
|
-
expect('source: a1 is a { dimension: s is all(count())}').translationToFailWith('Cannot use an aggregate field in a dimension declaration, did you mean to use a measure declaration instead?');
|
|
206
|
+
expect('source: a1 is a extend { dimension: s is all(count())}').translationToFailWith('Cannot use an aggregate field in a dimension declaration, did you mean to use a measure declaration instead?');
|
|
207
207
|
});
|
|
208
208
|
test('cannot use analytic in dimension', () => {
|
|
209
|
-
expect('source: a1 is a { dimension: s is row_number()}').translationToFailWith('Cannot use an analytic field in a dimension declaration');
|
|
209
|
+
expect('source: a1 is a extend { dimension: s is row_number()}').translationToFailWith('Cannot use an analytic field in a dimension declaration');
|
|
210
210
|
});
|
|
211
211
|
test('cannot use scalar in measure', () => {
|
|
212
|
-
expect('source: a1 is a { measure: s is 1}').translationToFailWith('Cannot use a scalar field in a measure declaration, did you mean to use a dimension declaration instead?');
|
|
212
|
+
expect('source: a1 is a extend { measure: s is 1}').translationToFailWith('Cannot use a scalar field in a measure declaration, did you mean to use a dimension declaration instead?');
|
|
213
213
|
});
|
|
214
214
|
test('cannot use analytic in measure', () => {
|
|
215
|
-
expect('source: a1 is a { measure: s is lag(count())}').translationToFailWith('Cannot use an analytic field in a measure declaration');
|
|
215
|
+
expect('source: a1 is a extend { measure: s is lag(count())}').translationToFailWith('Cannot use an analytic field in a measure declaration');
|
|
216
216
|
});
|
|
217
217
|
test('cannot use scalar in aggregate', () => {
|
|
218
|
-
expect('
|
|
218
|
+
expect('run: a -> { aggregate: s is 1}').translationToFailWith('Cannot use a scalar field in an aggregate operation, did you mean to use a group_by or project operation instead?');
|
|
219
219
|
});
|
|
220
220
|
test('cannot use analytic in aggregate', () => {
|
|
221
|
-
expect('
|
|
221
|
+
expect('run: a -> { aggregate: s is lag(count())}').translationToFailWith('Cannot use an analytic field in an aggregate operation, did you mean to use a calculate operation instead?');
|
|
222
222
|
});
|
|
223
223
|
test('cannot use scalar in calculate', () => {
|
|
224
|
-
expect('
|
|
224
|
+
expect('run: a -> { group_by: a is 1; calculate: s is 1 }').translationToFailWith('Cannot use a scalar field in a calculate operation, did you mean to use a group_by or project operation instead?');
|
|
225
225
|
});
|
|
226
226
|
test('cannot use aggregate in calculate', () => {
|
|
227
|
-
expect('
|
|
227
|
+
expect('run: a -> { group_by: a is 1; calculate: s is count() }').translationToFailWith('Cannot use an aggregate field in a calculate operation, did you mean to use an aggregate operation instead?');
|
|
228
228
|
});
|
|
229
229
|
test('cannot use aggregate in project', () => {
|
|
230
|
-
expect('
|
|
230
|
+
expect('run: a -> { select: s is count() }').translationToFailWith('Cannot use an aggregate field in a project operation, did you mean to use an aggregate operation instead?');
|
|
231
231
|
});
|
|
232
232
|
test('cannot use analytic in project', () => {
|
|
233
|
-
expect('
|
|
233
|
+
expect('run: a -> { select: s is row_number() }').translationToFailWith('Cannot use an analytic field in a project operation, did you mean to use a calculate operation instead?');
|
|
234
234
|
});
|
|
235
235
|
test('cannot use analytic in declare', () => {
|
|
236
|
-
expect(
|
|
236
|
+
expect(`##! -m4warnings
|
|
237
|
+
run: a -> { group_by: a is 1; declare: s is row_number() }`).translationToFailWith('Analytic expressions can not be used in a declare block');
|
|
237
238
|
});
|
|
238
239
|
test('cannot use aggregate in index', () => {
|
|
239
|
-
expect('
|
|
240
|
+
expect('run: a extend { measure: acount is count() } -> { index: acount }').translationToFailWith('Cannot use an aggregate field in an index operation');
|
|
240
241
|
});
|
|
241
242
|
test('can use aggregate in except', () => {
|
|
242
243
|
expect(`
|
|
243
|
-
source: b1 is a { measure: acount is count() }
|
|
244
|
-
source: c1 is b1 { except: acount }
|
|
244
|
+
source: b1 is a extend { measure: acount is count() }
|
|
245
|
+
source: c1 is b1 extend { except: acount }
|
|
245
246
|
`).toTranslate();
|
|
246
247
|
});
|
|
247
248
|
});
|
|
248
249
|
describe('field references', () => {
|
|
249
250
|
test('cannot use aggregate in group_by', () => {
|
|
250
|
-
expect('
|
|
251
|
+
expect('run: a -> { extend: {measure: acount is count()} group_by: acount }').translationToFailWith('Cannot use an aggregate field in a group_by operation, did you mean to use an aggregate operation instead?');
|
|
251
252
|
});
|
|
252
253
|
test('cannot use query in group_by', () => {
|
|
253
|
-
expect('
|
|
254
|
+
expect('run: a extend { view: q is { group_by: x is 1 } } -> { group_by: q }').translationToFailWith('Cannot use a view field in a group_by operation, did you mean to use a nest operation instead?');
|
|
254
255
|
});
|
|
255
256
|
test('cannot use scalar in aggregate', () => {
|
|
256
|
-
expect('
|
|
257
|
+
expect('run: a -> { extend: {dimension: aconst is 1} aggregate: aconst }').translationToFailWith('Cannot use a scalar field in an aggregate operation, did you mean to use a group_by or project operation instead?');
|
|
257
258
|
});
|
|
258
259
|
test('cannot use scalar in calculate', () => {
|
|
259
|
-
expect('
|
|
260
|
+
expect('run: a -> { extend: {dimension: aconst is 1} group_by: x is 1; calculate: aconst }').translationToFailWith('Cannot use a scalar field in a calculate operation, did you mean to use a group_by or project operation instead?');
|
|
260
261
|
});
|
|
261
262
|
test('cannot use aggregate in calculate', () => {
|
|
262
|
-
expect('
|
|
263
|
+
expect('run: a -> { extend: {measure: acount is count()} group_by: x is 1; calculate: acount }').translationToFailWith('Cannot use an aggregate field in a calculate operation, did you mean to use an aggregate operation instead?');
|
|
263
264
|
});
|
|
264
265
|
test('cannot use query in project', () => {
|
|
265
|
-
expect('
|
|
266
|
+
expect('run: a extend { view: q is { group_by: x is 1 } } -> { select: q }').translationToFailWith('Cannot use a view field in a project operation, did you mean to use a nest operation instead?');
|
|
266
267
|
});
|
|
267
268
|
test('cannot use query in index', () => {
|
|
268
|
-
expect('
|
|
269
|
+
expect('run: a extend { view: q is { group_by: x is 1 } } -> { index: q }').translationToFailWith('Cannot use a view field in an index operation');
|
|
269
270
|
});
|
|
270
271
|
test('cannot use query in calculate', () => {
|
|
271
|
-
expect('
|
|
272
|
+
expect('run: a extend { view: q is { group_by: x is 1 } } -> { group_by: x is 1; calculate: q }').translationToFailWith('Cannot use a view field in a calculate operation, did you mean to use a nest operation instead?');
|
|
272
273
|
});
|
|
273
274
|
test('cannot use query in aggregate', () => {
|
|
274
|
-
expect('
|
|
275
|
+
expect('run: a extend { view: q is { group_by: x is 1 } } -> { aggregate: q }').translationToFailWith('Cannot use a view field in an aggregate operation, did you mean to use a nest operation instead?');
|
|
275
276
|
});
|
|
276
277
|
test('cannot use aggregate in calculate, preserved over refinement', () => {
|
|
277
278
|
expect(`query: a1 is a -> {
|
|
278
279
|
aggregate: c is count()
|
|
279
280
|
}
|
|
280
|
-
|
|
281
|
+
run: a1 + {
|
|
281
282
|
calculate: b is c
|
|
282
283
|
}`).translationToFailWith('Cannot use an aggregate field in a calculate operation, did you mean to use an aggregate operation instead?');
|
|
283
284
|
});
|
|
@@ -285,7 +286,7 @@ describe('query:', () => {
|
|
|
285
286
|
expect(`query: a1 is a -> {
|
|
286
287
|
group_by: c is 1
|
|
287
288
|
}
|
|
288
|
-
|
|
289
|
+
run: a1 + {
|
|
289
290
|
calculate: b is c
|
|
290
291
|
}`).translationToFailWith('Cannot use a scalar field in a calculate operation, did you mean to use a group_by or project operation instead?');
|
|
291
292
|
});
|
|
@@ -294,7 +295,7 @@ describe('query:', () => {
|
|
|
294
295
|
group_by: c is 1
|
|
295
296
|
calculate: c2 is lag(c)
|
|
296
297
|
}
|
|
297
|
-
|
|
298
|
+
run: a1 + {
|
|
298
299
|
group_by: b is c2
|
|
299
300
|
}`).translationToFailWith(
|
|
300
301
|
// c2 is not defined because group_by doesn't know to look in the output space
|
|
@@ -305,7 +306,7 @@ describe('query:', () => {
|
|
|
305
306
|
group_by: c is 1
|
|
306
307
|
calculate: c2 is lag(c)
|
|
307
308
|
}
|
|
308
|
-
|
|
309
|
+
run: a1 + {
|
|
309
310
|
order_by: c2
|
|
310
311
|
}`).translationToFailWith('Illegal order by of analytic field c2');
|
|
311
312
|
});
|
|
@@ -331,7 +332,7 @@ describe('query:', () => {
|
|
|
331
332
|
expect(`query: a1 is a -> {
|
|
332
333
|
group_by: c is 1
|
|
333
334
|
}
|
|
334
|
-
|
|
335
|
+
run: a1 + {
|
|
335
336
|
order_by: c
|
|
336
337
|
}`).toTranslate();
|
|
337
338
|
});
|
|
@@ -339,7 +340,7 @@ describe('query:', () => {
|
|
|
339
340
|
expect(`query: a1 is a -> {
|
|
340
341
|
group_by: c is astr
|
|
341
342
|
}
|
|
342
|
-
|
|
343
|
+
run: a1 + {
|
|
343
344
|
order_by: c
|
|
344
345
|
}`).toTranslate();
|
|
345
346
|
});
|
|
@@ -347,30 +348,30 @@ describe('query:', () => {
|
|
|
347
348
|
});
|
|
348
349
|
describe('function typechecking', () => {
|
|
349
350
|
test('use function correctly', () => {
|
|
350
|
-
expect(`
|
|
351
|
+
expect(`run: a -> {
|
|
351
352
|
group_by: s is concat('a', 'b')
|
|
352
353
|
}`).toTranslate();
|
|
353
354
|
});
|
|
354
355
|
test('function incorrect case', () => {
|
|
355
|
-
expect(`
|
|
356
|
+
expect(`run: a -> {
|
|
356
357
|
group_by: s is CONCAT('a', 'b')
|
|
357
358
|
}`).toTranslateWithWarnings("Case insensitivity for function names is deprecated, use 'concat' instead");
|
|
358
359
|
});
|
|
359
360
|
test('function no matching overload', () => {
|
|
360
|
-
expect(`
|
|
361
|
+
expect(`run: a -> {
|
|
361
362
|
group_by: s is floor('a', 'b')
|
|
362
363
|
}`).translationToFailWith('No matching overload for function floor(string, string)');
|
|
363
364
|
});
|
|
364
365
|
test('unknown function', () => {
|
|
365
|
-
expect(`
|
|
366
|
+
expect(`run: a -> {
|
|
366
367
|
group_by: s is asdfasdf()
|
|
367
368
|
}`).translationToFailWith("Unknown function 'asdfasdf'. Use 'asdfasdf!(...)' to call a SQL function directly.");
|
|
368
369
|
});
|
|
369
370
|
test('can select different overload', () => {
|
|
370
|
-
expect('
|
|
371
|
+
expect('run: a -> { group_by: s is concat() }').toTranslate();
|
|
371
372
|
});
|
|
372
373
|
test('can pass different expression types', () => {
|
|
373
|
-
expect(`
|
|
374
|
+
expect(`run: a -> {
|
|
374
375
|
group_by: f1 is sqrt(1)
|
|
375
376
|
aggregate: f2 is sqrt(count())
|
|
376
377
|
aggregate: f3 is sqrt(all(count()))
|
|
@@ -379,29 +380,29 @@ describe('query:', () => {
|
|
|
379
380
|
}`).toTranslate();
|
|
380
381
|
});
|
|
381
382
|
test('function return type correct', () => {
|
|
382
|
-
expect(`
|
|
383
|
+
expect(`run: a -> {
|
|
383
384
|
group_by: s is floor(1.2) + 1
|
|
384
385
|
}`).toTranslate();
|
|
385
386
|
});
|
|
386
387
|
test('function return type incorrect', () => {
|
|
387
|
-
expect(`
|
|
388
|
+
expect(`run: a -> {
|
|
388
389
|
group_by: s is floor(1.2) + 'a'
|
|
389
390
|
}`).translationToFailWith("Non numeric('number,string') value with '+'");
|
|
390
391
|
});
|
|
391
392
|
test('can use output value in calculate', () => {
|
|
392
|
-
expect(`
|
|
393
|
+
expect(`run: a -> {
|
|
393
394
|
group_by: x is 1
|
|
394
395
|
calculate: s is lag(x)
|
|
395
396
|
}`).toTranslate();
|
|
396
397
|
});
|
|
397
398
|
test('cannot use output value in group_by', () => {
|
|
398
|
-
expect(`
|
|
399
|
+
expect(`run: a -> {
|
|
399
400
|
group_by: x is 1
|
|
400
401
|
group_by: y is x
|
|
401
402
|
}`).translationToFailWith("'x' is not defined");
|
|
402
403
|
});
|
|
403
404
|
test('lag can check that other args are constant', () => {
|
|
404
|
-
expect(`
|
|
405
|
+
expect(`run: a -> {
|
|
405
406
|
group_by: x is 1
|
|
406
407
|
calculate: s is lag(x, 1, x)
|
|
407
408
|
}`).translationToFailWith(
|
|
@@ -409,7 +410,7 @@ describe('query:', () => {
|
|
|
409
410
|
"Parameter 3 ('default') of lag must be literal or constant, but received output");
|
|
410
411
|
});
|
|
411
412
|
test('lag can check that other args are literal', () => {
|
|
412
|
-
expect(`
|
|
413
|
+
expect(`run: a -> {
|
|
413
414
|
group_by: x is 1
|
|
414
415
|
calculate: s is lag(x, 1 + 1)
|
|
415
416
|
}`).translationToFailWith(
|
|
@@ -417,13 +418,13 @@ describe('query:', () => {
|
|
|
417
418
|
"Parameter 2 ('offset') of lag must be literal, but received constant");
|
|
418
419
|
});
|
|
419
420
|
test('lag can check that other args are nonnull', () => {
|
|
420
|
-
expect(`
|
|
421
|
+
expect(`run: a -> {
|
|
421
422
|
group_by: x is 1
|
|
422
423
|
calculate: s is lag(x, null)
|
|
423
424
|
}`).translationToFailWith("Parameter 2 ('offset') of lag must not be a literal null");
|
|
424
425
|
});
|
|
425
426
|
test('lag can use constant values for other args', () => {
|
|
426
|
-
expect(`
|
|
427
|
+
expect(`run: a -> {
|
|
427
428
|
group_by: x is 1
|
|
428
429
|
calculate: s is lag(x, 2)
|
|
429
430
|
}`).toTranslate();
|
|
@@ -434,7 +435,7 @@ describe('query:', () => {
|
|
|
434
435
|
"'concat' is already defined, cannot redefine");
|
|
435
436
|
});
|
|
436
437
|
test('`now` is considered constant`', () => {
|
|
437
|
-
expect(`
|
|
438
|
+
expect(`run: a -> {
|
|
438
439
|
group_by: n is now
|
|
439
440
|
calculate: l is lag(n, 1, now)
|
|
440
441
|
}`).toTranslate();
|
|
@@ -442,7 +443,7 @@ describe('query:', () => {
|
|
|
442
443
|
// TODO it might be nice to reference a field which is a constant, and be able to
|
|
443
444
|
// use that as a constant param. Same with a literal.
|
|
444
445
|
test('cannot use a field which is a constant in a constant param', () => {
|
|
445
|
-
expect(`
|
|
446
|
+
expect(`run: a -> {
|
|
446
447
|
group_by: ai, pi is pi()
|
|
447
448
|
calculate: l is lag(ai, 1, pi)
|
|
448
449
|
}`).translationToFailWith("Parameter 3 ('default') of lag must be literal or constant, but received output");
|
|
@@ -452,7 +453,7 @@ describe('query:', () => {
|
|
|
452
453
|
// as a function argument.
|
|
453
454
|
// We add <join_name>_id to the query, but it's not included in the output space
|
|
454
455
|
test('cannot use struct in function arg', () => {
|
|
455
|
-
expect(`
|
|
456
|
+
expect(`run: a extend {join_one: b with astr } -> {
|
|
456
457
|
group_by: b
|
|
457
458
|
calculate: foo is lag(b)
|
|
458
459
|
}`).translationToFailWith('No matching overload for function lag(struct)');
|
|
@@ -460,37 +461,37 @@ describe('query:', () => {
|
|
|
460
461
|
// TODO this doesn't work today, we're not rigorous enough with integer
|
|
461
462
|
// subtypes. But we should probably make this typecheck properly.
|
|
462
463
|
test.skip('cannot use float in round precision', () => {
|
|
463
|
-
expect(`
|
|
464
|
+
expect(`run: a -> {
|
|
464
465
|
group_by: x is round(1.5, 1.6)
|
|
465
466
|
}`).translationToFailWith(
|
|
466
467
|
// TODO improve this error message
|
|
467
468
|
"Parameter 2 ('precision') for round must be integer, received float");
|
|
468
469
|
});
|
|
469
470
|
test('cannot use stddev with no arguments', () => {
|
|
470
|
-
expect(`
|
|
471
|
+
expect(`run: a -> {
|
|
471
472
|
aggregate: x is stddev()
|
|
472
473
|
}`).translationToFailWith('No matching overload for function stddev()');
|
|
473
474
|
});
|
|
474
475
|
test('can use stddev with postfix syntax', () => {
|
|
475
|
-
expect(`
|
|
476
|
-
|
|
476
|
+
expect(`run: a -> {
|
|
477
|
+
extend: { dimension: y is 1 }
|
|
477
478
|
aggregate: x is y.stddev()
|
|
478
479
|
}`).toTranslate();
|
|
479
480
|
});
|
|
480
481
|
test('can use stddev with postfix syntax on join', () => {
|
|
481
|
-
expect(`
|
|
482
|
-
join_one: b with astr
|
|
482
|
+
expect(`run: a -> {
|
|
483
|
+
extend: { join_one: b with astr }
|
|
483
484
|
aggregate: x is b.ai.stddev()
|
|
484
485
|
}`).toTranslate();
|
|
485
486
|
});
|
|
486
487
|
test('can use calculate with a measure', () => {
|
|
487
|
-
expect(`
|
|
488
|
+
expect(`run: a extend { measure: c is count() } -> {
|
|
488
489
|
group_by: y is 1
|
|
489
490
|
calculate: x is lag(c)
|
|
490
491
|
}`).toTranslate();
|
|
491
492
|
});
|
|
492
493
|
test('cannot use calculate with input fields', () => {
|
|
493
|
-
expect(`
|
|
494
|
+
expect(`run: a -> {
|
|
494
495
|
group_by: y is 1
|
|
495
496
|
calculate: x is lag(ai)
|
|
496
497
|
}`).translationToFailWith(
|
|
@@ -501,24 +502,24 @@ describe('query:', () => {
|
|
|
501
502
|
"Parameter 1 ('value') of lag must be literal, constant or output, but received input");
|
|
502
503
|
});
|
|
503
504
|
test('can use calculate with aggregate field which is not in query', () => {
|
|
504
|
-
expect(`
|
|
505
|
+
expect(`run: a extend { measure: acount is count() } -> {
|
|
505
506
|
group_by: astr
|
|
506
507
|
calculate: pc is lag(acount)
|
|
507
508
|
}`).toTranslate();
|
|
508
509
|
});
|
|
509
510
|
test('cannot use agregate as argument to agg function', () => {
|
|
510
|
-
expect(`
|
|
511
|
+
expect(`run: a -> {
|
|
511
512
|
aggregate: x is stddev(count())
|
|
512
513
|
}`).translationToFailWith("Parameter 1 ('value') of stddev must be scalar, but received aggregate");
|
|
513
514
|
});
|
|
514
515
|
test('cannot use calculate with no other fields', () => {
|
|
515
|
-
expect(`
|
|
516
|
+
expect(`run: a -> {
|
|
516
517
|
calculate: x is row_number()
|
|
517
518
|
}`).translationToFailWith("Can't determine query type (group_by/aggregate/nest,project,index)");
|
|
518
519
|
});
|
|
519
520
|
// TODO someday make it so we can order by an analytic function
|
|
520
521
|
test('today: cannot order by analytic function', () => {
|
|
521
|
-
expect(`
|
|
522
|
+
expect(`run: a -> {
|
|
522
523
|
group_by: astr
|
|
523
524
|
calculate: row_num is row_number()
|
|
524
525
|
order_by: row_num desc
|
|
@@ -529,45 +530,44 @@ describe('query:', () => {
|
|
|
529
530
|
group_by: astr
|
|
530
531
|
calculate: p is lag(astr)
|
|
531
532
|
}
|
|
532
|
-
|
|
533
|
+
run: a1 + {
|
|
533
534
|
calculate: p1 is lag(p)
|
|
534
535
|
}`).translationToFailWith("Parameter 1 ('value') of lag must be scalar or aggregate, but received scalar_analytic");
|
|
535
536
|
});
|
|
536
537
|
test('cannot use aggregate analytic in project', () => {
|
|
537
|
-
expect(`
|
|
538
|
-
|
|
538
|
+
expect(`run: a -> {
|
|
539
|
+
select: astr
|
|
539
540
|
calculate: p is lag(count())
|
|
540
541
|
}`).translationToFailWith('Cannot add aggregate analyics to project');
|
|
541
542
|
});
|
|
542
543
|
test('reference field in join', () => {
|
|
543
|
-
expect(`
|
|
544
|
-
join_one: b with astr
|
|
544
|
+
expect(`run: a -> {
|
|
545
|
+
extend: { join_one: b with astr }
|
|
545
546
|
group_by: b.ai
|
|
546
547
|
}`).toTranslate();
|
|
547
548
|
});
|
|
548
|
-
// TODO decide whether this syntax should be legal, really...
|
|
549
549
|
test('reference join name in group_by', () => {
|
|
550
|
-
expect(`
|
|
551
|
-
join_one: b with astr
|
|
550
|
+
expect(`run: a -> {
|
|
551
|
+
extend: { join_one: b with astr }
|
|
552
552
|
group_by: b
|
|
553
553
|
}`).toTranslate();
|
|
554
554
|
});
|
|
555
|
-
test('can reference
|
|
556
|
-
expect(`
|
|
557
|
-
join_one: b with astr
|
|
558
|
-
|
|
555
|
+
test('can reference select: inline join.* field in calculate', () => {
|
|
556
|
+
expect(`run: a -> {
|
|
557
|
+
extend: { join_one: b with astr }
|
|
558
|
+
select: b.*
|
|
559
559
|
calculate: s is lag(ai)
|
|
560
560
|
}`).toTranslate();
|
|
561
561
|
});
|
|
562
|
-
test('can reference
|
|
563
|
-
expect(`
|
|
564
|
-
|
|
562
|
+
test('can reference select: join.* field in calculate', () => {
|
|
563
|
+
expect(`run: a extend { join_one: b with astr } -> {
|
|
564
|
+
select: b.*
|
|
565
565
|
calculate: s is lag(ai)
|
|
566
566
|
}`).toTranslate();
|
|
567
567
|
});
|
|
568
568
|
test('can reference implied output entries in calculate', () => {
|
|
569
569
|
expect(`source: aaa is a extend { dimension: big_i is ai+10 }
|
|
570
|
-
|
|
570
|
+
run: a extend { join_one: aaa on astr=aaa.astr } -> {
|
|
571
571
|
group_by: aaa.big_i
|
|
572
572
|
aggregate: s is aaa.big_i.sum()
|
|
573
573
|
calculate: a is lag(big_i)
|
|
@@ -576,26 +576,26 @@ describe('query:', () => {
|
|
|
576
576
|
});
|
|
577
577
|
describe('qops', () => {
|
|
578
578
|
test('group by single', () => {
|
|
579
|
-
expect('
|
|
579
|
+
expect('run: a->{ group_by: astr }').toTranslate();
|
|
580
580
|
});
|
|
581
581
|
test("group_by x is x'", () => {
|
|
582
|
-
expect('
|
|
582
|
+
expect('run: a->{ group_by: ai is ai/2 }').toTranslate();
|
|
583
583
|
});
|
|
584
584
|
test('group by multiple', () => {
|
|
585
|
-
expect('
|
|
585
|
+
expect('run: a->{ group_by: astr,ai }').toTranslate();
|
|
586
586
|
});
|
|
587
587
|
test('aggregate single', () => {
|
|
588
|
-
expect('
|
|
588
|
+
expect('run: a->{ aggregate: num is count() }').toTranslate();
|
|
589
589
|
});
|
|
590
590
|
test('calculate in reduce', () => {
|
|
591
|
-
expect('
|
|
591
|
+
expect('run: a->{ group_by: astr, ai calculate: num is lag(ai) }').toTranslate();
|
|
592
592
|
});
|
|
593
593
|
test('calculate in project', () => {
|
|
594
|
-
expect('
|
|
594
|
+
expect('run: a->{ select: astr, ai calculate: num is lag(ai) }').toTranslate();
|
|
595
595
|
});
|
|
596
596
|
test('aggregate reference', () => {
|
|
597
597
|
var _a;
|
|
598
|
-
const doc = (0, test_translator_1.model) `
|
|
598
|
+
const doc = (0, test_translator_1.model) `run: a->{ aggregate: ai.sum() }`;
|
|
599
599
|
expect(doc).toTranslate();
|
|
600
600
|
const q = doc.translator.getQuery(0);
|
|
601
601
|
expect(q).toBeDefined();
|
|
@@ -608,7 +608,7 @@ describe('query:', () => {
|
|
|
608
608
|
});
|
|
609
609
|
test('timeunit reference', () => {
|
|
610
610
|
var _a;
|
|
611
|
-
const doc = (0, test_translator_1.model) `
|
|
611
|
+
const doc = (0, test_translator_1.model) `run: a->{ group_by: ats.day }`;
|
|
612
612
|
expect(doc).toTranslate();
|
|
613
613
|
const q = doc.translator.getQuery(0);
|
|
614
614
|
expect(q).toBeDefined();
|
|
@@ -617,13 +617,13 @@ describe('query:', () => {
|
|
|
617
617
|
});
|
|
618
618
|
test('aggregate multiple', () => {
|
|
619
619
|
expect(`
|
|
620
|
-
|
|
620
|
+
run: a->{
|
|
621
621
|
aggregate: num is count(), total is sum(ai)
|
|
622
622
|
}
|
|
623
623
|
`).toTranslate();
|
|
624
624
|
});
|
|
625
625
|
test('project ref', () => {
|
|
626
|
-
expect('
|
|
626
|
+
expect('run:ab->{ select: b.astr }').toTranslate();
|
|
627
627
|
});
|
|
628
628
|
const afields = test_translator_1.aTableDef.fields
|
|
629
629
|
.filter(f => (0, model_1.isAtomicFieldType)(f.type))
|
|
@@ -678,14 +678,10 @@ describe('query:', () => {
|
|
|
678
678
|
expect(fields.sort()).toEqual(afields.concat('x'));
|
|
679
679
|
});
|
|
680
680
|
test('project def', () => {
|
|
681
|
-
expect('
|
|
681
|
+
expect('run: ab->{ select: one is 1 }').toTranslate();
|
|
682
682
|
});
|
|
683
683
|
test('project multiple', () => {
|
|
684
|
-
expect(
|
|
685
|
-
query: a->{
|
|
686
|
-
project: one is 1, astr
|
|
687
|
-
}
|
|
688
|
-
`).toTranslate();
|
|
684
|
+
expect('run: a->{ select: one is 1, astr }').toTranslate();
|
|
689
685
|
});
|
|
690
686
|
test('index single', () => { });
|
|
691
687
|
test('regress check extend: and star', () => {
|
|
@@ -697,29 +693,29 @@ describe('query:', () => {
|
|
|
697
693
|
expect(fields.sort()).toEqual(afields.concat('x'));
|
|
698
694
|
});
|
|
699
695
|
test('project def', () => {
|
|
700
|
-
expect('
|
|
696
|
+
expect('run:ab->{ select: one is 1 }').toTranslate();
|
|
701
697
|
});
|
|
702
698
|
test('project multiple', () => {
|
|
703
699
|
expect(`
|
|
704
|
-
|
|
705
|
-
|
|
700
|
+
run: a->{
|
|
701
|
+
select: one is 1, astr
|
|
706
702
|
}
|
|
707
703
|
`).toTranslate();
|
|
708
704
|
});
|
|
709
705
|
test('index single', () => {
|
|
710
|
-
expect('
|
|
706
|
+
expect('run:a->{index: astr}').toTranslate();
|
|
711
707
|
});
|
|
712
708
|
test('index path', () => {
|
|
713
|
-
expect('
|
|
709
|
+
expect('run:ab->{index: ab.astr}').toTranslate();
|
|
714
710
|
});
|
|
715
711
|
test('index unique on path', () => {
|
|
716
|
-
expect('
|
|
712
|
+
expect('run:ab->{index: b.astr, ab.astr}').toTranslate();
|
|
717
713
|
});
|
|
718
714
|
test('index join.*', () => {
|
|
719
|
-
expect('
|
|
715
|
+
expect('run:ab->{index: ab.*}').toTranslate();
|
|
720
716
|
});
|
|
721
717
|
test('index multiple', () => {
|
|
722
|
-
const model = new test_translator_1.TestTranslator('
|
|
718
|
+
const model = new test_translator_1.TestTranslator('run:a->{index: af, astr}');
|
|
723
719
|
expect(model).toTranslate();
|
|
724
720
|
const q = model.getQuery(0);
|
|
725
721
|
expect(q).toBeDefined();
|
|
@@ -730,7 +726,7 @@ describe('query:', () => {
|
|
|
730
726
|
}
|
|
731
727
|
});
|
|
732
728
|
test('index star', () => {
|
|
733
|
-
const model = new test_translator_1.TestTranslator('
|
|
729
|
+
const model = new test_translator_1.TestTranslator('run:a->{index: *, astr}');
|
|
734
730
|
expect(model).toTranslate();
|
|
735
731
|
const q = model.getQuery(0);
|
|
736
732
|
expect(q).toBeDefined();
|
|
@@ -741,16 +737,16 @@ describe('query:', () => {
|
|
|
741
737
|
}
|
|
742
738
|
});
|
|
743
739
|
test('index by', () => {
|
|
744
|
-
expect('
|
|
740
|
+
expect('run:a->{index: * by ai}').toTranslate();
|
|
745
741
|
});
|
|
746
742
|
test('index sampled', () => {
|
|
747
|
-
expect('
|
|
743
|
+
expect('run:a->{index: *; sample: true}').toTranslate();
|
|
748
744
|
});
|
|
749
745
|
test('index unsampled', () => {
|
|
750
|
-
expect('
|
|
746
|
+
expect('run:a->{index: *; sample: false}').toTranslate();
|
|
751
747
|
});
|
|
752
748
|
test('index sample-percent', () => {
|
|
753
|
-
const model = new test_translator_1.TestTranslator('
|
|
749
|
+
const model = new test_translator_1.TestTranslator('run:a->{index: *; sample: 42%}');
|
|
754
750
|
expect(model).toTranslate();
|
|
755
751
|
const q = model.getQuery(0);
|
|
756
752
|
expect(q).toBeDefined();
|
|
@@ -763,74 +759,75 @@ describe('query:', () => {
|
|
|
763
759
|
}
|
|
764
760
|
});
|
|
765
761
|
test('index sample-rows', () => {
|
|
766
|
-
expect('
|
|
762
|
+
expect('run:a->{index: *; sample: 100000}').toTranslate();
|
|
767
763
|
});
|
|
768
764
|
test('top N', () => {
|
|
769
|
-
expect('
|
|
765
|
+
expect('run: a->{ top: 5; group_by: astr }').toTranslate();
|
|
770
766
|
});
|
|
771
767
|
test('top N by field', () => {
|
|
772
|
-
expect(
|
|
768
|
+
expect(`##! m4warnings
|
|
769
|
+
run: a->{top: 5 ${'by astr'}; group_by: astr}`).toTranslateWithWarnings('by clause of top statement unupported. Use order_by instead');
|
|
773
770
|
});
|
|
774
771
|
test('top N by expression', () => {
|
|
775
|
-
expect(
|
|
772
|
+
expect(`##! m4warnings
|
|
773
|
+
run: ab->{top: 5 by ai + 1; group_by: ai}`).toTranslateWithWarnings('by clause of top statement unupported. Use order_by instead');
|
|
776
774
|
});
|
|
777
|
-
test('top N by field must be in the output space', () => expect('query: a->{top: 5 by af; group_by: astr}').translationToFailWith('Unknown field af in output space'));
|
|
778
775
|
test('limit N', () => {
|
|
779
|
-
expect('
|
|
776
|
+
expect('run: a->{ limit: 5; group_by: astr }').toTranslate();
|
|
780
777
|
});
|
|
781
778
|
test('order by', () => {
|
|
782
|
-
expect('
|
|
779
|
+
expect('run: a->{ order_by: astr; group_by: astr }').toTranslate();
|
|
783
780
|
});
|
|
784
781
|
test('order by preserved over refinement', () => {
|
|
785
782
|
expect(`
|
|
786
783
|
query: a1 is a -> { group_by: astr }
|
|
787
|
-
|
|
784
|
+
run: a1 + { order_by: astr }
|
|
788
785
|
`).toTranslate();
|
|
789
786
|
});
|
|
790
|
-
test('order by must be in the output space', () => expect('
|
|
787
|
+
test('order by must be in the output space', () => expect('run: a -> { order_by: af; group_by: astr }').translationToFailWith('Unknown field af in output space'));
|
|
791
788
|
test('order by asc', () => {
|
|
792
|
-
expect('
|
|
789
|
+
expect('run: a->{ order_by: astr asc; group_by: astr }').toTranslate();
|
|
793
790
|
});
|
|
794
791
|
test('order by desc', () => {
|
|
795
|
-
expect('
|
|
792
|
+
expect('run: a->{ order_by: astr desc; group_by: astr }').toTranslate();
|
|
796
793
|
});
|
|
797
794
|
test('order by N', () => {
|
|
798
|
-
expect('
|
|
795
|
+
expect('run: a->{ order_by: 1 asc; group_by: astr }').toTranslate();
|
|
799
796
|
});
|
|
800
797
|
test('order by multiple', () => {
|
|
801
798
|
expect(`
|
|
802
|
-
|
|
799
|
+
run: a->{
|
|
803
800
|
order_by: 1 asc, af desc
|
|
804
801
|
group_by: astr, af
|
|
805
802
|
}
|
|
806
803
|
`).toTranslate();
|
|
807
804
|
});
|
|
808
805
|
test('agg cannot be used in where', () => {
|
|
809
|
-
expect('
|
|
806
|
+
expect('run:ab->{ aggregate: acount; group_by: astr; where: acount > 10 }').translationToFailWith('Aggregate expressions are not allowed in `where:`; use `having:`');
|
|
810
807
|
});
|
|
811
808
|
test('analytic cannot be used in where', () => {
|
|
812
|
-
expect('
|
|
809
|
+
expect('run:ab->{ calculate: prevc is lag(count()); group_by: astr; where: prevc > 10 }').translationToFailWith("'prevc' is not defined");
|
|
813
810
|
});
|
|
814
811
|
test('analytic cannot be used in having', () => {
|
|
815
|
-
expect('
|
|
812
|
+
expect('run:ab->{ calculate: prevc is lag(count()); group_by: astr; having: prevc > 10 }').translationToFailWith('Analytic expressions are not allowed in `having:`');
|
|
816
813
|
});
|
|
817
814
|
test('where single', () => {
|
|
818
|
-
expect('
|
|
815
|
+
expect('run:a->{ group_by: astr; where: af > 10 }').toTranslate();
|
|
819
816
|
});
|
|
820
817
|
test('having single', () => {
|
|
821
|
-
expect('
|
|
818
|
+
expect('run:ab->{ aggregate: acount; group_by: astr; having: acount > 10 }').toTranslate();
|
|
822
819
|
});
|
|
823
820
|
test('compound having still works', () => {
|
|
824
|
-
expect('
|
|
821
|
+
expect('run:ab->{ aggregate: acount; having: acount > 10 and acount < 100 }').toTranslate();
|
|
825
822
|
});
|
|
826
823
|
test('compound aggregate still works', () => {
|
|
827
|
-
expect('
|
|
824
|
+
expect('run:ab->{ aggregate: thing is acount > 10 and acount < 100 }').toTranslate();
|
|
828
825
|
});
|
|
829
826
|
test('where multiple', () => {
|
|
830
|
-
expect("
|
|
827
|
+
expect("run:a->{ group_by: astr; where: af > 10,astr~'a%' }").toTranslate();
|
|
831
828
|
});
|
|
832
829
|
test('filters preserve source formatting in code:', () => {
|
|
833
|
-
const model = new test_translator_1.TestTranslator("source: notb is a
|
|
830
|
+
const model = new test_translator_1.TestTranslator("source: notb is a extend { where: astr != 'b' }");
|
|
834
831
|
expect(model).toTranslate();
|
|
835
832
|
const notb = model.getSourceDef('notb');
|
|
836
833
|
expect(notb).toBeDefined();
|
|
@@ -843,7 +840,7 @@ describe('query:', () => {
|
|
|
843
840
|
}
|
|
844
841
|
});
|
|
845
842
|
test('field expressions preserve source formatting in code:', () => {
|
|
846
|
-
const model = new test_translator_1.TestTranslator('source: notb is a
|
|
843
|
+
const model = new test_translator_1.TestTranslator('source: notb is a extend { dimension: d is 1 + 2 }');
|
|
847
844
|
expect(model).toTranslate();
|
|
848
845
|
const notb = model.getSourceDef('notb');
|
|
849
846
|
expect(notb).toBeDefined();
|
|
@@ -858,42 +855,42 @@ describe('query:', () => {
|
|
|
858
855
|
});
|
|
859
856
|
test('nest single', () => {
|
|
860
857
|
expect(`
|
|
861
|
-
|
|
858
|
+
run: a->{
|
|
862
859
|
group_by: ai
|
|
863
860
|
nest: nestbystr is { group_by: astr; aggregate: N is count() }
|
|
864
861
|
}
|
|
865
862
|
`).toTranslate();
|
|
866
863
|
});
|
|
867
864
|
test('nest multiple', () => expect(`
|
|
868
|
-
|
|
865
|
+
run: a->{
|
|
869
866
|
group_by: ai
|
|
870
867
|
nest:
|
|
871
868
|
nestbystr is { group_by: astr; aggregate: N is count() },
|
|
872
869
|
renest is { group_by: astr; aggregate: N is count() }
|
|
873
870
|
}
|
|
874
871
|
`).toTranslate());
|
|
875
|
-
test('nest ref', () => expect('
|
|
872
|
+
test('nest ref', () => expect('run: ab->{group_by: ai; nest: aturtle}').toTranslate());
|
|
876
873
|
describe('extend block', () => {
|
|
877
874
|
test('works with dimension', () => {
|
|
878
|
-
expect('
|
|
875
|
+
expect('run: a -> { extend: { dimension: x is 1 }; group_by: x }').toTranslate();
|
|
879
876
|
});
|
|
880
877
|
test('works with measure', () => {
|
|
881
|
-
expect('
|
|
878
|
+
expect('run: a -> { extend: { measure: x is count() }; aggregate: x }').toTranslate();
|
|
882
879
|
});
|
|
883
880
|
test('works with join_one', () => {
|
|
884
|
-
expect('
|
|
881
|
+
expect('run: a -> { extend: { join_one: bb is b on bb.astr = astr }; group_by: bb.astr }').toTranslate();
|
|
885
882
|
});
|
|
886
883
|
test('works with join_many', () => {
|
|
887
|
-
expect('
|
|
884
|
+
expect('run: a -> { extend: { join_many: b on astr = b.astr }; group_by: b.astr }').toTranslate();
|
|
888
885
|
});
|
|
889
886
|
test('works with join_cross', () => {
|
|
890
|
-
expect('
|
|
887
|
+
expect('run: a -> { extend: { join_cross: b on true }; group_by: b.astr }').toTranslate();
|
|
891
888
|
});
|
|
892
889
|
test('works with multiple in one block', () => {
|
|
893
|
-
expect('
|
|
890
|
+
expect('run: a -> { extend: { dimension: x is 1, y is 2 }; group_by: x, y }').toTranslate();
|
|
894
891
|
});
|
|
895
892
|
test('works with multiple blocks', () => {
|
|
896
|
-
expect('
|
|
893
|
+
expect('run: a -> { extend: { dimension: x is 1; dimension: y is 2; measure: c is count() }; group_by: x, y; aggregate: c }').toTranslate();
|
|
897
894
|
});
|
|
898
895
|
});
|
|
899
896
|
describe('declare/query join warnings', () => {
|
|
@@ -912,12 +909,11 @@ describe('query:', () => {
|
|
|
912
909
|
});
|
|
913
910
|
test('refine query with extended source', () => {
|
|
914
911
|
const m = new test_translator_1.TestTranslator(`
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
912
|
+
run: ab extend {
|
|
913
|
+
view: xturtle is aturtle + {
|
|
914
|
+
extend: { measure: aratio is ai / acount }
|
|
918
915
|
}
|
|
919
|
-
}
|
|
920
|
-
query: nab -> xturtle + { aggregate: aratio }
|
|
916
|
+
} -> xturtle + { aggregate: aratio }
|
|
921
917
|
`);
|
|
922
918
|
expect(m).toTranslate();
|
|
923
919
|
const t = m.translate();
|
|
@@ -939,8 +935,8 @@ describe('query:', () => {
|
|
|
939
935
|
});
|
|
940
936
|
test('refine query source with field', () => {
|
|
941
937
|
const m = new test_translator_1.TestTranslator(`
|
|
942
|
-
|
|
943
|
-
|
|
938
|
+
run: ab -> aturtle + {
|
|
939
|
+
extend: { measure: aratio is ai / acount }
|
|
944
940
|
aggregate: aratio
|
|
945
941
|
}
|
|
946
942
|
`);
|
|
@@ -963,8 +959,8 @@ describe('query:', () => {
|
|
|
963
959
|
});
|
|
964
960
|
test('refine query source with join', () => {
|
|
965
961
|
const m = new test_translator_1.TestTranslator(`
|
|
966
|
-
|
|
967
|
-
join_one: bb is b on bb.astr = astr
|
|
962
|
+
run: ab -> aturtle + {
|
|
963
|
+
extend: { join_one: bb is b on bb.astr = astr }
|
|
968
964
|
group_by: foo is bb.astr
|
|
969
965
|
}
|
|
970
966
|
`);
|
|
@@ -985,8 +981,8 @@ describe('query:', () => {
|
|
|
985
981
|
describe('refinement location rules', () => {
|
|
986
982
|
test('where clauses go into the first segment', () => {
|
|
987
983
|
const doc = (0, test_translator_1.model) `
|
|
988
|
-
query: refineme is a -> {
|
|
989
|
-
query: checkme is refineme
|
|
984
|
+
query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
985
|
+
query: checkme is refineme + { where: astr = 'a' }`;
|
|
990
986
|
expect(doc).toTranslate();
|
|
991
987
|
const checkme = doc.translator.getQuery('checkme');
|
|
992
988
|
expect(checkme).toBeDefined();
|
|
@@ -1001,7 +997,7 @@ describe('query:', () => {
|
|
|
1001
997
|
test('having clauses go into the last segment', () => {
|
|
1002
998
|
const doc = (0, test_translator_1.model) `
|
|
1003
999
|
query: refineme is a -> { group_by: ai,astr } -> { group_by: ai, aggregate: ac is count() }
|
|
1004
|
-
query: checkme is refineme
|
|
1000
|
+
query: checkme is refineme + { having: ac > 0 }`;
|
|
1005
1001
|
expect(doc).toTranslate();
|
|
1006
1002
|
const checkme = doc.translator.getQuery('checkme');
|
|
1007
1003
|
expect(checkme).toBeDefined();
|
|
@@ -1016,7 +1012,7 @@ describe('query:', () => {
|
|
|
1016
1012
|
test('limit goes into the last segment', () => {
|
|
1017
1013
|
const doc = (0, test_translator_1.model) `
|
|
1018
1014
|
query: refineme is a -> { group_by: ai,astr } -> { group_by: ai, aggregate: ac is count() }
|
|
1019
|
-
query: checkme is refineme
|
|
1015
|
+
query: checkme is refineme + { limit: 1 }`;
|
|
1020
1016
|
expect(doc).toTranslate();
|
|
1021
1017
|
const checkme = doc.translator.getQuery('checkme');
|
|
1022
1018
|
expect(checkme).toBeDefined();
|
|
@@ -1027,7 +1023,7 @@ describe('query:', () => {
|
|
|
1027
1023
|
test('order_by goes into the last segment', () => {
|
|
1028
1024
|
const doc = (0, test_translator_1.model) `
|
|
1029
1025
|
query: refineme is a -> { group_by: ai,astr } -> { group_by: ai, aggregate: ac is count() }
|
|
1030
|
-
query: checkme is refineme
|
|
1026
|
+
query: checkme is refineme + { order_by: 2 }`;
|
|
1031
1027
|
expect(doc).toTranslate();
|
|
1032
1028
|
const checkme = doc.translator.getQuery('checkme');
|
|
1033
1029
|
expect(checkme).toBeDefined();
|
|
@@ -1037,28 +1033,28 @@ describe('query:', () => {
|
|
|
1037
1033
|
});
|
|
1038
1034
|
const stageErr = 'Illegal in refinement of a query with more than one stage';
|
|
1039
1035
|
test('group_by illegal in long pipes', () => {
|
|
1040
|
-
expect((0, test_translator_1.markSource) `query: refineme is a -> {
|
|
1041
|
-
query: checkme is refineme
|
|
1036
|
+
expect((0, test_translator_1.markSource) `query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
1037
|
+
query: checkme is refineme + { ${'group_by: stage'} }`).translationToFailWith(stageErr);
|
|
1042
1038
|
});
|
|
1043
1039
|
test('aggregate illegal in long pipes', () => {
|
|
1044
|
-
expect((0, test_translator_1.markSource) `query: refineme is a -> {
|
|
1045
|
-
query: checkme is refineme
|
|
1040
|
+
expect((0, test_translator_1.markSource) `query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
1041
|
+
query: checkme is refineme + { ${'aggregate: c is count()'} }`).translationToFailWith(stageErr);
|
|
1046
1042
|
});
|
|
1047
1043
|
test('calcluate illegal in long pipes', () => {
|
|
1048
|
-
expect((0, test_translator_1.markSource) `query: refineme is a -> {
|
|
1049
|
-
query: checkme is refineme
|
|
1044
|
+
expect((0, test_translator_1.markSource) `query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
1045
|
+
query: checkme is refineme + { ${'calculate: c is count()'} }`).translationToFailWith(stageErr);
|
|
1050
1046
|
});
|
|
1051
1047
|
test('extend illegal in long pipes', () => {
|
|
1052
|
-
expect((0, test_translator_1.markSource) `query: refineme is a -> {
|
|
1053
|
-
query: checkme is refineme
|
|
1048
|
+
expect((0, test_translator_1.markSource) `query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
1049
|
+
query: checkme is refineme + { ${'extend: {measure: c is count()}'} }`).translationToFailWith(stageErr);
|
|
1054
1050
|
});
|
|
1055
1051
|
test('nest illegal in long pipes', () => {
|
|
1056
|
-
expect((0, test_translator_1.markSource) `query: refineme is a -> {
|
|
1057
|
-
query: checkme is refineme
|
|
1052
|
+
expect((0, test_translator_1.markSource) `query: refineme is a -> { select: stage is "stage1" } -> { select: stage is "stage2" }
|
|
1053
|
+
query: checkme is refineme + { ${'nest: b is {group_by: stage}'} }`).translationToFailWith(stageErr);
|
|
1058
1054
|
});
|
|
1059
1055
|
test('all single stage refinements are accepted', () => {
|
|
1060
1056
|
expect((0, test_translator_1.markSource) `query: refineme is a -> { group_by: stage is "stage1" }
|
|
1061
|
-
query: checkme is refineme
|
|
1057
|
+
query: checkme is refineme + {
|
|
1062
1058
|
extend: { dimension: red is 'red' }
|
|
1063
1059
|
nest: nestRed is { group_by: red }
|
|
1064
1060
|
group_by: ai
|