@malloydata/malloy 0.0.237-dev250225015031 → 0.0.237-dev250225213433
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/annotation.d.ts +15 -0
- package/dist/annotation.js +86 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -3
- package/dist/lang/ast/types/annotation-elements.d.ts +1 -1
- package/dist/lang/ast/types/annotation-elements.js +2 -2
- package/dist/lang/ast/types/malloy-element.d.ts +1 -1
- package/dist/lang/ast/types/malloy-element.js +2 -2
- package/dist/lang/malloy-to-ast.d.ts +1 -1
- package/dist/lang/malloy-to-ast.js +2 -2
- package/dist/lang/parse-malloy.d.ts +1 -1
- package/dist/lang/parse-malloy.js +4 -3
- package/dist/lang/parse-utils.d.ts +0 -11
- package/dist/lang/parse-utils.js +4 -82
- package/dist/lang/syntax-errors/custom-error-messages.d.ts +4 -2
- package/dist/lang/syntax-errors/custom-error-messages.js +75 -16
- package/dist/lang/syntax-errors/malloy-error-strategy.d.ts +4 -6
- package/dist/lang/syntax-errors/malloy-error-strategy.js +3 -22
- package/dist/lang/syntax-errors/malloy-parser-error-listener.d.ts +1 -1
- package/dist/lang/syntax-errors/malloy-parser-error-listener.js +107 -10
- package/dist/lang/test/literals.spec.js +0 -34
- package/dist/lang/test/syntax-errors.spec.js +113 -59
- package/dist/malloy.d.ts +13 -8
- package/dist/malloy.js +23 -23
- package/dist/model/malloy_query.d.ts +3 -1
- package/dist/model/malloy_query.js +18 -3
- package/dist/model/materialization/utils.js +2 -2
- package/dist/to_stable.d.ts +3 -0
- package/dist/to_stable.js +170 -0
- package/package.json +3 -1
- package/dist/lang/lib/Malloy/MalloyTagLexer.d.ts +0 -42
- package/dist/lang/lib/Malloy/MalloyTagLexer.js +0 -385
- package/dist/lang/lib/Malloy/MalloyTagParser.d.ts +0 -180
- package/dist/lang/lib/Malloy/MalloyTagParser.js +0 -1051
- package/dist/lang/lib/Malloy/MalloyTagVisitor.d.ts +0 -120
- package/dist/lang/lib/Malloy/MalloyTagVisitor.js +0 -4
- package/dist/tags.d.ts +0 -72
- package/dist/tags.js +0 -512
|
@@ -6,11 +6,19 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.MalloyParserErrorListener = exports.
|
|
9
|
+
exports.MalloyParserErrorListener = exports.malloyCustomErrorCases = void 0;
|
|
10
10
|
const MalloyParser_1 = require("../lib/Malloy/MalloyParser");
|
|
11
11
|
const custom_error_messages_1 = require("./custom-error-messages");
|
|
12
12
|
const parse_log_1 = require("../parse-log");
|
|
13
|
-
|
|
13
|
+
// A set of custom error messages and their triggering cases,
|
|
14
|
+
// used for syntax error message re-writing when ANTLR would
|
|
15
|
+
// otherwise print a standard (and not very useful) error message.
|
|
16
|
+
//
|
|
17
|
+
// Most Malloy errors are detected and generated in language elements
|
|
18
|
+
// inside `src/lang/ast`. These custom error messages are used to
|
|
19
|
+
// cover a variety of cases that are not as straightforward to
|
|
20
|
+
// catch in the AST.
|
|
21
|
+
exports.malloyCustomErrorCases = [
|
|
14
22
|
{
|
|
15
23
|
errorMessage: "'view:' must be followed by '<identifier> is {'",
|
|
16
24
|
ruleContextOptions: ['exploreQueryDef'],
|
|
@@ -18,7 +26,7 @@ exports.commonErrorCases = [
|
|
|
18
26
|
precedingTokenOptions: [[MalloyParser_1.MalloyParser.VIEW], [MalloyParser_1.MalloyParser.COLON]],
|
|
19
27
|
},
|
|
20
28
|
{
|
|
21
|
-
errorMessage: "Missing '}' at '${
|
|
29
|
+
errorMessage: "Missing '}' at '${offendingSymbol}'",
|
|
22
30
|
ruleContextOptions: ['vExpr'],
|
|
23
31
|
offendingSymbol: MalloyParser_1.MalloyParser.VIEW,
|
|
24
32
|
currentToken: MalloyParser_1.MalloyParser.OCURLY,
|
|
@@ -30,17 +38,106 @@ exports.commonErrorCases = [
|
|
|
30
38
|
'queryProperties',
|
|
31
39
|
'exploreStatement',
|
|
32
40
|
],
|
|
33
|
-
|
|
34
|
-
[MalloyParser_1.MalloyParser.EOF],
|
|
35
|
-
[MalloyParser_1.MalloyParser.RUN],
|
|
36
|
-
[MalloyParser_1.MalloyParser.SOURCE],
|
|
37
|
-
],
|
|
41
|
+
offendingSymbolTextOptions: ['<eof>', 'run:', 'source:'],
|
|
38
42
|
},
|
|
39
43
|
{
|
|
40
44
|
errorMessage: "'aggregate:' entries must include a name (ex: `some_name is count()`)",
|
|
41
45
|
precedingTokenOptions: [[MalloyParser_1.MalloyParser.AGGREGATE]],
|
|
42
46
|
lookAheadOptions: [[-MalloyParser_1.MalloyParser.IS]],
|
|
43
|
-
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
errorMessage: "Expected ':' following 'source'",
|
|
50
|
+
offendingSymbol: MalloyParser_1.MalloyParser.SOURCE_KW,
|
|
51
|
+
ruleContextOptions: ['malloyDocument'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
errorMessage: "Expected ':' following '${offendingSymbol}'",
|
|
55
|
+
offendingSymbolTextOptions: [
|
|
56
|
+
'dimension',
|
|
57
|
+
'measure',
|
|
58
|
+
'where',
|
|
59
|
+
'declare',
|
|
60
|
+
'join_one',
|
|
61
|
+
'join_many',
|
|
62
|
+
'join_cross',
|
|
63
|
+
'primary_key',
|
|
64
|
+
],
|
|
65
|
+
ruleContextOptions: ['exploreStatement'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
errorMessage: "Expected 'is' or '(' following identifier '${previousToken}'",
|
|
69
|
+
ruleContextOptions: ['sourceDefinition'],
|
|
70
|
+
lookbackSiblingRuleOptions: [
|
|
71
|
+
MalloyParser_1.MalloyParser.RULE_sourceNameDef,
|
|
72
|
+
MalloyParser_1.MalloyParser.RULE_sourceParameters,
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
errorMessage: "Unexpected '{' following source expression. Expected: 'extend', 'include', '+' or '->'",
|
|
77
|
+
offendingSymbol: MalloyParser_1.MalloyParser.OCURLY,
|
|
78
|
+
ruleContextOptions: ['malloyDocument'],
|
|
79
|
+
predecessorHasAncestorRule: MalloyParser_1.MalloyParser.RULE_sqExplore,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
errorMessage: "Unexpected 'join:'. Did you mean 'join_one:', 'join_many:' or 'join_cross:'?",
|
|
83
|
+
ruleContextOptions: ['exploreStatement'],
|
|
84
|
+
offendingSymbolTextOptions: ['join'],
|
|
85
|
+
lookAheadOptions: [[MalloyParser_1.MalloyParser.COLON]],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
errorMessage: "Unexpected '${offendingSymbol}'. Did you mean 'primary_key:'?",
|
|
89
|
+
ruleContextOptions: ['exploreStatement'],
|
|
90
|
+
offendingSymbolTextOptions: ['primarykey', 'primary'],
|
|
91
|
+
lookAheadOptions: [
|
|
92
|
+
[MalloyParser_1.MalloyParser.COLON],
|
|
93
|
+
['key', MalloyParser_1.MalloyParser.COLON],
|
|
94
|
+
['key', MalloyParser_1.MalloyParser.IDENTIFIER],
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
errorMessage: "Unexpected '${offendingSymbol}'. Did you mean 'group_by:'?",
|
|
99
|
+
ruleContextOptions: ['queryStatement'],
|
|
100
|
+
offendingSymbolTextOptions: ['groupby', 'group'],
|
|
101
|
+
lookAheadOptions: [
|
|
102
|
+
[MalloyParser_1.MalloyParser.COLON],
|
|
103
|
+
['by', MalloyParser_1.MalloyParser.COLON],
|
|
104
|
+
['by', MalloyParser_1.MalloyParser.IDENTIFIER],
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
errorMessage: "Unexpected '${offendingSymbol}'. Did you mean 'order_by:'?",
|
|
109
|
+
ruleContextOptions: ['queryStatement'],
|
|
110
|
+
offendingSymbolTextOptions: ['orderby', 'order'],
|
|
111
|
+
lookAheadOptions: [
|
|
112
|
+
[MalloyParser_1.MalloyParser.COLON],
|
|
113
|
+
['by', MalloyParser_1.MalloyParser.COLON],
|
|
114
|
+
['by', MalloyParser_1.MalloyParser.IDENTIFIER],
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
errorMessage: "Expected ':' following '${offendingSymbol}'",
|
|
119
|
+
offendingSymbolTextOptions: [
|
|
120
|
+
'group_by',
|
|
121
|
+
'declare',
|
|
122
|
+
'join_one',
|
|
123
|
+
'join_many',
|
|
124
|
+
'join_cross',
|
|
125
|
+
'extend',
|
|
126
|
+
'select',
|
|
127
|
+
'project',
|
|
128
|
+
'index',
|
|
129
|
+
'aggregate',
|
|
130
|
+
'calculate',
|
|
131
|
+
'top',
|
|
132
|
+
'limit',
|
|
133
|
+
'order_by',
|
|
134
|
+
'where',
|
|
135
|
+
'having',
|
|
136
|
+
'nest',
|
|
137
|
+
'sample',
|
|
138
|
+
'timezone',
|
|
139
|
+
],
|
|
140
|
+
ruleContextOptions: ['queryStatement'],
|
|
44
141
|
},
|
|
45
142
|
];
|
|
46
143
|
class MalloyParserErrorListener {
|
|
@@ -57,7 +154,7 @@ class MalloyParserErrorListener {
|
|
|
57
154
|
const range = offendingSymbol
|
|
58
155
|
? this.translator.rangeFromToken(offendingSymbol)
|
|
59
156
|
: { start: errAt, end: errAt };
|
|
60
|
-
const overrideMessage = (0, custom_error_messages_1.checkCustomErrorMessage)(recognizer, offendingSymbol, exports.
|
|
157
|
+
const overrideMessage = (0, custom_error_messages_1.checkCustomErrorMessage)(recognizer, offendingSymbol, exports.malloyCustomErrorCases);
|
|
61
158
|
if (overrideMessage) {
|
|
62
159
|
message = overrideMessage;
|
|
63
160
|
}
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
const test_translator_1 = require("./test-translator");
|
|
26
|
-
const parse_utils_1 = require("../parse-utils");
|
|
27
26
|
require("./parse-expects");
|
|
28
27
|
const granular_result_1 = require("../ast/types/granular-result");
|
|
29
28
|
describe('literals', () => {
|
|
@@ -154,39 +153,6 @@ describe('literals', () => {
|
|
|
154
153
|
test('regex', () => {
|
|
155
154
|
expect((0, test_translator_1.expr) `r'RegularExpression'`).toTranslate();
|
|
156
155
|
});
|
|
157
|
-
describe('quote comprehension inside strings', () => {
|
|
158
|
-
test('\\b', () => {
|
|
159
|
-
expect((0, parse_utils_1.parseString)('\\b')).toEqual('\b');
|
|
160
|
-
});
|
|
161
|
-
test('\\f', () => {
|
|
162
|
-
expect((0, parse_utils_1.parseString)('\\f')).toEqual('\f');
|
|
163
|
-
});
|
|
164
|
-
test('\\n', () => {
|
|
165
|
-
expect((0, parse_utils_1.parseString)('\\n')).toEqual('\n');
|
|
166
|
-
});
|
|
167
|
-
test('\\r', () => {
|
|
168
|
-
expect((0, parse_utils_1.parseString)('\\r')).toEqual('\r');
|
|
169
|
-
});
|
|
170
|
-
test('\\t', () => {
|
|
171
|
-
expect((0, parse_utils_1.parseString)('\\t')).toEqual('\t');
|
|
172
|
-
});
|
|
173
|
-
test('unicode ?', () => {
|
|
174
|
-
expect((0, parse_utils_1.parseString)('\\u003f')).toEqual('?');
|
|
175
|
-
expect((0, parse_utils_1.parseString)('\\u003F')).toEqual('?');
|
|
176
|
-
});
|
|
177
|
-
test('normal stuff', () => {
|
|
178
|
-
expect((0, parse_utils_1.parseString)('normal stuff')).toEqual('normal stuff');
|
|
179
|
-
});
|
|
180
|
-
test('stuff & nonsense', () => {
|
|
181
|
-
expect((0, parse_utils_1.parseString)('stuff \\u0026 nonsense')).toEqual('stuff & nonsense');
|
|
182
|
-
});
|
|
183
|
-
test('one thing\\nnext thing', () => {
|
|
184
|
-
expect((0, parse_utils_1.parseString)('one thing\\nnext thing')).toEqual('one thing\nnext thing');
|
|
185
|
-
});
|
|
186
|
-
test('quote stripping works', () => {
|
|
187
|
-
expect((0, parse_utils_1.parseString)('|42|', '|')).toEqual('42');
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
156
|
describe('string parsing in language', () => {
|
|
191
157
|
const tz = 'America/Mexico_City';
|
|
192
158
|
test('multi-line indent increasing', () => {
|
|
@@ -8,62 +8,91 @@
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
const test_translator_1 = require("./test-translator");
|
|
10
10
|
require("./parse-expects");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Unit tests intended to cover the custom error messages defined in
|
|
13
|
+
* malloy-custom-error-messages.ts.
|
|
14
|
+
*
|
|
15
|
+
* These tests are intended to prevent unintended regressions. It is
|
|
16
|
+
* okay to change or remove tests here as long as you are doing so
|
|
17
|
+
* for a good reason.
|
|
18
|
+
*/
|
|
19
|
+
describe('custom error messages', () => {
|
|
20
|
+
describe('source', () => {
|
|
21
|
+
test('missing alias', () => {
|
|
22
|
+
expect('source: x extend { }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected 'is' or '(' following identifier 'x'"));
|
|
23
|
+
});
|
|
24
|
+
test('missing closing curly: EOF', () => {
|
|
25
|
+
expect('source: x is a extend {').toLogAtLeast((0, test_translator_1.errorMessage)("Missing '}' at '<EOF>'"));
|
|
26
|
+
});
|
|
27
|
+
test('source: missing colon in root context', () => {
|
|
28
|
+
expect('source x is a extend { }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'source'"));
|
|
29
|
+
});
|
|
30
|
+
test('opening curly to EOF', () => {
|
|
31
|
+
expect(`
|
|
32
|
+
source: y is x extend {
|
|
33
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("Missing '}' at '<EOF>'"));
|
|
34
|
+
});
|
|
35
|
+
test('expression missing operand before curly', () => {
|
|
36
|
+
expect("source: a is presto.table('malloytest.state_facts') {}").toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected '{' following source expression. Expected: 'extend', 'include', '+' or '->'"));
|
|
37
|
+
});
|
|
38
|
+
test('missing opening curly after source extend keyword', () => {
|
|
39
|
+
expect(`
|
|
40
|
+
source: x is a extend
|
|
41
|
+
primary_key: id
|
|
42
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("missing '{' at 'primary_key:'"));
|
|
43
|
+
});
|
|
14
44
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
45
|
+
describe('exploreProperties', () => {
|
|
46
|
+
test('misspelled "join"', () => {
|
|
47
|
+
expect(`source: x is a extend {
|
|
48
|
+
join: data is y on dataId = data.id
|
|
49
|
+
}`).toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'join:'. Did you mean 'join_one:', 'join_many:' or 'join_cross:'?"));
|
|
50
|
+
expect(`source: x is a extend {
|
|
51
|
+
primary_key: name
|
|
52
|
+
join: data is y on dataId = data.id
|
|
53
|
+
}`).toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'join:'. Did you mean 'join_one:', 'join_many:' or 'join_cross:'?"));
|
|
54
|
+
});
|
|
55
|
+
test('misspelled "primary_key:"', () => {
|
|
56
|
+
expect('source: x is a extend { primaryKey: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'primaryKey'. Did you mean 'primary_key:'?"));
|
|
57
|
+
expect('source: x is a extend { primary key: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'primary'. Did you mean 'primary_key:'?"));
|
|
58
|
+
});
|
|
59
|
+
test('explore statement keyword missing colon', () => {
|
|
60
|
+
expect('source: x is a extend { where x > 5 }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'where'"));
|
|
61
|
+
expect('source: x is a extend { primary_key name }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'primary_key'"));
|
|
62
|
+
expect('source: x is a extend { declare total is value.sum() }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'declare'"));
|
|
63
|
+
});
|
|
64
|
+
test('incorrect opening curly after dimension', () => {
|
|
65
|
+
expect(`
|
|
66
|
+
source: x is a extend {
|
|
67
|
+
dimension: {
|
|
68
|
+
test is best
|
|
69
|
+
}
|
|
20
70
|
}
|
|
21
|
-
|
|
22
|
-
|
|
71
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("extraneous input '{' expecting {BQ_STRING, IDENTIFIER}"));
|
|
72
|
+
});
|
|
23
73
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
74
|
+
describe('view', () => {
|
|
75
|
+
test('view is missing name', () => {
|
|
76
|
+
expect(`
|
|
77
|
+
source: x is a extend { view: {
|
|
78
|
+
group_by: b
|
|
79
|
+
} }
|
|
80
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("'view:' must be followed by '<identifier> is {'"));
|
|
81
|
+
});
|
|
82
|
+
test('missing closing curly, source>view', () => {
|
|
83
|
+
expect(`
|
|
84
|
+
source: x is a extend {
|
|
85
|
+
view: y is {
|
|
86
|
+
group_by: b
|
|
29
87
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
`).toLogAtLeast((0, test_translator_1.errorMessage)("Missing '}' at 'view:'"));
|
|
35
|
-
});
|
|
36
|
-
test('incorrect opening curly after dimension', () => {
|
|
37
|
-
expect(`
|
|
38
|
-
source: x is a extend {
|
|
39
|
-
dimension: {
|
|
40
|
-
test is best
|
|
88
|
+
view: z is {
|
|
89
|
+
group_by: c
|
|
90
|
+
}
|
|
41
91
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(`
|
|
47
|
-
source: x is a extend {
|
|
48
|
-
primarykey: id
|
|
49
|
-
}
|
|
50
|
-
`).toLogAtLeast((0, test_translator_1.errorMessage)("no viable alternative at input 'primarykey'"));
|
|
51
|
-
});
|
|
52
|
-
test('missing opening curly after source extend keyword', () => {
|
|
53
|
-
expect(`
|
|
54
|
-
source: x is a extend
|
|
55
|
-
primary_key: id
|
|
56
|
-
`).toLogAtLeast((0, test_translator_1.errorMessage)("Missing '{' after 'extend'"));
|
|
57
|
-
});
|
|
58
|
-
test('missing alias for aggregate entry', () => {
|
|
59
|
-
expect(`
|
|
60
|
-
run: x -> {
|
|
61
|
-
aggregate: count()
|
|
62
|
-
}
|
|
63
|
-
`).toLogAtLeast((0, test_translator_1.errorMessage)("'aggregate:' entries must include a name (ex: `some_name is count()`)"));
|
|
64
|
-
});
|
|
65
|
-
test('missing alias for aggregate inside source>view', () => {
|
|
66
|
-
expect(`
|
|
92
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("Missing '}' at 'view:'"));
|
|
93
|
+
});
|
|
94
|
+
test('missing alias for aggregate inside source>view', () => {
|
|
95
|
+
expect(`
|
|
67
96
|
source: x is aa extend {
|
|
68
97
|
measure: airport_count is count()
|
|
69
98
|
|
|
@@ -73,16 +102,41 @@ describe('errors', () => {
|
|
|
73
102
|
}
|
|
74
103
|
}
|
|
75
104
|
`).toLogAtLeast((0, test_translator_1.errorMessage)("'aggregate:' entries must include a name (ex: `some_name is count()`)"));
|
|
105
|
+
});
|
|
76
106
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
107
|
+
describe('queryStatement', () => {
|
|
108
|
+
test('misspelled group_by:', () => {
|
|
109
|
+
expect('source: x is a -> { groupBy: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'groupBy'. Did you mean 'group_by:'?"));
|
|
110
|
+
expect('source: x is a -> { group by: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'group'. Did you mean 'group_by:'?"));
|
|
111
|
+
expect('source: x is a -> { group by name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'group'. Did you mean 'group_by:'?"));
|
|
112
|
+
});
|
|
113
|
+
test('misspelled order_by:', () => {
|
|
114
|
+
expect('source: x is a -> { orderBy: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'orderBy'. Did you mean 'order_by:'?"));
|
|
115
|
+
expect('source: x is a -> { order by: name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'order'. Did you mean 'order_by:'?"));
|
|
116
|
+
expect('source: x is a -> { order by name }').toLogAtLeast((0, test_translator_1.errorMessage)("Unexpected 'order'. Did you mean 'order_by:'?"));
|
|
117
|
+
});
|
|
118
|
+
test('query statement keyword missing colon', () => {
|
|
119
|
+
expect('source: x is a -> { group_by x > 5 }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'group_by'"));
|
|
120
|
+
expect('source: x is a -> { declare name is id }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'declare'"));
|
|
121
|
+
expect('source: x is a -> { select * }').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'select'"));
|
|
122
|
+
expect('source: x is a -> { project i, j, k}').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'project'"));
|
|
123
|
+
expect('source: x is a -> { where val > 5}').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'where'"));
|
|
124
|
+
expect('source: x is a -> { order_by name desc, 2 asc}').toLogAtLeast((0, test_translator_1.errorMessage)("Expected ':' following 'order_by'"));
|
|
125
|
+
});
|
|
81
126
|
});
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
127
|
+
describe('run', () => {
|
|
128
|
+
test('missing alias for aggregate entry', () => {
|
|
129
|
+
expect(`
|
|
130
|
+
run: x -> {
|
|
131
|
+
aggregate: count()
|
|
132
|
+
}
|
|
133
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("'aggregate:' entries must include a name (ex: `some_name is count()`)"));
|
|
134
|
+
});
|
|
135
|
+
test('run opening curly to EOF', () => {
|
|
136
|
+
expect(`
|
|
137
|
+
run: x -> {
|
|
138
|
+
`).toLogAtLeast((0, test_translator_1.errorMessage)("Missing '}' at '<EOF>'"));
|
|
139
|
+
});
|
|
86
140
|
});
|
|
87
141
|
});
|
|
88
142
|
//# sourceMappingURL=syntax-errors.spec.js.map
|
package/dist/malloy.d.ts
CHANGED
|
@@ -6,9 +6,14 @@ import { DocumentHelpContext } from './lang/parse-tree-walkers/document-help-con
|
|
|
6
6
|
import { CompiledQuery, DocumentLocation, DocumentReference, BooleanFieldDef, JSONFieldDef, NumberFieldDef, StringFieldDef, FilterCondition, Query as InternalQuery, ModelDef, DocumentPosition as ModelDocumentPosition, NamedQuery, QueryData, QueryDataRow, QueryResult, SearchIndexResult, SearchValueMapResult, StructDef, TurtleDef, NativeUnsupportedFieldDef, QueryRunStats, ImportLocation, Annotation, SQLSentence, SQLSourceDef, AtomicFieldDef, DateFieldDef, TimestampFieldDef, SourceDef, QueryToMaterialize } from './model';
|
|
7
7
|
import { EventStream, InvalidationKey, ModelString, ModelURL, QueryString, QueryURL, URLReader } from './runtime_types';
|
|
8
8
|
import { Connection, FetchSchemaOptions, InfoConnection, LookupConnection } from './connection/types';
|
|
9
|
-
import { Tag
|
|
9
|
+
import { Tag } from '@malloydata/malloy-tag';
|
|
10
10
|
import { Dialect } from './dialect';
|
|
11
11
|
import { PathInfo } from './lang/parse-tree-walkers/find-table-path-walker';
|
|
12
|
+
import { MalloyTagParse, TagParseSpec } from './annotation';
|
|
13
|
+
export interface Taggable {
|
|
14
|
+
tagParse: (spec?: TagParseSpec) => MalloyTagParse;
|
|
15
|
+
getTaglines: (prefix?: RegExp) => string[];
|
|
16
|
+
}
|
|
12
17
|
export interface Loggable {
|
|
13
18
|
debug: (message?: any, ...optionalParams: any[]) => void;
|
|
14
19
|
info: (message?: any, ...optionalParams: any[]) => void;
|
|
@@ -185,7 +190,7 @@ export declare class Model implements Taggable {
|
|
|
185
190
|
_referenceAt: (location: ModelDocumentPosition) => DocumentReference | undefined;
|
|
186
191
|
_importAt: (location: ModelDocumentPosition) => ImportLocation | undefined;
|
|
187
192
|
constructor(modelDef: ModelDef, problems: LogMessage[], fromSources: string[], referenceAt?: (location: ModelDocumentPosition) => DocumentReference | undefined, importAt?: (location: ModelDocumentPosition) => ImportLocation | undefined);
|
|
188
|
-
tagParse(spec?: TagParseSpec):
|
|
193
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
189
194
|
getTaglines(prefix?: RegExp): string[];
|
|
190
195
|
/**
|
|
191
196
|
* Retrieve a document reference for the token at the given position within
|
|
@@ -260,7 +265,7 @@ export declare class PreparedQuery implements Taggable {
|
|
|
260
265
|
_modelDef: ModelDef;
|
|
261
266
|
_query: InternalQuery | NamedQuery;
|
|
262
267
|
constructor(query: InternalQuery, model: ModelDef, problems: LogMessage[], name?: string | undefined);
|
|
263
|
-
tagParse(spec?: TagParseSpec):
|
|
268
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
264
269
|
getTaglines(prefix?: RegExp): string[];
|
|
265
270
|
/**
|
|
266
271
|
* Generate the SQL for this query.
|
|
@@ -457,7 +462,7 @@ export declare class PreparedResult implements Taggable {
|
|
|
457
462
|
protected inner: CompiledQuery;
|
|
458
463
|
constructor(query: CompiledQuery, modelDef: ModelDef);
|
|
459
464
|
static fromJson({ query, modelDef, }: PreparedResultJSON): PreparedResult;
|
|
460
|
-
tagParse(spec?: TagParseSpec):
|
|
465
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
461
466
|
getTaglines(prefix?: RegExp): string[];
|
|
462
467
|
get annotation(): Annotation | undefined;
|
|
463
468
|
get modelAnnotation(): Annotation | undefined;
|
|
@@ -587,7 +592,7 @@ export declare class Explore extends Entity implements Taggable {
|
|
|
587
592
|
get source(): Explore | undefined;
|
|
588
593
|
isIntrinsic(): boolean;
|
|
589
594
|
isExploreField(): this is ExploreField;
|
|
590
|
-
tagParse(spec?: TagParseSpec):
|
|
595
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
591
596
|
getTaglines(prefix?: RegExp): string[];
|
|
592
597
|
private parsedModelTag?;
|
|
593
598
|
get modelTag(): Tag;
|
|
@@ -632,7 +637,7 @@ export declare class AtomicField extends Entity implements Taggable {
|
|
|
632
637
|
protected parent: Explore;
|
|
633
638
|
constructor(fieldTypeDef: AtomicFieldDef, parent: Explore, source?: AtomicField);
|
|
634
639
|
get type(): AtomicFieldType;
|
|
635
|
-
tagParse(spec?: TagParseSpec):
|
|
640
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
636
641
|
getTaglines(prefix?: RegExp): string[];
|
|
637
642
|
isIntrinsic(): boolean;
|
|
638
643
|
isQueryField(): this is QueryField;
|
|
@@ -723,7 +728,7 @@ export declare class Query extends Entity {
|
|
|
723
728
|
export declare class QueryField extends Query implements Taggable {
|
|
724
729
|
protected parent: Explore;
|
|
725
730
|
constructor(turtleDef: TurtleDef, parent: Explore, source?: Query);
|
|
726
|
-
tagParse(spec?: TagParseSpec):
|
|
731
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
727
732
|
getTaglines(prefix?: RegExp): string[];
|
|
728
733
|
isQueryField(): this is QueryField;
|
|
729
734
|
isExploreField(): this is ExploreField;
|
|
@@ -744,7 +749,7 @@ export declare class ExploreField extends Explore {
|
|
|
744
749
|
get joinRelationship(): JoinRelationship;
|
|
745
750
|
get isRecord(): boolean;
|
|
746
751
|
get isArray(): boolean;
|
|
747
|
-
tagParse(spec?: TagParseSpec):
|
|
752
|
+
tagParse(spec?: TagParseSpec): MalloyTagParse;
|
|
748
753
|
isQueryField(): this is QueryField;
|
|
749
754
|
isExploreField(): this is ExploreField;
|
|
750
755
|
isAtomicField(): this is AtomicField;
|
package/dist/malloy.js
CHANGED
|
@@ -26,10 +26,10 @@ exports.InMemoryModelCache = exports.CacheManager = exports.CSVWriter = exports.
|
|
|
26
26
|
const lang_1 = require("./lang");
|
|
27
27
|
const model_1 = require("./model");
|
|
28
28
|
const luxon_1 = require("luxon");
|
|
29
|
-
const tags_1 = require("./tags");
|
|
30
29
|
const dialect_1 = require("./dialect");
|
|
31
30
|
const version_1 = require("./version");
|
|
32
31
|
const uuid_1 = require("uuid");
|
|
32
|
+
const annotation_1 = require("./annotation");
|
|
33
33
|
const MALLOY_INTERNAL_URL = 'internal://internal.malloy';
|
|
34
34
|
class Malloy {
|
|
35
35
|
static get version() {
|
|
@@ -446,10 +446,10 @@ class Model {
|
|
|
446
446
|
this._importAt = importAt;
|
|
447
447
|
}
|
|
448
448
|
tagParse(spec) {
|
|
449
|
-
return
|
|
449
|
+
return (0, annotation_1.annotationToTag)(this.modelDef.annotation, spec);
|
|
450
450
|
}
|
|
451
451
|
getTaglines(prefix) {
|
|
452
|
-
return
|
|
452
|
+
return (0, annotation_1.annotationToTaglines)(this.modelDef.annotation, prefix);
|
|
453
453
|
}
|
|
454
454
|
/**
|
|
455
455
|
* Retrieve a document reference for the token at the given position within
|
|
@@ -569,12 +569,12 @@ class PreparedQuery {
|
|
|
569
569
|
this._modelDef = model;
|
|
570
570
|
}
|
|
571
571
|
tagParse(spec) {
|
|
572
|
-
const modelScope =
|
|
573
|
-
spec =
|
|
574
|
-
return
|
|
572
|
+
const modelScope = (0, annotation_1.annotationToTag)(this._modelDef.annotation).tag;
|
|
573
|
+
spec = (0, annotation_1.addModelScope)(spec, modelScope);
|
|
574
|
+
return (0, annotation_1.annotationToTag)(this._query.annotation, spec);
|
|
575
575
|
}
|
|
576
576
|
getTaglines(prefix) {
|
|
577
|
-
return
|
|
577
|
+
return (0, annotation_1.annotationToTaglines)(this._query.annotation, prefix);
|
|
578
578
|
}
|
|
579
579
|
/**
|
|
580
580
|
* Generate the SQL for this query.
|
|
@@ -831,12 +831,12 @@ class PreparedResult {
|
|
|
831
831
|
return new PreparedResult(query, modelDef);
|
|
832
832
|
}
|
|
833
833
|
tagParse(spec) {
|
|
834
|
-
const modelScope =
|
|
835
|
-
spec =
|
|
836
|
-
return
|
|
834
|
+
const modelScope = (0, annotation_1.annotationToTag)(this.modelDef.annotation).tag;
|
|
835
|
+
spec = (0, annotation_1.addModelScope)(spec, modelScope);
|
|
836
|
+
return (0, annotation_1.annotationToTag)(this.inner.annotation, spec);
|
|
837
837
|
}
|
|
838
838
|
getTaglines(prefix) {
|
|
839
|
-
return
|
|
839
|
+
return (0, annotation_1.annotationToTaglines)(this.inner.annotation, prefix);
|
|
840
840
|
}
|
|
841
841
|
get annotation() {
|
|
842
842
|
return this.inner.annotation;
|
|
@@ -845,7 +845,7 @@ class PreparedResult {
|
|
|
845
845
|
return this.modelDef.annotation;
|
|
846
846
|
}
|
|
847
847
|
get modelTag() {
|
|
848
|
-
return
|
|
848
|
+
return (0, annotation_1.annotationToTag)(this.modelDef.annotation).tag;
|
|
849
849
|
}
|
|
850
850
|
/**
|
|
851
851
|
* @return The name of the connection this query should be run against.
|
|
@@ -1096,13 +1096,13 @@ class Explore extends Entity {
|
|
|
1096
1096
|
return false;
|
|
1097
1097
|
}
|
|
1098
1098
|
tagParse(spec) {
|
|
1099
|
-
return
|
|
1099
|
+
return (0, annotation_1.annotationToTag)(this._structDef.annotation, spec);
|
|
1100
1100
|
}
|
|
1101
1101
|
getTaglines(prefix) {
|
|
1102
|
-
return
|
|
1102
|
+
return (0, annotation_1.annotationToTaglines)(this._structDef.annotation, prefix);
|
|
1103
1103
|
}
|
|
1104
1104
|
get modelTag() {
|
|
1105
|
-
this.parsedModelTag || (this.parsedModelTag =
|
|
1105
|
+
this.parsedModelTag || (this.parsedModelTag = (0, annotation_1.annotationToTag)(this._structDef.modelAnnotation).tag);
|
|
1106
1106
|
return this.parsedModelTag;
|
|
1107
1107
|
}
|
|
1108
1108
|
/**
|
|
@@ -1343,11 +1343,11 @@ class AtomicField extends Entity {
|
|
|
1343
1343
|
}
|
|
1344
1344
|
}
|
|
1345
1345
|
tagParse(spec) {
|
|
1346
|
-
spec =
|
|
1347
|
-
return
|
|
1346
|
+
spec = (0, annotation_1.addModelScope)(spec, this.parent.modelTag);
|
|
1347
|
+
return (0, annotation_1.annotationToTag)(this.fieldTypeDef.annotation, spec);
|
|
1348
1348
|
}
|
|
1349
1349
|
getTaglines(prefix) {
|
|
1350
|
-
return
|
|
1350
|
+
return (0, annotation_1.annotationToTaglines)(this.fieldTypeDef.annotation, prefix);
|
|
1351
1351
|
}
|
|
1352
1352
|
isIntrinsic() {
|
|
1353
1353
|
return (0, model_1.fieldIsIntrinsic)(this.fieldTypeDef);
|
|
@@ -1573,11 +1573,11 @@ class QueryField extends Query {
|
|
|
1573
1573
|
this.parent = parent;
|
|
1574
1574
|
}
|
|
1575
1575
|
tagParse(spec) {
|
|
1576
|
-
spec =
|
|
1577
|
-
return
|
|
1576
|
+
spec = (0, annotation_1.addModelScope)(spec, this.parent.modelTag);
|
|
1577
|
+
return (0, annotation_1.annotationToTag)(this.turtleDef.annotation, spec);
|
|
1578
1578
|
}
|
|
1579
1579
|
getTaglines(prefix) {
|
|
1580
|
-
return
|
|
1580
|
+
return (0, annotation_1.annotationToTaglines)(this.turtleDef.annotation, prefix);
|
|
1581
1581
|
}
|
|
1582
1582
|
isQueryField() {
|
|
1583
1583
|
return true;
|
|
@@ -1633,8 +1633,8 @@ class ExploreField extends Explore {
|
|
|
1633
1633
|
return this.joinRelationship !== JoinRelationship.OneToOne;
|
|
1634
1634
|
}
|
|
1635
1635
|
tagParse(spec) {
|
|
1636
|
-
spec =
|
|
1637
|
-
return
|
|
1636
|
+
spec = (0, annotation_1.addModelScope)(spec, this._parentExplore.modelTag);
|
|
1637
|
+
return (0, annotation_1.annotationToTag)(this._structDef.annotation, spec);
|
|
1638
1638
|
}
|
|
1639
1639
|
isQueryField() {
|
|
1640
1640
|
return false;
|
|
@@ -4,7 +4,7 @@ import { Connection } from '../connection/types';
|
|
|
4
4
|
import { AndChain } from './utils';
|
|
5
5
|
import { QueryInfo } from '../dialect/dialect';
|
|
6
6
|
import { EventStream } from '../runtime_types';
|
|
7
|
-
import { Tag } from '
|
|
7
|
+
import { Tag } from '@malloydata/malloy-tag';
|
|
8
8
|
interface TurtleDefPlus extends TurtleDef, Filtered {
|
|
9
9
|
}
|
|
10
10
|
/** Parent from QueryStruct. */
|
|
@@ -225,6 +225,8 @@ declare class JoinInstance {
|
|
|
225
225
|
export declare class Segment {
|
|
226
226
|
static nextStructDef(structDef: SourceDef, segment: PipeSegment): QueryResultDef;
|
|
227
227
|
}
|
|
228
|
+
export declare function getResultStructDefForView(source: SourceDef, view: TurtleDef): SourceDef;
|
|
229
|
+
export declare function getResultStructDefForQuery(model: ModelDef, query: Query): SourceDef;
|
|
228
230
|
type StageGroupMaping = {
|
|
229
231
|
fromGroup: number;
|
|
230
232
|
toGroup: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QueryModel = exports.Segment = void 0;
|
|
3
|
+
exports.QueryModel = exports.getResultStructDefForQuery = exports.getResultStructDefForView = exports.Segment = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright 2023 Google LLC
|
|
6
6
|
*
|
|
@@ -29,7 +29,7 @@ const standardsql_1 = require("../dialect/standardsql/standardsql");
|
|
|
29
29
|
const malloy_types_1 = require("./malloy_types");
|
|
30
30
|
const utils_1 = require("./utils");
|
|
31
31
|
const utils_2 = require("./materialization/utils");
|
|
32
|
-
const
|
|
32
|
+
const annotation_1 = require("../annotation");
|
|
33
33
|
function pathToCol(path) {
|
|
34
34
|
return path.map(el => encodeURIComponent(el)).join('/');
|
|
35
35
|
}
|
|
@@ -1564,6 +1564,21 @@ class Segment {
|
|
|
1564
1564
|
}
|
|
1565
1565
|
}
|
|
1566
1566
|
exports.Segment = Segment;
|
|
1567
|
+
function getResultStructDefForView(source, view) {
|
|
1568
|
+
const qs = new QueryStruct(source, undefined, {
|
|
1569
|
+
model: new QueryModel(undefined),
|
|
1570
|
+
}, {});
|
|
1571
|
+
const queryQueryQuery = QueryQuery.makeQuery(view, qs, new StageWriter(true, undefined), // stage write indicates we want to get a result.
|
|
1572
|
+
false);
|
|
1573
|
+
return queryQueryQuery.getResultStructDef();
|
|
1574
|
+
}
|
|
1575
|
+
exports.getResultStructDefForView = getResultStructDefForView;
|
|
1576
|
+
function getResultStructDefForQuery(model, query) {
|
|
1577
|
+
const queryModel = new QueryModel(model);
|
|
1578
|
+
const compiled = queryModel.compileQuery(query);
|
|
1579
|
+
return compiled.structs[compiled.structs.length - 1];
|
|
1580
|
+
}
|
|
1581
|
+
exports.getResultStructDefForQuery = getResultStructDefForQuery;
|
|
1567
1582
|
/** Query builder object. */
|
|
1568
1583
|
class QueryQuery extends QueryField {
|
|
1569
1584
|
constructor(fieldDef, parent, stageWriter, isJoinedSubquery) {
|
|
@@ -3087,7 +3102,7 @@ class QueryStruct {
|
|
|
3087
3102
|
modelCompilerFlags() {
|
|
3088
3103
|
if (this._modelTag === undefined) {
|
|
3089
3104
|
const annotation = this.structDef.modelAnnotation;
|
|
3090
|
-
const { tag } =
|
|
3105
|
+
const { tag } = (0, annotation_1.annotationToTag)(annotation, { prefix: /^##!\s*/ });
|
|
3091
3106
|
this._modelTag = tag;
|
|
3092
3107
|
}
|
|
3093
3108
|
return this._modelTag;
|