@malloydata/malloy 0.0.38-dev230609221655 → 0.0.38-dev230612191503
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/refined-source.js +1 -1
- package/dist/lang/ast/source-properties/timezone-statement.d.ts +1 -0
- package/dist/lang/ast/source-properties/timezone-statement.js +9 -0
- package/dist/lang/ast/sources/sql-source.js +3 -3
- package/dist/lang/lib/Malloy/MalloyLexer.d.ts +131 -132
- package/dist/lang/lib/Malloy/MalloyLexer.js +1051 -1063
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +233 -245
- package/dist/lang/lib/Malloy/MalloyParser.js +1437 -1513
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +0 -11
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +0 -7
- package/dist/lang/malloy-to-ast.js +8 -4
- package/dist/lang/test/document-help-context-walker.spec.js +1 -1
- package/dist/lang/test/document-symbol-walker.spec.js +10 -10
- package/dist/lang/test/parse-expects.d.ts +3 -1
- package/dist/lang/test/parse-expects.js +5 -2
- package/dist/lang/test/parse.spec.js +96 -96
- package/dist/lang/test/sql-block.spec.js +2 -2
- package/dist/lang/test/test-translator.js +1 -1
- package/dist/malloy.js +1 -1
- package/dist/model/malloy_query.js +2 -2
- package/package.json +1 -1
|
@@ -78,17 +78,17 @@ function badModel(s, msg) {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
describe('model statements', () => {
|
|
81
|
-
describe('
|
|
82
|
-
test('
|
|
83
|
-
test('
|
|
84
|
-
expect("
|
|
81
|
+
describe('source:', () => {
|
|
82
|
+
test('table', modelOK("source: testA is table('aTable')"));
|
|
83
|
+
test('shorcut fitlered table', () => {
|
|
84
|
+
expect("source: testA is table('aTable') {? astr ~ 'a%' } ").toCompile();
|
|
85
85
|
});
|
|
86
|
-
test('
|
|
87
|
-
|
|
86
|
+
test('fitlered table', modelOK(`
|
|
87
|
+
source: testA is table('aTable') { where: astr ~ 'a%' }
|
|
88
88
|
`));
|
|
89
|
-
test('
|
|
90
|
-
test('
|
|
91
|
-
test('refine
|
|
89
|
+
test('ref source with no refinement', modelOK('source: testA is a'));
|
|
90
|
+
test('from(query)', modelOK('source: testA is from(a->{group_by: astr})'));
|
|
91
|
+
test('refine source', modelOK('source: aa is a { dimension: a is astr }'));
|
|
92
92
|
test('source refinement preserves original', () => {
|
|
93
93
|
const x = new test_translator_1.TestTranslator('source: na is a + { dimension: one is 1 }');
|
|
94
94
|
expect(x).modelCompiled();
|
|
@@ -116,7 +116,7 @@ describe('model statements', () => {
|
|
|
116
116
|
-> { group_by: astr; aggregate: acount }
|
|
117
117
|
-> { top: 5; where: astr ~ 'a%' group_by: astr }
|
|
118
118
|
`));
|
|
119
|
-
test('query
|
|
119
|
+
test('from(query) refined into query', modelOK('query: from(ab -> {group_by: astr}) { dimension: bigstr is UPPER(astr) } -> { group_by: bigstr }'));
|
|
120
120
|
test('query with shortcut filtered turtle', modelOK("query: allA is ab->aturtle {? astr ~ 'a%' }"));
|
|
121
121
|
test('query with filtered turtle', modelOK("query: allA is ab->aturtle { where: astr ~ 'a%' }"));
|
|
122
122
|
test('nest: in group_by:', modelOK(`
|
|
@@ -228,34 +228,34 @@ describe('model statements', () => {
|
|
|
228
228
|
expect('query: q1 is a -> { project: * }, q1 is a -> { project: * }').compileToFailWith("Query 'q1' is already defined, cannot redefine");
|
|
229
229
|
});
|
|
230
230
|
});
|
|
231
|
-
describe('
|
|
232
|
-
test('single dimension', modelOK('
|
|
231
|
+
describe('source properties', () => {
|
|
232
|
+
test('single dimension', modelOK('source: aa is a { dimension: x is 1 }'));
|
|
233
233
|
test('multiple dimensions', modelOK(`
|
|
234
|
-
|
|
234
|
+
source: aa is a {
|
|
235
235
|
dimension:
|
|
236
236
|
x is 1
|
|
237
237
|
y is 2
|
|
238
238
|
}
|
|
239
239
|
`));
|
|
240
|
-
test('single declare', modelOK('
|
|
240
|
+
test('single declare', modelOK('source: aa is a { declare: x is 1 }'));
|
|
241
241
|
test('multiple declare', modelOK(`
|
|
242
|
-
|
|
242
|
+
source: aa is a {
|
|
243
243
|
declare:
|
|
244
244
|
x is 1
|
|
245
245
|
y is 2
|
|
246
246
|
}
|
|
247
247
|
`));
|
|
248
|
-
test('single measure', modelOK('
|
|
248
|
+
test('single measure', modelOK('source: aa is a { measure: x is count() }'));
|
|
249
249
|
test('multiple measures', modelOK(`
|
|
250
|
-
|
|
250
|
+
source: aa is a {
|
|
251
251
|
dimension:
|
|
252
252
|
x is count()
|
|
253
253
|
y is x * x
|
|
254
254
|
}
|
|
255
255
|
`));
|
|
256
|
-
test('single where', modelOK('
|
|
256
|
+
test('single where', modelOK('source: aa is a { where: ai > 10 }'));
|
|
257
257
|
test('multiple where', modelOK(`
|
|
258
|
-
|
|
258
|
+
source: aa is a {
|
|
259
259
|
where:
|
|
260
260
|
ai > 10,
|
|
261
261
|
af < 1000
|
|
@@ -271,18 +271,18 @@ describe('explore properties', () => {
|
|
|
271
271
|
}
|
|
272
272
|
}`));
|
|
273
273
|
describe('joins', () => {
|
|
274
|
-
test('with', modelOK('
|
|
275
|
-
test('with', modelOK('
|
|
276
|
-
test('with dotted ref', modelOK('
|
|
277
|
-
test('one on', modelOK('
|
|
278
|
-
test('one is on', modelOK('
|
|
279
|
-
test('many on', modelOK('
|
|
280
|
-
test('many is on', modelOK('
|
|
281
|
-
test('cross', modelOK('
|
|
282
|
-
test('cross is', modelOK('
|
|
283
|
-
test('cross on', modelOK('
|
|
274
|
+
test('with', modelOK('source: x is a { join_one: b with astr }'));
|
|
275
|
+
test('with', modelOK('source: x is a { join_one: y is b with astr }'));
|
|
276
|
+
test('with dotted ref', modelOK('source: x is ab { join_one: xz is a with b.astr }'));
|
|
277
|
+
test('one on', modelOK('source: x is a { join_one: b on astr = b.astr }'));
|
|
278
|
+
test('one is on', modelOK('source: x is a { join_one: y is b on astr = y.astr }'));
|
|
279
|
+
test('many on', modelOK('source: nab is a { join_many: b on astr = b.astr }'));
|
|
280
|
+
test('many is on', modelOK('source: y is a { join_many: x is b on astr = x.astr }'));
|
|
281
|
+
test('cross', modelOK('source: nab is a { join_cross: b }'));
|
|
282
|
+
test('cross is', modelOK('source: nab is a { join_cross: xb is b }'));
|
|
283
|
+
test('cross on', modelOK('source: nab is a { join_cross: b on true}'));
|
|
284
284
|
test('multiple joins', modelOK(`
|
|
285
|
-
|
|
285
|
+
source: nab is a {
|
|
286
286
|
join_one:
|
|
287
287
|
b with astr,
|
|
288
288
|
br is b with astr
|
|
@@ -296,19 +296,19 @@ describe('explore properties', () => {
|
|
|
296
296
|
`).compileToFailWith('join_one: Cannot use with unless source has a primary key');
|
|
297
297
|
});
|
|
298
298
|
});
|
|
299
|
-
test('primary_key', modelOK('
|
|
300
|
-
test('rename', modelOK('
|
|
299
|
+
test('primary_key', modelOK('source: c is a { primary_key: ai }'));
|
|
300
|
+
test('rename', modelOK('source: c is a { rename: nn is ai }'));
|
|
301
301
|
test('accept single', () => {
|
|
302
|
-
const onlyAstr = new test_translator_1.TestTranslator('
|
|
302
|
+
const onlyAstr = new test_translator_1.TestTranslator('source: c is a { accept: astr }');
|
|
303
303
|
expect(onlyAstr).modelCompiled();
|
|
304
304
|
const c = onlyAstr.getSourceDef('c');
|
|
305
305
|
if (c) {
|
|
306
306
|
expect(c.fields.length).toBe(1);
|
|
307
307
|
}
|
|
308
308
|
});
|
|
309
|
-
test('accept multi', modelOK('
|
|
309
|
+
test('accept multi', modelOK('source: c is a { accept: astr, af }'));
|
|
310
310
|
test('except single', () => {
|
|
311
|
-
const noAstr = new test_translator_1.TestTranslator('
|
|
311
|
+
const noAstr = new test_translator_1.TestTranslator('source: c is a { except: astr }');
|
|
312
312
|
expect(noAstr).modelCompiled();
|
|
313
313
|
const c = noAstr.getSourceDef('c');
|
|
314
314
|
if (c) {
|
|
@@ -316,15 +316,15 @@ describe('explore properties', () => {
|
|
|
316
316
|
expect(foundAstr).toBeUndefined();
|
|
317
317
|
}
|
|
318
318
|
});
|
|
319
|
-
test('except multi', modelOK('
|
|
320
|
-
test('explore-query', modelOK('
|
|
319
|
+
test('except multi', modelOK('source: c is a { except: astr, af }'));
|
|
320
|
+
test('explore-query', modelOK('source: c is a {query: q is { group_by: astr } }'));
|
|
321
321
|
test('refined explore-query', modelOK(`
|
|
322
|
-
|
|
322
|
+
source: abNew is ab {
|
|
323
323
|
query: for1 is aturtle {? ai = 1 }
|
|
324
324
|
}
|
|
325
325
|
`));
|
|
326
326
|
test('chained explore-query', modelOK(`
|
|
327
|
-
|
|
327
|
+
source: c is a {
|
|
328
328
|
query: chain is {
|
|
329
329
|
group_by: astr
|
|
330
330
|
} -> {
|
|
@@ -334,7 +334,7 @@ describe('explore properties', () => {
|
|
|
334
334
|
}
|
|
335
335
|
`));
|
|
336
336
|
test('multiple explore-query', modelOK(`
|
|
337
|
-
|
|
337
|
+
source: abNew is ab {
|
|
338
338
|
query:
|
|
339
339
|
q1 is { group_by: astr },
|
|
340
340
|
q2 is { group_by: ai }
|
|
@@ -751,14 +751,14 @@ describe('expressions', () => {
|
|
|
751
751
|
`));
|
|
752
752
|
test('n-ary without else', () => {
|
|
753
753
|
expect((0, test_translator_1.markSource) `
|
|
754
|
-
|
|
754
|
+
source: na is a + { dimension: d is
|
|
755
755
|
pick 7 when true and true
|
|
756
756
|
}
|
|
757
757
|
`).compileToFailWith("pick incomplete, missing 'else'", "Cannot define 'd', value has unknown type");
|
|
758
758
|
});
|
|
759
759
|
test('n-ary with mismatch when clauses', () => {
|
|
760
760
|
expect((0, test_translator_1.markSource) `
|
|
761
|
-
|
|
761
|
+
source: na is a + { dimension: d is
|
|
762
762
|
pick 7 when true and true
|
|
763
763
|
pick '7' when true or true
|
|
764
764
|
else 7
|
|
@@ -767,7 +767,7 @@ describe('expressions', () => {
|
|
|
767
767
|
});
|
|
768
768
|
test('n-ary with mismatched else clause', () => {
|
|
769
769
|
expect((0, test_translator_1.markSource) `
|
|
770
|
-
|
|
770
|
+
source: na is a + { dimension: d is
|
|
771
771
|
pick 7 when true and true
|
|
772
772
|
else '7'
|
|
773
773
|
}
|
|
@@ -775,21 +775,21 @@ describe('expressions', () => {
|
|
|
775
775
|
});
|
|
776
776
|
test('applied else mismatch', () => {
|
|
777
777
|
expect((0, test_translator_1.markSource) `
|
|
778
|
-
|
|
778
|
+
source: na is a + { dimension: d is
|
|
779
779
|
7 ? pick 7 when 7 else 'not seven'
|
|
780
780
|
}
|
|
781
781
|
`).compileToFailWith("else type 'string', expected 'number'", "Cannot define 'd', value has unknown type");
|
|
782
782
|
});
|
|
783
783
|
test('applied default mismatch', () => {
|
|
784
784
|
expect((0, test_translator_1.markSource) `
|
|
785
|
-
|
|
785
|
+
source: na is a + { dimension: d is
|
|
786
786
|
7 ? pick 'seven' when 7
|
|
787
787
|
}
|
|
788
788
|
`).compileToFailWith("pick default type 'number', expected 'string'", "Cannot define 'd', value has unknown type");
|
|
789
789
|
});
|
|
790
790
|
test('applied when mismatch', () => {
|
|
791
791
|
expect((0, test_translator_1.markSource) `
|
|
792
|
-
|
|
792
|
+
source: na is a + { dimension: d is
|
|
793
793
|
7 ? pick 'seven' when 7 pick 6 when 6
|
|
794
794
|
}
|
|
795
795
|
`).compileToFailWith("pick type 'number', expected 'string'", "Cannot define 'd', value has unknown type");
|
|
@@ -893,12 +893,12 @@ describe('error handling', () => {
|
|
|
893
893
|
});
|
|
894
894
|
test('join reference before definition', () => {
|
|
895
895
|
expect((0, test_translator_1.markSource) `
|
|
896
|
-
|
|
897
|
-
|
|
896
|
+
source: newAB is a { join_one: newB is ${'bb'} on astring }
|
|
897
|
+
source: newB is b
|
|
898
898
|
`).compileToFailWith("Undefined source 'bb'");
|
|
899
899
|
});
|
|
900
|
-
test('non-rename rename', badModel('
|
|
901
|
-
test('reference to field in its definition', badModel('
|
|
900
|
+
test('non-rename rename', badModel('source: na is a { rename: astr is astr }', "Can't rename field to itself"));
|
|
901
|
+
test('reference to field in its definition', badModel('source: na is a { dimension: ustr is UPPER(ustr) } ', "Circular reference to 'ustr' in definition"));
|
|
902
902
|
test('empty model', modelOK(''));
|
|
903
903
|
test('one line model ', modelOK('\n'));
|
|
904
904
|
test('query without fields', badModel('query: a -> { top: 5 }', "Can't determine query type (group_by/aggregate/nest,project,index)"));
|
|
@@ -906,7 +906,7 @@ describe('error handling', () => {
|
|
|
906
906
|
test('undefined field ref in query', badModel('query: ab -> { aggregate: xyzzy }', "'xyzzy' is not defined"));
|
|
907
907
|
test('query on source with errors', () => {
|
|
908
908
|
expect((0, test_translator_1.markSource) `
|
|
909
|
-
|
|
909
|
+
source: na is a { join_one: ${'n'} on astr }
|
|
910
910
|
`).compileToFailWith("Undefined source 'n'");
|
|
911
911
|
});
|
|
912
912
|
test('detect duplicate output field names', () => {
|
|
@@ -945,7 +945,7 @@ describe('error handling', () => {
|
|
|
945
945
|
}
|
|
946
946
|
`));
|
|
947
947
|
test('popping out of embedding when not embedded', () => {
|
|
948
|
-
expect('}%').compileToFailWith(
|
|
948
|
+
expect('}%').compileToFailWith(/extraneous input '}%' expecting/);
|
|
949
949
|
});
|
|
950
950
|
test('bad sql in sql block', () => {
|
|
951
951
|
const badModel = new test_translator_1.TestTranslator('sql: { select: """)""" }');
|
|
@@ -987,20 +987,20 @@ function getSelectOneStruct(sqlBlock) {
|
|
|
987
987
|
};
|
|
988
988
|
}
|
|
989
989
|
describe('source locations', () => {
|
|
990
|
-
test('renamed
|
|
991
|
-
const source = (0, test_translator_1.markSource) `
|
|
990
|
+
test('renamed source location', () => {
|
|
991
|
+
const source = (0, test_translator_1.markSource) `source: ${'na is a'}`;
|
|
992
992
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
993
993
|
expect(m).modelParsed();
|
|
994
994
|
expect((0, test_translator_1.getExplore)(m.modelDef, 'na').location).toMatchObject(source.locations[0]);
|
|
995
995
|
});
|
|
996
|
-
test('refined
|
|
997
|
-
const source = (0, test_translator_1.markSource) `
|
|
996
|
+
test('refined source location', () => {
|
|
997
|
+
const source = (0, test_translator_1.markSource) `source: ${'na is a {}'}`;
|
|
998
998
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
999
999
|
expect(m).modelParsed();
|
|
1000
1000
|
expect((0, test_translator_1.getExplore)(m.modelDef, 'na').location).toMatchObject(source.locations[0]);
|
|
1001
1001
|
});
|
|
1002
1002
|
test('location of defined dimension', () => {
|
|
1003
|
-
const source = (0, test_translator_1.markSource) `
|
|
1003
|
+
const source = (0, test_translator_1.markSource) `source: na is a { dimension: ${'x is 1'} }`;
|
|
1004
1004
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1005
1005
|
expect(m).modelCompiled();
|
|
1006
1006
|
const na = (0, test_translator_1.getExplore)(m.modelDef, 'na');
|
|
@@ -1008,7 +1008,7 @@ describe('source locations', () => {
|
|
|
1008
1008
|
expect(x.location).toMatchObject(source.locations[0]);
|
|
1009
1009
|
});
|
|
1010
1010
|
test('location of defined measure', () => {
|
|
1011
|
-
const source = (0, test_translator_1.markSource) `
|
|
1011
|
+
const source = (0, test_translator_1.markSource) `source: na is a { measure: ${'x is count()'} }`;
|
|
1012
1012
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1013
1013
|
expect(m).modelCompiled();
|
|
1014
1014
|
const na = (0, test_translator_1.getExplore)(m.modelDef, 'na');
|
|
@@ -1016,7 +1016,7 @@ describe('source locations', () => {
|
|
|
1016
1016
|
expect(x.location).toMatchObject(source.locations[0]);
|
|
1017
1017
|
});
|
|
1018
1018
|
test('location of defined query', () => {
|
|
1019
|
-
const source = (0, test_translator_1.markSource) `
|
|
1019
|
+
const source = (0, test_translator_1.markSource) `source: na is a { query: ${'x is { group_by: y is 1 }'} }`;
|
|
1020
1020
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1021
1021
|
expect(m).modelCompiled();
|
|
1022
1022
|
const na = (0, test_translator_1.getExplore)(m.modelDef, 'na');
|
|
@@ -1025,7 +1025,7 @@ describe('source locations', () => {
|
|
|
1025
1025
|
});
|
|
1026
1026
|
test('location of defined field inside a query', () => {
|
|
1027
1027
|
const source = (0, test_translator_1.markSource) `
|
|
1028
|
-
|
|
1028
|
+
source: na is a {
|
|
1029
1029
|
query: x is {
|
|
1030
1030
|
group_by: ${'y is 1'}
|
|
1031
1031
|
}
|
|
@@ -1039,7 +1039,7 @@ describe('source locations', () => {
|
|
|
1039
1039
|
});
|
|
1040
1040
|
test('location of filtered field inside a query', () => {
|
|
1041
1041
|
const source = (0, test_translator_1.markSource) `
|
|
1042
|
-
|
|
1042
|
+
source: na is a {
|
|
1043
1043
|
measure: y is count()
|
|
1044
1044
|
query: x is {
|
|
1045
1045
|
group_by: ${'z is y { where: true }'}
|
|
@@ -1053,7 +1053,7 @@ describe('source locations', () => {
|
|
|
1053
1053
|
expect(z.location).toMatchObject(source.locations[0]);
|
|
1054
1054
|
});
|
|
1055
1055
|
test('location of field inherited from table', () => {
|
|
1056
|
-
const source = (0, test_translator_1.markSource) `
|
|
1056
|
+
const source = (0, test_translator_1.markSource) `source: na is ${"table('aTable')"}`;
|
|
1057
1057
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1058
1058
|
expect(m).modelCompiled();
|
|
1059
1059
|
const na = (0, test_translator_1.getExplore)(m.modelDef, 'na');
|
|
@@ -1063,7 +1063,7 @@ describe('source locations', () => {
|
|
|
1063
1063
|
test('location of field inherited from sql block', () => {
|
|
1064
1064
|
const source = (0, test_translator_1.markSource) `--- comment
|
|
1065
1065
|
sql: s is { select: ${'"""SELECT 1 as one """'} }
|
|
1066
|
-
|
|
1066
|
+
source: na is from_sql(s)
|
|
1067
1067
|
`;
|
|
1068
1068
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1069
1069
|
expect(m).modelParsed();
|
|
@@ -1081,7 +1081,7 @@ describe('source locations', () => {
|
|
|
1081
1081
|
});
|
|
1082
1082
|
test('location of fields inherited from a query', () => {
|
|
1083
1083
|
const source = (0, test_translator_1.markSource) `
|
|
1084
|
-
|
|
1084
|
+
source: na is from(
|
|
1085
1085
|
${"table('aTable')"} -> {
|
|
1086
1086
|
group_by:
|
|
1087
1087
|
abool
|
|
@@ -1129,7 +1129,7 @@ describe('source locations', () => {
|
|
|
1129
1129
|
});
|
|
1130
1130
|
test('location of renamed field', () => {
|
|
1131
1131
|
const source = (0, test_translator_1.markSource) `
|
|
1132
|
-
|
|
1132
|
+
source: na is a {
|
|
1133
1133
|
rename: ${'bbool is abool'}
|
|
1134
1134
|
}
|
|
1135
1135
|
`;
|
|
@@ -1141,7 +1141,7 @@ describe('source locations', () => {
|
|
|
1141
1141
|
});
|
|
1142
1142
|
test('location of join on', () => {
|
|
1143
1143
|
const source = (0, test_translator_1.markSource) `
|
|
1144
|
-
|
|
1144
|
+
source: na is a {
|
|
1145
1145
|
join_one: ${'x is a { primary_key: abool } on abool'}
|
|
1146
1146
|
}
|
|
1147
1147
|
`;
|
|
@@ -1153,7 +1153,7 @@ describe('source locations', () => {
|
|
|
1153
1153
|
});
|
|
1154
1154
|
test('location of join with', () => {
|
|
1155
1155
|
const source = (0, test_translator_1.markSource) `
|
|
1156
|
-
|
|
1156
|
+
source: na is a {
|
|
1157
1157
|
join_one: ${'x is a { primary_key: astr } with astr'}
|
|
1158
1158
|
}
|
|
1159
1159
|
`;
|
|
@@ -1165,7 +1165,7 @@ describe('source locations', () => {
|
|
|
1165
1165
|
});
|
|
1166
1166
|
test('location of field in join', () => {
|
|
1167
1167
|
const source = (0, test_translator_1.markSource) `
|
|
1168
|
-
|
|
1168
|
+
source: na is a {
|
|
1169
1169
|
join_one: x is a {
|
|
1170
1170
|
primary_key: abool
|
|
1171
1171
|
dimension: ${'y is 1'}
|
|
@@ -1196,7 +1196,7 @@ describe('source locations', () => {
|
|
|
1196
1196
|
describe('source references', () => {
|
|
1197
1197
|
test('reference to explore', () => {
|
|
1198
1198
|
const source = (0, test_translator_1.markSource) `
|
|
1199
|
-
|
|
1199
|
+
source: ${'na is a'}
|
|
1200
1200
|
query: ${'na'} -> { project: * }
|
|
1201
1201
|
`;
|
|
1202
1202
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1212,7 +1212,7 @@ describe('source references', () => {
|
|
|
1212
1212
|
});
|
|
1213
1213
|
test('reference to query in query', () => {
|
|
1214
1214
|
const source = (0, test_translator_1.markSource) `
|
|
1215
|
-
|
|
1215
|
+
source: t is a {
|
|
1216
1216
|
query: ${'q is { project: * }'}
|
|
1217
1217
|
}
|
|
1218
1218
|
query: t -> ${'q'}
|
|
@@ -1230,7 +1230,7 @@ describe('source references', () => {
|
|
|
1230
1230
|
});
|
|
1231
1231
|
test('reference to query in query (version 2)', () => {
|
|
1232
1232
|
const source = (0, test_translator_1.markSource) `
|
|
1233
|
-
|
|
1233
|
+
source: na is a { query: ${'x is { group_by: y is 1 }'} }
|
|
1234
1234
|
query: na -> ${'x'}
|
|
1235
1235
|
`;
|
|
1236
1236
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1247,7 +1247,7 @@ describe('source references', () => {
|
|
|
1247
1247
|
test('reference to sql block', () => {
|
|
1248
1248
|
const source = (0, test_translator_1.markSource) `
|
|
1249
1249
|
${'sql: s is {select:"""SELECT 1 as one"""}'}
|
|
1250
|
-
|
|
1250
|
+
source: na is from_sql(${'s'})
|
|
1251
1251
|
`;
|
|
1252
1252
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1253
1253
|
expect(m).modelParsed();
|
|
@@ -1273,7 +1273,7 @@ describe('source references', () => {
|
|
|
1273
1273
|
test('reference to query in from', () => {
|
|
1274
1274
|
const source = (0, test_translator_1.markSource) `
|
|
1275
1275
|
query: ${'q is a -> { project: * }'}
|
|
1276
|
-
|
|
1276
|
+
source: na is from(-> ${'q'})
|
|
1277
1277
|
`;
|
|
1278
1278
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1279
1279
|
expect(m).modelCompiled();
|
|
@@ -1320,7 +1320,7 @@ describe('source references', () => {
|
|
|
1320
1320
|
});
|
|
1321
1321
|
test('reference to field in expression', () => {
|
|
1322
1322
|
const source = (0, test_translator_1.markSource) `
|
|
1323
|
-
|
|
1323
|
+
source: na is ${"table('aTable')"}
|
|
1324
1324
|
query: na -> { project: bbool is not ${'abool'} }
|
|
1325
1325
|
`;
|
|
1326
1326
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1336,7 +1336,7 @@ describe('source references', () => {
|
|
|
1336
1336
|
});
|
|
1337
1337
|
test('reference to quoted field in expression', () => {
|
|
1338
1338
|
const source = (0, test_translator_1.markSource) `
|
|
1339
|
-
|
|
1339
|
+
source: na is a {
|
|
1340
1340
|
dimension: ${"`name` is 'name'"}
|
|
1341
1341
|
}
|
|
1342
1342
|
query: na -> { project: ${'`name`'} }
|
|
@@ -1354,7 +1354,7 @@ describe('source references', () => {
|
|
|
1354
1354
|
});
|
|
1355
1355
|
test('reference to joined field in expression', () => {
|
|
1356
1356
|
const source = (0, test_translator_1.markSource) `
|
|
1357
|
-
|
|
1357
|
+
source: na is a {
|
|
1358
1358
|
join_one: self is ${"table('aTable')"}
|
|
1359
1359
|
on astr = self.astr
|
|
1360
1360
|
}
|
|
@@ -1373,7 +1373,7 @@ describe('source references', () => {
|
|
|
1373
1373
|
});
|
|
1374
1374
|
test('reference to joined join in expression', () => {
|
|
1375
1375
|
const source = (0, test_translator_1.markSource) `
|
|
1376
|
-
|
|
1376
|
+
source: na is a {
|
|
1377
1377
|
join_one: ${'self is a on astr = self.astr'}
|
|
1378
1378
|
}
|
|
1379
1379
|
query: na -> { project: bstr is ${'self'}.astr }
|
|
@@ -1406,7 +1406,7 @@ describe('source references', () => {
|
|
|
1406
1406
|
});
|
|
1407
1407
|
test('reference to field not in expression (project)', () => {
|
|
1408
1408
|
const source = (0, test_translator_1.markSource) `
|
|
1409
|
-
|
|
1409
|
+
source: na is ${"table('aTable')"}
|
|
1410
1410
|
query: na -> { project: ${'abool'} }
|
|
1411
1411
|
`;
|
|
1412
1412
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1476,7 +1476,7 @@ describe('source references', () => {
|
|
|
1476
1476
|
});
|
|
1477
1477
|
test('reference to field in measure', () => {
|
|
1478
1478
|
const source = (0, test_translator_1.markSource) `
|
|
1479
|
-
|
|
1479
|
+
source: e is a {
|
|
1480
1480
|
measure: ${'c is count()'}
|
|
1481
1481
|
measure: c2 is ${'c'}
|
|
1482
1482
|
}
|
|
@@ -1548,7 +1548,7 @@ describe('source references', () => {
|
|
|
1548
1548
|
});
|
|
1549
1549
|
test('reference to field in aggregate source', () => {
|
|
1550
1550
|
const source = (0, test_translator_1.markSource) `
|
|
1551
|
-
|
|
1551
|
+
source: na is ${"table('aTable')"}
|
|
1552
1552
|
query: na -> { aggregate: ai_sum is ${'ai'}.sum() }
|
|
1553
1553
|
`;
|
|
1554
1554
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1567,7 +1567,7 @@ describe('source references', () => {
|
|
|
1567
1567
|
}
|
|
1568
1568
|
test('reference to join in aggregate source', () => {
|
|
1569
1569
|
const source = (0, test_translator_1.markSource) `
|
|
1570
|
-
|
|
1570
|
+
source: na is a {
|
|
1571
1571
|
join_one: ${'self is a on astr = self.astr'}
|
|
1572
1572
|
}
|
|
1573
1573
|
query: na -> { aggregate: ai_sum is ${'self'}.sum(self.ai) }
|
|
@@ -1585,7 +1585,7 @@ describe('source references', () => {
|
|
|
1585
1585
|
});
|
|
1586
1586
|
test('reference to join in aggregate in expr', () => {
|
|
1587
1587
|
const source = (0, test_translator_1.markSource) `
|
|
1588
|
-
|
|
1588
|
+
source: na is a {
|
|
1589
1589
|
join_one: ${'self is a on astr = self.astr'}
|
|
1590
1590
|
}
|
|
1591
1591
|
query: na -> { aggregate: ai_sum is self.sum(${'self'}.ai) }
|
|
@@ -1601,10 +1601,10 @@ describe('source references', () => {
|
|
|
1601
1601
|
},
|
|
1602
1602
|
});
|
|
1603
1603
|
});
|
|
1604
|
-
test('reference to
|
|
1604
|
+
test('reference to sourcein join', () => {
|
|
1605
1605
|
const source = (0, test_translator_1.markSource) `
|
|
1606
|
-
|
|
1607
|
-
|
|
1606
|
+
source: ${'exp1 is a'}
|
|
1607
|
+
source: exp2 is a {
|
|
1608
1608
|
join_one: ${'exp1'} on astr = exp1.astr
|
|
1609
1609
|
}
|
|
1610
1610
|
`;
|
|
@@ -1621,7 +1621,7 @@ describe('source references', () => {
|
|
|
1621
1621
|
});
|
|
1622
1622
|
test('reference to field in aggregate (in expr)', () => {
|
|
1623
1623
|
const source = (0, test_translator_1.markSource) `
|
|
1624
|
-
|
|
1624
|
+
source: na is ${"table('aTable')"}
|
|
1625
1625
|
query: na -> { aggregate: ai_sum is sum(${'ai'}) }
|
|
1626
1626
|
`;
|
|
1627
1627
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
@@ -1637,7 +1637,7 @@ describe('source references', () => {
|
|
|
1637
1637
|
});
|
|
1638
1638
|
test('reference to field in rename', () => {
|
|
1639
1639
|
const source = (0, test_translator_1.markSource) `
|
|
1640
|
-
|
|
1640
|
+
source: na is ${"table('aTable')"} {
|
|
1641
1641
|
rename: bbool is ${'abool'}
|
|
1642
1642
|
}
|
|
1643
1643
|
`;
|
|
@@ -1654,8 +1654,8 @@ describe('source references', () => {
|
|
|
1654
1654
|
});
|
|
1655
1655
|
test('reference to field in join with', () => {
|
|
1656
1656
|
const source = (0, test_translator_1.markSource) `
|
|
1657
|
-
|
|
1658
|
-
|
|
1657
|
+
source: exp1 is a { primary_key: astr }
|
|
1658
|
+
source: exp2 is ${"table('aTable')"} {
|
|
1659
1659
|
join_one: exp1 with ${'astr'}
|
|
1660
1660
|
}
|
|
1661
1661
|
`;
|
|
@@ -1702,7 +1702,7 @@ describe('translation need error locations', () => {
|
|
|
1702
1702
|
});
|
|
1703
1703
|
test('table struct error location', () => {
|
|
1704
1704
|
const source = (0, test_translator_1.markSource) `
|
|
1705
|
-
|
|
1705
|
+
source: bad_explore is ${"table('malloy-data.bad.table')"}
|
|
1706
1706
|
`;
|
|
1707
1707
|
const m = new test_translator_1.TestTranslator(source.code);
|
|
1708
1708
|
const result = m.translate();
|
|
@@ -1719,7 +1719,7 @@ describe('translation need error locations', () => {
|
|
|
1719
1719
|
});
|
|
1720
1720
|
describe('pipeline comprehension', () => {
|
|
1721
1721
|
test('second query gets namespace from first', modelOK(`
|
|
1722
|
-
|
|
1722
|
+
source: aq is a {
|
|
1723
1723
|
query: t1 is {
|
|
1724
1724
|
group_by: t1int is ai, t1str is astr
|
|
1725
1725
|
} -> {
|
|
@@ -1728,7 +1728,7 @@ describe('pipeline comprehension', () => {
|
|
|
1728
1728
|
}
|
|
1729
1729
|
`));
|
|
1730
1730
|
test("second query doesn't have access to original fields", badModel((0, test_translator_1.markSource) `
|
|
1731
|
-
|
|
1731
|
+
source: aq is a {
|
|
1732
1732
|
query: t1 is {
|
|
1733
1733
|
group_by: t1int is ai, t1str is astr
|
|
1734
1734
|
} -> {
|
|
@@ -1737,7 +1737,7 @@ describe('pipeline comprehension', () => {
|
|
|
1737
1737
|
}
|
|
1738
1738
|
`, "'ai' is not defined"));
|
|
1739
1739
|
test('new query can append ops to existing query', modelOK(`
|
|
1740
|
-
|
|
1740
|
+
source: aq is a {
|
|
1741
1741
|
query: t0 is {
|
|
1742
1742
|
group_by: t1int is ai, t1str is astr
|
|
1743
1743
|
}
|
|
@@ -1747,7 +1747,7 @@ describe('pipeline comprehension', () => {
|
|
|
1747
1747
|
}
|
|
1748
1748
|
`));
|
|
1749
1749
|
test('new query can refine and append to exisiting query', modelOK(`
|
|
1750
|
-
|
|
1750
|
+
source: aq is table('aTable') {
|
|
1751
1751
|
query: by_region is { group_by: astr }
|
|
1752
1752
|
query: by_region2 is by_region {
|
|
1753
1753
|
nest: dateNest is { group_by: ad }
|
|
@@ -1762,9 +1762,9 @@ describe('pipeline comprehension', () => {
|
|
|
1762
1762
|
nest: aturtle { limit: 1 }
|
|
1763
1763
|
}
|
|
1764
1764
|
`));
|
|
1765
|
-
test('Querying an
|
|
1765
|
+
test('Querying an sourcebased on a query', modelOK(`
|
|
1766
1766
|
query: q is a -> { group_by: astr; aggregate: strsum is ai.sum() }
|
|
1767
|
-
|
|
1767
|
+
source: aq is a {
|
|
1768
1768
|
join_one: aq is from(->q) on astr = aq.astr
|
|
1769
1769
|
}
|
|
1770
1770
|
query: aqf is aq -> { project: * }
|
|
@@ -108,7 +108,7 @@ describe('sql:', () => {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
});
|
|
111
|
-
test('
|
|
111
|
+
test('source from imported sql-based-source', () => {
|
|
112
112
|
const createModel = `
|
|
113
113
|
sql: users IS { select: """${selStmt}""" }
|
|
114
114
|
source: malloyUsers is from_sql(users) { primary_key: ai }
|
|
@@ -161,7 +161,7 @@ describe('sql:', () => {
|
|
|
161
161
|
model.update({ compileSQL: { [sql.name]: makeSchemaResponse(sql) } });
|
|
162
162
|
expect(model).modelCompiled();
|
|
163
163
|
});
|
|
164
|
-
test('
|
|
164
|
+
test('source from extended sql-based-source', () => {
|
|
165
165
|
var _a, _b;
|
|
166
166
|
const model = new test_translator_1.TestTranslator(`
|
|
167
167
|
sql: sql_block IS { select: """${selStmt}""" }
|
|
@@ -307,7 +307,7 @@ class TestTranslator extends parse_malloy_1.MalloyTranslator {
|
|
|
307
307
|
if (explore && explore.type === 'struct') {
|
|
308
308
|
return explore;
|
|
309
309
|
}
|
|
310
|
-
throw new Error(`Expected model to contain
|
|
310
|
+
throw new Error(`Expected model to contain source '${exploreName}'`);
|
|
311
311
|
}
|
|
312
312
|
compile() {
|
|
313
313
|
const compileTo = this.translate();
|
package/dist/malloy.js
CHANGED
|
@@ -1305,7 +1305,7 @@ class ExploreField extends Explore {
|
|
|
1305
1305
|
case 'nested':
|
|
1306
1306
|
return JoinRelationship.ManyToOne;
|
|
1307
1307
|
default:
|
|
1308
|
-
throw new Error('
|
|
1308
|
+
throw new Error('A source field must have a join relationship.');
|
|
1309
1309
|
}
|
|
1310
1310
|
}
|
|
1311
1311
|
isQueryField() {
|
|
@@ -1286,13 +1286,13 @@ class QueryQuery extends QueryField {
|
|
|
1286
1286
|
while (path.length > 0 && (pathElementName = path.shift())) {
|
|
1287
1287
|
const structNode = struct.getChildByName(pathElementName);
|
|
1288
1288
|
if (structNode === undefined) {
|
|
1289
|
-
throw new Error(`Nested
|
|
1289
|
+
throw new Error(`Nested source not found '${pathElementName}'`);
|
|
1290
1290
|
}
|
|
1291
1291
|
if (structNode instanceof QueryStruct) {
|
|
1292
1292
|
struct = structNode;
|
|
1293
1293
|
}
|
|
1294
1294
|
else {
|
|
1295
|
-
throw new Error(`'${pathElementName}' is not
|
|
1295
|
+
throw new Error(`'${pathElementName}' is not a source object`);
|
|
1296
1296
|
}
|
|
1297
1297
|
}
|
|
1298
1298
|
ret = ret.concat(this.expandWildCardStruct(struct, expandChildren, filter));
|