@malloydata/malloy 0.0.157 → 0.0.158-dev240805161224
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/expressions/constant-expression.d.ts +28 -0
- package/dist/lang/ast/expressions/{constant-sub-expression.js → constant-expression.js} +6 -5
- package/dist/lang/ast/expressions/expr-func.js +29 -11
- package/dist/lang/ast/expressions/expr-id-reference.d.ts +0 -1
- package/dist/lang/ast/expressions/expr-id-reference.js +0 -24
- package/dist/lang/ast/field-space/dynamic-space.d.ts +4 -1
- package/dist/lang/ast/field-space/dynamic-space.js +22 -11
- package/dist/lang/ast/field-space/index-field-space.js +3 -0
- package/dist/lang/ast/field-space/join-space-field.d.ts +3 -1
- package/dist/lang/ast/field-space/join-space-field.js +3 -2
- package/dist/lang/ast/field-space/parameter-space.d.ts +18 -0
- package/dist/lang/ast/field-space/parameter-space.js +67 -0
- package/dist/lang/ast/field-space/query-spaces.js +3 -0
- package/dist/lang/ast/field-space/reference-field.js +13 -4
- package/dist/lang/ast/field-space/refined-space.d.ts +2 -1
- package/dist/lang/ast/field-space/refined-space.js +12 -1
- package/dist/lang/ast/field-space/static-space.js +3 -5
- package/dist/lang/ast/index.d.ts +1 -0
- package/dist/lang/ast/index.js +1 -0
- package/dist/lang/ast/parameters/argument.d.ts +14 -0
- package/dist/lang/ast/parameters/argument.js +20 -0
- package/dist/lang/ast/parameters/has-parameter.d.ts +3 -5
- package/dist/lang/ast/parameters/has-parameter.js +24 -13
- package/dist/lang/ast/query-elements/query-arrow.js +7 -7
- package/dist/lang/ast/query-elements/query-head-struct.d.ts +6 -4
- package/dist/lang/ast/query-elements/query-head-struct.js +6 -5
- package/dist/lang/ast/query-elements/query-raw.js +7 -7
- package/dist/lang/ast/query-elements/query-reference.js +2 -2
- package/dist/lang/ast/query-items/field-references.d.ts +4 -0
- package/dist/lang/ast/query-items/field-references.js +12 -1
- package/dist/lang/ast/source-elements/named-source.d.ts +15 -12
- package/dist/lang/ast/source-elements/named-source.js +91 -60
- package/dist/lang/ast/source-elements/query-source.d.ts +4 -1
- package/dist/lang/ast/source-elements/query-source.js +9 -3
- package/dist/lang/ast/source-elements/refined-source.d.ts +3 -2
- package/dist/lang/ast/source-elements/refined-source.js +12 -7
- package/dist/lang/ast/source-elements/source.d.ts +6 -4
- package/dist/lang/ast/source-elements/source.js +19 -16
- package/dist/lang/ast/source-elements/sql-source.d.ts +2 -2
- package/dist/lang/ast/source-elements/sql-source.js +4 -3
- package/dist/lang/ast/source-properties/joins.d.ts +5 -4
- package/dist/lang/ast/source-properties/joins.js +7 -7
- package/dist/lang/ast/source-query-elements/sq-reference.d.ts +3 -1
- package/dist/lang/ast/source-query-elements/sq-reference.js +9 -2
- package/dist/lang/ast/statements/define-source.d.ts +4 -2
- package/dist/lang/ast/statements/define-source.js +28 -14
- package/dist/lang/ast/struct-utils.js +3 -2
- package/dist/lang/ast/types/expression-def.js +2 -0
- package/dist/lang/lib/Malloy/MalloyParser.d.ts +169 -101
- package/dist/lang/lib/Malloy/MalloyParser.js +2105 -1600
- package/dist/lang/lib/Malloy/MalloyParserListener.d.ts +64 -9
- package/dist/lang/lib/Malloy/MalloyParserVisitor.d.ts +40 -5
- package/dist/lang/malloy-to-ast.d.ts +5 -1
- package/dist/lang/malloy-to-ast.js +51 -10
- package/dist/lang/test/expressions.spec.js +21 -1
- package/dist/lang/test/field-symbols.spec.js +0 -2
- package/dist/lang/test/locations.spec.js +3 -0
- package/dist/lang/test/parameters.spec.d.ts +1 -0
- package/dist/lang/test/parameters.spec.js +578 -0
- package/dist/model/malloy_query.d.ts +8 -5
- package/dist/model/malloy_query.js +68 -37
- package/dist/model/malloy_types.d.ts +12 -14
- package/dist/model/malloy_types.js +22 -10
- package/package.json +1 -1
- package/dist/lang/ast/expressions/constant-sub-expression.d.ts +0 -16
- package/dist/lang/ast/parameters/constant-parameter.d.ts +0 -8
- package/dist/lang/ast/parameters/constant-parameter.js +0 -54
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const test_translator_1 = require("./test-translator");
|
|
10
|
+
require("./parse-expects");
|
|
11
|
+
describe('parameters', () => {
|
|
12
|
+
test('can declare parameter with no default value', () => {
|
|
13
|
+
expect(`
|
|
14
|
+
##! experimental.parameters
|
|
15
|
+
source: ab_new(param::number) is ab
|
|
16
|
+
`).toTranslate();
|
|
17
|
+
});
|
|
18
|
+
test('can declare parameter with default value literal', () => {
|
|
19
|
+
expect(`
|
|
20
|
+
##! experimental.parameters
|
|
21
|
+
source: ab_new(param::number is 7) is ab
|
|
22
|
+
`).toTranslate();
|
|
23
|
+
});
|
|
24
|
+
test('can declare parameter with default value constant', () => {
|
|
25
|
+
expect(`
|
|
26
|
+
##! experimental.parameters
|
|
27
|
+
source: ab_new(param::number is 7 + 7) is ab
|
|
28
|
+
`).toTranslate();
|
|
29
|
+
});
|
|
30
|
+
test('cannot specify default value with incompatible type', () => {
|
|
31
|
+
expect((0, test_translator_1.markSource) `
|
|
32
|
+
##! experimental.parameters
|
|
33
|
+
source: ab_new(param::number is ${'"hello"'}) is ab
|
|
34
|
+
`).translationToFailWith('Default value for parameter does not match declared type `number`');
|
|
35
|
+
});
|
|
36
|
+
test('error if paramter has no type or value', () => {
|
|
37
|
+
expect((0, test_translator_1.markSource) `
|
|
38
|
+
##! experimental.parameters
|
|
39
|
+
source: ab_new(param) is ab
|
|
40
|
+
`).translationToFailWith('Parameter must have default value or declared type');
|
|
41
|
+
});
|
|
42
|
+
test('error if paramter type is null', () => {
|
|
43
|
+
expect((0, test_translator_1.markSource) `
|
|
44
|
+
##! experimental.parameters
|
|
45
|
+
source: ab_new(param is null) is ab
|
|
46
|
+
`).translationToFailWith('Default value cannot have type `null`');
|
|
47
|
+
});
|
|
48
|
+
test('error if paramter type is range', () => {
|
|
49
|
+
expect((0, test_translator_1.markSource) `
|
|
50
|
+
##! experimental.parameters
|
|
51
|
+
source: ab_new(param is 10 to 20) is ab
|
|
52
|
+
`).translationToFailWith('A Range is not a value');
|
|
53
|
+
});
|
|
54
|
+
test('no additional error if default value type is error', () => {
|
|
55
|
+
expect((0, test_translator_1.markSource) `
|
|
56
|
+
##! experimental.parameters
|
|
57
|
+
source: ab_new(param::number is 1 + "foo") is ab
|
|
58
|
+
`).translationToFailWith("Non numeric('number,string') value with '+'");
|
|
59
|
+
});
|
|
60
|
+
test('can declare parameter with inferred type', () => {
|
|
61
|
+
expect(`
|
|
62
|
+
##! experimental.parameters
|
|
63
|
+
source: ab_new(param is 7) is ab
|
|
64
|
+
`).toTranslate();
|
|
65
|
+
});
|
|
66
|
+
test('can pass parameter into extended base source', () => {
|
|
67
|
+
expect(`
|
|
68
|
+
##! experimental.parameters
|
|
69
|
+
source: ab_new(param::number) is ab
|
|
70
|
+
source: ab_new_new(param::number) is ab_new(param) extend {}
|
|
71
|
+
`).toTranslate();
|
|
72
|
+
});
|
|
73
|
+
test.skip('can pass parameter into source of query', () => {
|
|
74
|
+
expect(`
|
|
75
|
+
##! experimental.parameters
|
|
76
|
+
source: ab_new(param::number) is ab
|
|
77
|
+
source: ab_new_new(param::number) is ab_new(param) -> { select: * }
|
|
78
|
+
`).toTranslate();
|
|
79
|
+
});
|
|
80
|
+
test('can pass parameter to override default value with constant', () => {
|
|
81
|
+
expect(`
|
|
82
|
+
##! experimental.parameters
|
|
83
|
+
source: ab_new(param::number is 10) is ab
|
|
84
|
+
source: ab_new_new is ab_new(param is 7) extend {}
|
|
85
|
+
`).toTranslate();
|
|
86
|
+
});
|
|
87
|
+
test('can pass parameter to override default value with param value', () => {
|
|
88
|
+
expect(`
|
|
89
|
+
##! experimental.parameters
|
|
90
|
+
source: ab_new(param::number is 10) is ab
|
|
91
|
+
source: ab_new_new(param::number is 11) is ab_new(param) extend {}
|
|
92
|
+
`).toTranslate();
|
|
93
|
+
});
|
|
94
|
+
test('can pass parameter into named base source', () => {
|
|
95
|
+
expect(`
|
|
96
|
+
##! experimental.parameters
|
|
97
|
+
source: ab_new(param::number) is ab
|
|
98
|
+
source: ab_new_new(param::number) is ab_new(param)
|
|
99
|
+
`).toTranslate();
|
|
100
|
+
});
|
|
101
|
+
test('can pass differently-named parameter into extended base source', () => {
|
|
102
|
+
expect(`
|
|
103
|
+
##! experimental.parameters
|
|
104
|
+
source: ab_new(new_param::number) is ab
|
|
105
|
+
source: ab_new_new(new_new_param::number) is ab_new(new_param is new_new_param) extend {}
|
|
106
|
+
`).toTranslate();
|
|
107
|
+
});
|
|
108
|
+
test('can pass differently-named parameter into named base source', () => {
|
|
109
|
+
expect(`
|
|
110
|
+
##! experimental.parameters
|
|
111
|
+
source: ab_new(new_param::number) is ab
|
|
112
|
+
source: ab_new_new(new_new_param::number) is ab_new(new_param is new_new_param)
|
|
113
|
+
`).toTranslate();
|
|
114
|
+
});
|
|
115
|
+
test('can pass parameter into base source longhand', () => {
|
|
116
|
+
expect(`
|
|
117
|
+
##! experimental.parameters
|
|
118
|
+
source: ab_new(param::number) is ab
|
|
119
|
+
source: ab_new_new(param::number) is ab_new(param is param)
|
|
120
|
+
`).toTranslate();
|
|
121
|
+
});
|
|
122
|
+
test('can pass parameter into base source shorthand', () => {
|
|
123
|
+
expect(`
|
|
124
|
+
##! experimental.parameters
|
|
125
|
+
source: ab_new(param::number) is ab
|
|
126
|
+
source: ab_new_new(param::number) is ab_new(param)
|
|
127
|
+
`).toTranslate();
|
|
128
|
+
});
|
|
129
|
+
test('can use declared parameter in dimension', () => {
|
|
130
|
+
expect(`
|
|
131
|
+
##! experimental.parameters
|
|
132
|
+
source: ab_new(param::number) is ab extend {
|
|
133
|
+
dimension: param_plus_one is param + 1
|
|
134
|
+
}
|
|
135
|
+
`).toTranslate();
|
|
136
|
+
});
|
|
137
|
+
test('can use declared parameter in sql function', () => {
|
|
138
|
+
expect(`
|
|
139
|
+
##! experimental { parameters sql_functions }
|
|
140
|
+
source: ab_new(param::number) is ab extend {
|
|
141
|
+
dimension: param_plus_one is sql_number("\${param} + 1")
|
|
142
|
+
}
|
|
143
|
+
run: ab_new(param is 1) -> param_plus_one
|
|
144
|
+
`).toTranslate();
|
|
145
|
+
});
|
|
146
|
+
test('can use declared parameter in nest extending other', () => {
|
|
147
|
+
expect(`
|
|
148
|
+
##! experimental.parameters
|
|
149
|
+
source: ab_new(param::number is 10) is ab extend {
|
|
150
|
+
dimension: p1 is param
|
|
151
|
+
view: my_view is {
|
|
152
|
+
group_by: p2 is param
|
|
153
|
+
nest: nested is {
|
|
154
|
+
group_by: p3 is param
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
run: ab_new -> my_view
|
|
159
|
+
`).toTranslate();
|
|
160
|
+
});
|
|
161
|
+
test('can use declared parameter in source extension in view', () => {
|
|
162
|
+
expect(`
|
|
163
|
+
##! experimental.parameters
|
|
164
|
+
source: ab_new(param::number is 10) is ab extend {
|
|
165
|
+
view: my_view is {
|
|
166
|
+
extend: {
|
|
167
|
+
dimension: p1 is param
|
|
168
|
+
}
|
|
169
|
+
group_by: p1
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
`).toTranslate();
|
|
173
|
+
});
|
|
174
|
+
test('can use declared parameter in nest with table', () => {
|
|
175
|
+
expect(`
|
|
176
|
+
##! experimental.parameters
|
|
177
|
+
source: ab_new(param::number is 10) is _db_.table('aTable') extend {
|
|
178
|
+
dimension: p1 is param
|
|
179
|
+
view: my_view is {
|
|
180
|
+
group_by: p2 is param
|
|
181
|
+
nest: nested is {
|
|
182
|
+
group_by: p3 is param
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
run: ab_new -> my_view
|
|
187
|
+
`).toTranslate();
|
|
188
|
+
});
|
|
189
|
+
test('can pass argument for param', () => {
|
|
190
|
+
expect(`
|
|
191
|
+
##! experimental.parameters
|
|
192
|
+
source: ab_new(param::number) is ab
|
|
193
|
+
run: ab_new(param is 1) -> { select: * }
|
|
194
|
+
`).toTranslate();
|
|
195
|
+
});
|
|
196
|
+
test('can not pass argument for default-valued param', () => {
|
|
197
|
+
expect(`
|
|
198
|
+
##! experimental.parameters
|
|
199
|
+
source: ab_new(param is 1) is ab
|
|
200
|
+
run: ab_new -> { select: * }
|
|
201
|
+
`).toTranslate();
|
|
202
|
+
});
|
|
203
|
+
test('can pass zero args for source with default-valued param', () => {
|
|
204
|
+
expect(`
|
|
205
|
+
##! experimental.parameters
|
|
206
|
+
source: ab_new(param is 1) is ab
|
|
207
|
+
run: ab_new() -> { select: * }
|
|
208
|
+
`).toTranslate();
|
|
209
|
+
});
|
|
210
|
+
test('can pass non-literal argument for param', () => {
|
|
211
|
+
expect(`
|
|
212
|
+
##! experimental.parameters
|
|
213
|
+
source: ab_new(param::number) is ab
|
|
214
|
+
run: ab_new(param is 1 + 1) -> { select: * }
|
|
215
|
+
`).toTranslate();
|
|
216
|
+
});
|
|
217
|
+
test('parameter not included in wildcard', () => {
|
|
218
|
+
expect((0, test_translator_1.markSource) `
|
|
219
|
+
##! experimental.parameters
|
|
220
|
+
source: ab_new(param::number) is ab extend {
|
|
221
|
+
view: all_fields is { select: * }
|
|
222
|
+
}
|
|
223
|
+
run: ab_new(param is 1) -> all_fields -> { select: ${'param'} }
|
|
224
|
+
`).translationToFailWith("'param' is not defined");
|
|
225
|
+
});
|
|
226
|
+
test('cannot reference renamed param in query against source', () => {
|
|
227
|
+
expect((0, test_translator_1.markSource) `
|
|
228
|
+
##! experimental.parameters
|
|
229
|
+
source: ab_new(param::number) is ab
|
|
230
|
+
run: ab_new(param is 1) -> { select: p is ${'param'} }
|
|
231
|
+
`).translationToFailWith("'param' is not defined");
|
|
232
|
+
});
|
|
233
|
+
test('cannot reference param in query against source', () => {
|
|
234
|
+
expect((0, test_translator_1.markSource) `
|
|
235
|
+
##! experimental.parameters
|
|
236
|
+
source: ab_new(param::number) is ab
|
|
237
|
+
run: ab_new(param is 1) -> { select: ${'param'} }
|
|
238
|
+
`).translationToFailWith("'param' is not defined");
|
|
239
|
+
});
|
|
240
|
+
test('cannot reference param in source extension', () => {
|
|
241
|
+
expect((0, test_translator_1.markSource) `
|
|
242
|
+
##! experimental.parameters
|
|
243
|
+
source: ab_new(param::number) is ab
|
|
244
|
+
source: x is ab_new(param is 1) extend {
|
|
245
|
+
dimension: param_copy is ${'param'}
|
|
246
|
+
}
|
|
247
|
+
`).translationToFailWith("'param' is not defined");
|
|
248
|
+
});
|
|
249
|
+
test('cannot reference param in in-query source extension', () => {
|
|
250
|
+
expect((0, test_translator_1.markSource) `
|
|
251
|
+
##! experimental.parameters
|
|
252
|
+
source: ab_new(param::number) is ab
|
|
253
|
+
run: ab_new(param is 1) -> {
|
|
254
|
+
extend: {
|
|
255
|
+
dimension: param_copy is ${'param'}
|
|
256
|
+
}
|
|
257
|
+
group_by: param_copy
|
|
258
|
+
}
|
|
259
|
+
`).translationToFailWith("'param' is not defined");
|
|
260
|
+
});
|
|
261
|
+
test('can reference field in source in argument', () => {
|
|
262
|
+
expect((0, test_translator_1.markSource) `
|
|
263
|
+
##! experimental.parameters
|
|
264
|
+
source: ab_new(param::number) is ab
|
|
265
|
+
run: ab_new(param is ${'ai'}) -> { select: * }
|
|
266
|
+
`).translationToFailWith('`ai` is not defined');
|
|
267
|
+
});
|
|
268
|
+
test('can pass through parameter to joined source', () => {
|
|
269
|
+
expect(`
|
|
270
|
+
##! experimental.parameters
|
|
271
|
+
source: ab_ext_1(a_1::string) is ab extend {
|
|
272
|
+
where: ai = a_1
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
source: ab_ext_2(a_2::string) is ab extend {
|
|
276
|
+
where: ai = a_2
|
|
277
|
+
join_many: ab_ext_1 is ab_ext_1(a_1 is a_2) on 1 = 1
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
run: ab_ext_2(a_2 is "CA") -> {
|
|
281
|
+
group_by:
|
|
282
|
+
a1 is ai,
|
|
283
|
+
a2 is ab_ext_1.ai
|
|
284
|
+
aggregate: c is count()
|
|
285
|
+
}
|
|
286
|
+
`).toTranslate();
|
|
287
|
+
});
|
|
288
|
+
test.skip('can pass through parameter to source in joined query', () => {
|
|
289
|
+
expect(`
|
|
290
|
+
##! experimental.parameters
|
|
291
|
+
source: ab_ext_1(a_1::string) is ab extend {
|
|
292
|
+
where: ai = a_1
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
source: ab_ext_2(a_2::string) is ab extend {
|
|
296
|
+
where: ai = a_2
|
|
297
|
+
join_many: ab_ext_1 is ab_ext_1(a_1 is a_2) -> { select: * } on 1 = 1
|
|
298
|
+
}
|
|
299
|
+
`).toTranslate();
|
|
300
|
+
});
|
|
301
|
+
test.skip('can pass through parameter to view in joined query', () => {
|
|
302
|
+
expect(`
|
|
303
|
+
##! experimental.parameters
|
|
304
|
+
source: ab_ext(param::string) is ab extend {
|
|
305
|
+
join_many: abq is ab -> { select: p is param } on 1 = 1
|
|
306
|
+
}
|
|
307
|
+
`).toTranslate();
|
|
308
|
+
});
|
|
309
|
+
test.skip('can pass through parameter to source in query in SQL source', () => {
|
|
310
|
+
expect(`
|
|
311
|
+
##! experimental.parameters
|
|
312
|
+
source: ab_ext(param::string) is ab
|
|
313
|
+
source: sql_query(a_1::string) is duckdb.sql("""
|
|
314
|
+
SELECT * FROM (%{ ab_ext(param is a_1) -> { select: * } })
|
|
315
|
+
""")
|
|
316
|
+
`).toTranslate();
|
|
317
|
+
});
|
|
318
|
+
test.skip('can pass through parameter to view in query in SQL source', () => {
|
|
319
|
+
expect(`
|
|
320
|
+
##! experimental.parameters
|
|
321
|
+
source: sql_query(a_1::string) is duckdb.sql("""
|
|
322
|
+
SELECT * FROM (%{ ab -> { select: p is param } })
|
|
323
|
+
""")
|
|
324
|
+
`).toTranslate();
|
|
325
|
+
});
|
|
326
|
+
test.skip('can pass through parameter to source in query in joined SQL source', () => {
|
|
327
|
+
expect(`
|
|
328
|
+
##! experimental.parameters
|
|
329
|
+
source: ab_ext_1(a_1::string) is ab extend {
|
|
330
|
+
where: ai = a_1
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
source: ab_ext_2(a_2::string) is ab extend {
|
|
334
|
+
where: ai = a_2
|
|
335
|
+
join_many: ab_ext_1 is duckdb.sql("""
|
|
336
|
+
SELECT * FROM (%{ ab_ext_1(a_1 is a_2) -> { select: * } })
|
|
337
|
+
""") on 1 = 1
|
|
338
|
+
}
|
|
339
|
+
`).toTranslate();
|
|
340
|
+
});
|
|
341
|
+
test('can reference param in query against source', () => {
|
|
342
|
+
expect((0, test_translator_1.markSource) `
|
|
343
|
+
##! experimental.parameters
|
|
344
|
+
source: ab_new(param::number) is ab
|
|
345
|
+
run: ab_new(param is 1) -> { select: ${'param'} }
|
|
346
|
+
`).translationToFailWith("'param' is not defined");
|
|
347
|
+
});
|
|
348
|
+
test('can reference param in view in source', () => {
|
|
349
|
+
expect(`
|
|
350
|
+
##! experimental.parameters
|
|
351
|
+
source: ab_new(param::number) is ab extend {
|
|
352
|
+
view: x is { select: param }
|
|
353
|
+
}
|
|
354
|
+
`).toTranslate();
|
|
355
|
+
});
|
|
356
|
+
test('can declare dimension which is just the parameter', () => {
|
|
357
|
+
expect(`
|
|
358
|
+
##! experimental.parameters
|
|
359
|
+
source: ab_new(param::number) is ab extend {
|
|
360
|
+
dimension: p is param
|
|
361
|
+
}
|
|
362
|
+
`).toTranslate();
|
|
363
|
+
});
|
|
364
|
+
test('cannot reference param in expression in query against source', () => {
|
|
365
|
+
expect(`
|
|
366
|
+
##! experimental.parameters
|
|
367
|
+
source: ab_new(param::number) is ab
|
|
368
|
+
run: ab_new(param is 1) -> { select: p is ${'param'} }
|
|
369
|
+
`).translationToFailWith("'param' is not defined");
|
|
370
|
+
});
|
|
371
|
+
test('error when declaring parameter twice', () => {
|
|
372
|
+
expect((0, test_translator_1.markSource) `
|
|
373
|
+
##! experimental.parameters
|
|
374
|
+
source: ab_new(param::number, ${'param::number'}) is ab
|
|
375
|
+
`).translationToFailWith('Cannot redefine parameter `param`');
|
|
376
|
+
});
|
|
377
|
+
// This behavior will likely change in the future; but in the meantime, this
|
|
378
|
+
// safeguards against some confusion about parameter scoping
|
|
379
|
+
test('error when declaring parameter with same name as field (extended)', () => {
|
|
380
|
+
expect(`
|
|
381
|
+
##! experimental.parameters
|
|
382
|
+
source: ab_new(ai::string) is ab extend {
|
|
383
|
+
dimension: foo is upper(ai)
|
|
384
|
+
}
|
|
385
|
+
`).translationToFailWith('No matching overload for function upper(number)', 'Illegal shadowing of field `ai` by parameter with the same name');
|
|
386
|
+
});
|
|
387
|
+
test('can shadow field that is excepted', () => {
|
|
388
|
+
expect(`
|
|
389
|
+
##! experimental.parameters
|
|
390
|
+
source: ab_new(ai::string) is ab extend {
|
|
391
|
+
except: ai
|
|
392
|
+
dimension: foo is upper(ai)
|
|
393
|
+
}
|
|
394
|
+
`).toTranslate();
|
|
395
|
+
});
|
|
396
|
+
test('error when declaring parameter with same name as field (not extended)', () => {
|
|
397
|
+
expect((0, test_translator_1.markSource) `
|
|
398
|
+
##! experimental.parameters
|
|
399
|
+
source: ab_new(${'ai::string'}) is ab
|
|
400
|
+
`).translationToFailWith('Illegal shadowing of field `ai` by parameter with the same name');
|
|
401
|
+
});
|
|
402
|
+
test('do not inherit parameters from base source', () => {
|
|
403
|
+
expect((0, test_translator_1.markSource) `
|
|
404
|
+
##! experimental.parameters
|
|
405
|
+
source: ab_new(param::number) is ab
|
|
406
|
+
source: ab_new_new is ab_new(param is 1)
|
|
407
|
+
run: ab_new_new(${'param'} is 2) -> { select: * }
|
|
408
|
+
`).translationToFailWith('`ab_new_new` has no declared parameter named `param`');
|
|
409
|
+
});
|
|
410
|
+
test('error when declaring field with same name as parameter', () => {
|
|
411
|
+
expect((0, test_translator_1.markSource) `
|
|
412
|
+
##! experimental.parameters
|
|
413
|
+
source: ab_new(param::number) is ab extend {
|
|
414
|
+
dimension: param is 1
|
|
415
|
+
}
|
|
416
|
+
`).translationToFailWith("Cannot redefine 'param'");
|
|
417
|
+
});
|
|
418
|
+
test('error when declaring parameter without experiment enabled', () => {
|
|
419
|
+
expect((0, test_translator_1.markSource) `
|
|
420
|
+
source: ab_new(param::number) is ab
|
|
421
|
+
`).translationToFailWith("Experimental flag 'parameters' required to enable this feature");
|
|
422
|
+
});
|
|
423
|
+
test('cannot except parameter from extended source', () => {
|
|
424
|
+
expect((0, test_translator_1.markSource) `
|
|
425
|
+
##! experimental.parameters
|
|
426
|
+
source: ab_new(param_a::number) is ab
|
|
427
|
+
source: ab_new_new(param_b::number) is ab_new(param_a is 1) extend {
|
|
428
|
+
except: param_a
|
|
429
|
+
}
|
|
430
|
+
`).translationToFailWith('`param_a` is not defined');
|
|
431
|
+
});
|
|
432
|
+
test('cannot except parameter in direct extend', () => {
|
|
433
|
+
expect((0, test_translator_1.markSource) `
|
|
434
|
+
##! experimental.parameters
|
|
435
|
+
source: ab_new(param::number) is ab extend {
|
|
436
|
+
except: param
|
|
437
|
+
}
|
|
438
|
+
`).translationToFailWith('Illegal `except:` of parameter');
|
|
439
|
+
});
|
|
440
|
+
test('cannot accept parameter', () => {
|
|
441
|
+
expect((0, test_translator_1.markSource) `
|
|
442
|
+
##! experimental.parameters
|
|
443
|
+
source: ab_new(param::number) is ab extend {
|
|
444
|
+
accept: param
|
|
445
|
+
}
|
|
446
|
+
`).translationToFailWith('Illegal `accept:` of parameter');
|
|
447
|
+
});
|
|
448
|
+
test('error when using parameter without experiment enabled', () => {
|
|
449
|
+
expect((0, test_translator_1.markSource) `
|
|
450
|
+
run: ab_new${'(param is param)'} -> { select: * }
|
|
451
|
+
`).translationToFailWith("Experimental flag 'parameters' required to enable this feature");
|
|
452
|
+
});
|
|
453
|
+
test('parameters cannot reference themselves', () => {
|
|
454
|
+
expect((0, test_translator_1.markSource) `
|
|
455
|
+
##! experimental.parameters
|
|
456
|
+
source: ab_new(param::number) is ab
|
|
457
|
+
run: ab_new(param is ${'param'}) -> { select: * }
|
|
458
|
+
`).translationToFailWith('`param` is not defined');
|
|
459
|
+
});
|
|
460
|
+
// This just looks like circular referencing--in reality, you cannot reference other
|
|
461
|
+
// parameters in parameter arguments, hence just "xxx is not defined"
|
|
462
|
+
test('error when circularly referencing mutually recursive parameters in argument', () => {
|
|
463
|
+
expect((0, test_translator_1.markSource) `
|
|
464
|
+
##! experimental.parameters
|
|
465
|
+
source: ab_new(p_a::number, p_b::number) is ab
|
|
466
|
+
run: ab_new(p_a is ${'p_b'}, p_b is ${'p_a'}) -> { select: * }
|
|
467
|
+
`).translationToFailWith('`p_b` is not defined', '`p_a` is not defined');
|
|
468
|
+
});
|
|
469
|
+
test('error when passing param with no name', () => {
|
|
470
|
+
expect((0, test_translator_1.markSource) `
|
|
471
|
+
##! experimental.parameters
|
|
472
|
+
source: ab_new(param::number) is ab
|
|
473
|
+
run: ab_new(${'1'}) -> { select: * }
|
|
474
|
+
`).translationToFailWith('Parameterized source arguments must be named with `parameter_name is`', 'Argument not provided for required parameter `param`');
|
|
475
|
+
});
|
|
476
|
+
test('error when passing param with incorrect name', () => {
|
|
477
|
+
expect((0, test_translator_1.markSource) `
|
|
478
|
+
##! experimental.parameters
|
|
479
|
+
source: ab_new(param::number) is ab
|
|
480
|
+
run: ab_new(${'wrong_name'} is 1, param is 2) -> { select: * }
|
|
481
|
+
`).translationToFailWith('`ab_new` has no declared parameter named `wrong_name`');
|
|
482
|
+
});
|
|
483
|
+
test('error when passing param multiple times', () => {
|
|
484
|
+
expect((0, test_translator_1.markSource) `
|
|
485
|
+
##! experimental.parameters
|
|
486
|
+
source: ab_new(param::number) is ab
|
|
487
|
+
run: ab_new(param is 1, ${'param is 2'}) -> { select: * }
|
|
488
|
+
`).translationToFailWith('Cannot pass argument for `param` more than once');
|
|
489
|
+
});
|
|
490
|
+
test('error when not specifying argument for param with parentheses', () => {
|
|
491
|
+
expect((0, test_translator_1.markSource) `
|
|
492
|
+
##! experimental.parameters
|
|
493
|
+
source: ab_new(param::number) is ab
|
|
494
|
+
run: ${'ab_new'}() -> { select: * }
|
|
495
|
+
`).translationToFailWith('Argument not provided for required parameter `param`');
|
|
496
|
+
});
|
|
497
|
+
test('error when not specifying argument for param without parentheses', () => {
|
|
498
|
+
expect((0, test_translator_1.markSource) `
|
|
499
|
+
##! experimental.parameters
|
|
500
|
+
source: ab_new(param::number) is ab
|
|
501
|
+
run: ${'ab_new'} -> { select: * }
|
|
502
|
+
`).translationToFailWith('Argument not provided for required parameter `param`');
|
|
503
|
+
});
|
|
504
|
+
test('error when not specifying argument for param second time', () => {
|
|
505
|
+
expect((0, test_translator_1.markSource) `
|
|
506
|
+
##! experimental.parameters
|
|
507
|
+
source: ab_new(param::number) is ab
|
|
508
|
+
run: ab_new(param is 1) -> { select: * }
|
|
509
|
+
run: ${'ab_new'} -> { select: * }
|
|
510
|
+
`).translationToFailWith('Argument not provided for required parameter `param`');
|
|
511
|
+
});
|
|
512
|
+
test('error when referencing parameter that does not exist in join definition', () => {
|
|
513
|
+
expect((0, test_translator_1.markSource) `
|
|
514
|
+
##! experimental.parameters
|
|
515
|
+
source: ab_new_1(param_1::number) is ab
|
|
516
|
+
source: ab_new_2(param_2::number) is ab extend {
|
|
517
|
+
join_one: ab_join is ab_new_1(param_1 is ${'param_3'})
|
|
518
|
+
}
|
|
519
|
+
`).translationToFailWith('`param_3` is not defined');
|
|
520
|
+
});
|
|
521
|
+
test('error when referencing identifier in default param value', () => {
|
|
522
|
+
expect((0, test_translator_1.markSource) `
|
|
523
|
+
##! experimental.parameters
|
|
524
|
+
source: ab_new_1(param_1 is ${'ident'}) is ab
|
|
525
|
+
`).translationToFailWith('Only constants allowed in parameter default values');
|
|
526
|
+
});
|
|
527
|
+
test.skip('can use param in multi-stage query', () => {
|
|
528
|
+
expect(`
|
|
529
|
+
##! experimental.parameters
|
|
530
|
+
source: ab_new(param::number) is ab extend {
|
|
531
|
+
view: q is {
|
|
532
|
+
select: *
|
|
533
|
+
} -> {
|
|
534
|
+
group_by: x is param
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
`).toTranslate();
|
|
538
|
+
});
|
|
539
|
+
test('can not pass parameter into source of query yet', () => {
|
|
540
|
+
expect((0, test_translator_1.markSource) `
|
|
541
|
+
##! experimental.parameters
|
|
542
|
+
source: ab_new(param::number) is ab
|
|
543
|
+
source: ab_new_new(param::number) is ab_new(${'param'}) -> { select: * }
|
|
544
|
+
`).translationToFailWith('`param` is not defined');
|
|
545
|
+
});
|
|
546
|
+
test.skip('can add an annotation to a param', () => {
|
|
547
|
+
expect(`
|
|
548
|
+
##! experimental.parameters
|
|
549
|
+
source: ab_new(
|
|
550
|
+
# mytag=1
|
|
551
|
+
param::number
|
|
552
|
+
) is ab
|
|
553
|
+
`).toTranslate();
|
|
554
|
+
});
|
|
555
|
+
test('source arguments from query propagate as arguments not parameters', () => {
|
|
556
|
+
expect(`
|
|
557
|
+
##! experimental.parameters
|
|
558
|
+
source: ab_new(param::number) is ab extend {
|
|
559
|
+
dimension: param_value is param
|
|
560
|
+
}
|
|
561
|
+
query: foo is ab_new(param is 1) -> { select: param_value }
|
|
562
|
+
source: foo_ext is foo
|
|
563
|
+
run: foo_ext -> { select: param_value }
|
|
564
|
+
`).toTranslate();
|
|
565
|
+
});
|
|
566
|
+
test('source arguments carry over from previous invocation', () => {
|
|
567
|
+
expect(`
|
|
568
|
+
##! experimental.parameters
|
|
569
|
+
source: ab_new(param::number) is ab extend {
|
|
570
|
+
dimension: param_value is param
|
|
571
|
+
}
|
|
572
|
+
source: foo is ab_new(param is 1)
|
|
573
|
+
source: foo_ext is foo
|
|
574
|
+
run: foo_ext -> { select: param_value }
|
|
575
|
+
`).toTranslate();
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
//# sourceMappingURL=parameters.spec.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Dialect, DialectFieldList } from '../dialect';
|
|
2
|
-
import { AggregateFragment, AggregateFunctionType, Annotation, CompiledQuery, DialectFragment, Expr, FieldDef, FieldFragment, Filtered, FilterExpression, FilterFragment, FunctionCallFragment, FunctionOverloadDef, FunctionParameterDef, JoinRelationship, ModelDef, OrderBy, OutputFieldFragment, Parameter, ParameterFragment, PipeSegment, Query, QueryFieldDef, QuerySegment, ResultMetadataDef, ResultStructMetadataDef, SearchIndexResult, SourceReferenceFragment, SegmentFieldDef, SpreadFragment, SQLExpressionFragment, SqlStringFragment, StructDef, StructRef, TurtleDef, UngroupFragment, FunctionOrderBy } from './malloy_types';
|
|
2
|
+
import { AggregateFragment, AggregateFunctionType, Annotation, CompiledQuery, DialectFragment, Expr, FieldDef, FieldFragment, Filtered, FilterExpression, FilterFragment, FunctionCallFragment, FunctionOverloadDef, FunctionParameterDef, JoinRelationship, ModelDef, OrderBy, OutputFieldFragment, Parameter, ParameterFragment, PipeSegment, Query, QueryFieldDef, QuerySegment, ResultMetadataDef, ResultStructMetadataDef, SearchIndexResult, SourceReferenceFragment, SegmentFieldDef, SpreadFragment, SQLExpressionFragment, SqlStringFragment, StructDef, StructRef, TurtleDef, UngroupFragment, FunctionOrderBy, Argument } from './malloy_types';
|
|
3
3
|
import { Connection } from '../runtime_types';
|
|
4
4
|
import { AndChain } from './utils';
|
|
5
5
|
import { QueryInfo } from '../dialect/dialect';
|
|
@@ -76,7 +76,7 @@ declare class QueryField extends QueryNode {
|
|
|
76
76
|
getParamForArgIndex(params: FunctionParameterDef[], argIndex: number): FunctionParameterDef;
|
|
77
77
|
generateFunctionCallExpression(resultSet: FieldInstanceResult, context: QueryStruct, frag: FunctionCallFragment, state: GenerateState): string;
|
|
78
78
|
generateSpread(_resultSet: FieldInstanceResult, _context: QueryStruct, _frag: SpreadFragment, _state: GenerateState): string;
|
|
79
|
-
generateParameterFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: ParameterFragment,
|
|
79
|
+
generateParameterFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: ParameterFragment, state: GenerateState): string;
|
|
80
80
|
generateFilterFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: FilterFragment, state: GenerateState): string;
|
|
81
81
|
generateDimFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: Expr, state: GenerateState): string;
|
|
82
82
|
generateUngroupedFragment(resultSet: FieldInstanceResult, context: QueryStruct, expr: UngroupFragment, state: GenerateState): string;
|
|
@@ -284,6 +284,7 @@ declare class QueryQuery extends QueryField {
|
|
|
284
284
|
}
|
|
285
285
|
/** Structure object as it is used to build a query */
|
|
286
286
|
declare class QueryStruct extends QueryNode {
|
|
287
|
+
readonly sourceArguments: Record<string, Argument> | undefined;
|
|
287
288
|
fieldDef: StructDef;
|
|
288
289
|
parent: QueryStruct | undefined;
|
|
289
290
|
model: QueryModel;
|
|
@@ -291,8 +292,10 @@ declare class QueryStruct extends QueryNode {
|
|
|
291
292
|
pathAliasMap: Map<string, string>;
|
|
292
293
|
dialect: Dialect;
|
|
293
294
|
connectionName: string;
|
|
294
|
-
constructor(fieldDef: StructDef, parent: ParentQueryStruct | ParentQueryModel);
|
|
295
|
-
|
|
295
|
+
constructor(fieldDef: StructDef, sourceArguments: Record<string, Argument> | undefined, parent: ParentQueryStruct | ParentQueryModel);
|
|
296
|
+
resolveParentParameterReferences(param: Parameter): Parameter;
|
|
297
|
+
private _arguments;
|
|
298
|
+
arguments(): Record<string, Argument>;
|
|
296
299
|
addFieldsFromFieldList(fields: FieldDef[]): void;
|
|
297
300
|
getAliasIdentifier(): string;
|
|
298
301
|
getSQLIdentifier(): string;
|
|
@@ -346,7 +349,7 @@ export declare class QueryModel {
|
|
|
346
349
|
constructor(modelDef: ModelDef | undefined);
|
|
347
350
|
loadModelFromDef(modelDef: ModelDef): void;
|
|
348
351
|
getStructByName(name: string): QueryStruct;
|
|
349
|
-
getStructFromRef(structRef: StructRef): QueryStruct;
|
|
352
|
+
getStructFromRef(structRef: StructRef, sourceArguments: Record<string, Argument> | undefined): QueryStruct;
|
|
350
353
|
loadQuery(query: Query, stageWriter: StageWriter | undefined, emitFinalStage?: boolean, isJoinedSubquery?: boolean): QueryResults;
|
|
351
354
|
compileQuery(query: Query, finalize?: boolean): CompiledQuery;
|
|
352
355
|
exploreSearchSQLMap: Map<any, any>;
|