flowquery 1.0.0
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/.github/workflows/npm-publish.yml +30 -0
- package/.github/workflows/release.yml +84 -0
- package/CODE_OF_CONDUCT.md +10 -0
- package/FlowQueryLogoIcon.png +0 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/SECURITY.md +14 -0
- package/SUPPORT.md +13 -0
- package/docs/flowquery.min.js +1 -0
- package/docs/index.html +105 -0
- package/flowquery-vscode/.vscode-test.mjs +5 -0
- package/flowquery-vscode/.vscodeignore +13 -0
- package/flowquery-vscode/LICENSE +21 -0
- package/flowquery-vscode/README.md +11 -0
- package/flowquery-vscode/demo/FlowQueryVSCodeDemo.gif +0 -0
- package/flowquery-vscode/eslint.config.mjs +25 -0
- package/flowquery-vscode/extension.js +508 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -0
- package/flowquery-vscode/flowquery-worker.js +66 -0
- package/flowquery-vscode/images/FlowQueryLogoIcon.png +0 -0
- package/flowquery-vscode/jsconfig.json +13 -0
- package/flowquery-vscode/libs/page.css +53 -0
- package/flowquery-vscode/libs/table.css +13 -0
- package/flowquery-vscode/libs/tabs.css +66 -0
- package/flowquery-vscode/package-lock.json +2917 -0
- package/flowquery-vscode/package.json +51 -0
- package/flowquery-vscode/test/extension.test.js +196 -0
- package/flowquery-vscode/test/worker.test.js +25 -0
- package/flowquery-vscode/vsc-extension-quickstart.md +42 -0
- package/jest.config.js +11 -0
- package/package.json +28 -0
- package/queries/analyze_catfacts.cql +75 -0
- package/queries/azure_openai_completions.cql +13 -0
- package/queries/azure_openai_models.cql +9 -0
- package/queries/mock_pipeline.cql +84 -0
- package/queries/openai_completions.cql +15 -0
- package/queries/openai_models.cql +13 -0
- package/queries/test.cql +6 -0
- package/queries/tool_inference.cql +24 -0
- package/queries/wisdom.cql +6 -0
- package/queries/wisdom_letter_histogram.cql +8 -0
- package/src/compute/runner.ts +65 -0
- package/src/index.browser.ts +11 -0
- package/src/index.ts +12 -0
- package/src/io/command_line.ts +74 -0
- package/src/parsing/alias.ts +23 -0
- package/src/parsing/alias_option.ts +5 -0
- package/src/parsing/ast_node.ts +153 -0
- package/src/parsing/base_parser.ts +92 -0
- package/src/parsing/components/csv.ts +9 -0
- package/src/parsing/components/from.ts +12 -0
- package/src/parsing/components/headers.ts +12 -0
- package/src/parsing/components/json.ts +9 -0
- package/src/parsing/components/null.ts +9 -0
- package/src/parsing/components/post.ts +9 -0
- package/src/parsing/components/text.ts +9 -0
- package/src/parsing/context.ts +48 -0
- package/src/parsing/data_structures/associative_array.ts +43 -0
- package/src/parsing/data_structures/json_array.ts +31 -0
- package/src/parsing/data_structures/key_value_pair.ts +37 -0
- package/src/parsing/data_structures/lookup.ts +40 -0
- package/src/parsing/data_structures/range_lookup.ts +36 -0
- package/src/parsing/expressions/expression.ts +142 -0
- package/src/parsing/expressions/f_string.ts +26 -0
- package/src/parsing/expressions/identifier.ts +22 -0
- package/src/parsing/expressions/number.ts +40 -0
- package/src/parsing/expressions/operator.ts +179 -0
- package/src/parsing/expressions/reference.ts +42 -0
- package/src/parsing/expressions/string.ts +34 -0
- package/src/parsing/functions/aggregate_function.ts +58 -0
- package/src/parsing/functions/avg.ts +37 -0
- package/src/parsing/functions/collect.ts +44 -0
- package/src/parsing/functions/function.ts +60 -0
- package/src/parsing/functions/function_factory.ts +66 -0
- package/src/parsing/functions/join.ts +26 -0
- package/src/parsing/functions/predicate_function.ts +44 -0
- package/src/parsing/functions/predicate_function_factory.ts +15 -0
- package/src/parsing/functions/predicate_sum.ts +29 -0
- package/src/parsing/functions/rand.ts +13 -0
- package/src/parsing/functions/range.ts +18 -0
- package/src/parsing/functions/reducer_element.ts +10 -0
- package/src/parsing/functions/replace.ts +19 -0
- package/src/parsing/functions/round.ts +17 -0
- package/src/parsing/functions/size.ts +17 -0
- package/src/parsing/functions/split.ts +26 -0
- package/src/parsing/functions/stringify.ts +26 -0
- package/src/parsing/functions/sum.ts +31 -0
- package/src/parsing/functions/to_json.ts +17 -0
- package/src/parsing/functions/value_holder.ts +13 -0
- package/src/parsing/logic/case.ts +26 -0
- package/src/parsing/logic/else.ts +12 -0
- package/src/parsing/logic/end.ts +9 -0
- package/src/parsing/logic/then.ts +12 -0
- package/src/parsing/logic/when.ts +12 -0
- package/src/parsing/operations/aggregated_return.ts +18 -0
- package/src/parsing/operations/aggregated_with.ts +18 -0
- package/src/parsing/operations/group_by.ts +124 -0
- package/src/parsing/operations/limit.ts +22 -0
- package/src/parsing/operations/load.ts +92 -0
- package/src/parsing/operations/operation.ts +65 -0
- package/src/parsing/operations/projection.ts +18 -0
- package/src/parsing/operations/return.ts +43 -0
- package/src/parsing/operations/unwind.ts +32 -0
- package/src/parsing/operations/where.ts +38 -0
- package/src/parsing/operations/with.ts +20 -0
- package/src/parsing/parser.ts +762 -0
- package/src/parsing/token_to_node.ts +91 -0
- package/src/tokenization/keyword.ts +43 -0
- package/src/tokenization/operator.ts +25 -0
- package/src/tokenization/string_walker.ts +194 -0
- package/src/tokenization/symbol.ts +15 -0
- package/src/tokenization/token.ts +633 -0
- package/src/tokenization/token_mapper.ts +53 -0
- package/src/tokenization/token_type.ts +15 -0
- package/src/tokenization/tokenizer.ts +229 -0
- package/src/tokenization/trie.ts +117 -0
- package/src/utils/object_utils.ts +17 -0
- package/src/utils/string_utils.ts +114 -0
- package/tests/compute/runner.test.ts +498 -0
- package/tests/parsing/context.test.ts +27 -0
- package/tests/parsing/expression.test.ts +40 -0
- package/tests/parsing/parser.test.ts +434 -0
- package/tests/tokenization/token_mapper.test.ts +47 -0
- package/tests/tokenization/tokenizer.test.ts +67 -0
- package/tests/tokenization/trie.test.ts +20 -0
- package/tsconfig.json +15 -0
- package/typedoc.json +16 -0
- package/webpack.config.js +26 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import Runner from '../../src/compute/runner';
|
|
2
|
+
|
|
3
|
+
test('Test return', async () => {
|
|
4
|
+
const runner = new Runner('return 1 + 2 as sum');
|
|
5
|
+
await runner.run();
|
|
6
|
+
const results = runner.results;
|
|
7
|
+
expect(results.length).toBe(1);
|
|
8
|
+
expect(results[0]).toEqual({'sum': 3});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('Test return with multiple expressions', async () => {
|
|
12
|
+
const runner = new Runner('return 1 + 2 as sum, 3 + 4 as sum2');
|
|
13
|
+
await runner.run();
|
|
14
|
+
const results = runner.results;
|
|
15
|
+
expect(results.length).toBe(1);
|
|
16
|
+
expect(results[0]).toEqual({'sum': 3, 'sum2': 7});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('Test unwind and return', async () => {
|
|
20
|
+
const runner = new Runner('unwind [1, 2, 3] as num return num');
|
|
21
|
+
await runner.run();
|
|
22
|
+
const results = runner.results;
|
|
23
|
+
expect(results.length).toBe(3);
|
|
24
|
+
expect(results[0]).toEqual({'num': 1});
|
|
25
|
+
expect(results[1]).toEqual({'num': 2});
|
|
26
|
+
expect(results[2]).toEqual({'num': 3});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('Test load and return', async () => {
|
|
30
|
+
const runner = new Runner('load json from "https://jsonplaceholder.typicode.com/todos" as todo return todo');
|
|
31
|
+
await runner.run();
|
|
32
|
+
const results = runner.results;
|
|
33
|
+
expect(results.length).toBeGreaterThan(0);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('Test load with post and return', async () => {
|
|
37
|
+
const runner = new Runner('load json from "https://jsonplaceholder.typicode.com/posts" post {userId: 1} as data return data');
|
|
38
|
+
await runner.run();
|
|
39
|
+
const results = runner.results;
|
|
40
|
+
expect(results.length).toBe(1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('Test aggregated return', async () => {
|
|
44
|
+
const runner = new Runner('unwind [1, 1, 2, 2] as i unwind [1, 2, 3, 4] as j return i, sum(j) as sum');
|
|
45
|
+
await runner.run();
|
|
46
|
+
const results = runner.results;
|
|
47
|
+
expect(results.length).toBe(2);
|
|
48
|
+
expect(results[0]).toEqual({'i': 1, 'sum': 20});
|
|
49
|
+
expect(results[1]).toEqual({'i': 2, 'sum': 20});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('Test aggregated return with string', async () => {
|
|
53
|
+
const runner = new Runner('unwind [1, 1, 2, 2] as i unwind ["a", "b", "c", "d"] as j return i, sum(j) as sum');
|
|
54
|
+
await runner.run();
|
|
55
|
+
const results = runner.results;
|
|
56
|
+
expect(results.length).toBe(2);
|
|
57
|
+
expect(results[0]).toEqual({'i': 1, 'sum': 'abcdabcd'});
|
|
58
|
+
expect(results[1]).toEqual({'i': 2, 'sum': 'abcdabcd'});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('Test aggregated return with object', async () => {
|
|
62
|
+
const runner = new Runner('unwind [1, 1, 2, 2] as i unwind [1, 2, 3 4] as j return i, {sum: sum(j)} as sum');
|
|
63
|
+
await runner.run();
|
|
64
|
+
const results = runner.results;
|
|
65
|
+
expect(results.length).toBe(2);
|
|
66
|
+
expect(results[0]).toEqual({'i': 1, 'sum': {'sum': 20}});
|
|
67
|
+
expect(results[1]).toEqual({'i': 2, 'sum': {'sum': 20}});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('Test aggregated return with array', async () => {
|
|
71
|
+
const runner = new Runner('unwind [1, 1, 2, 2] as i unwind [1, 2, 3 4] as j return i, [sum(j)] as sum');
|
|
72
|
+
await runner.run();
|
|
73
|
+
const results = runner.results;
|
|
74
|
+
expect(results.length).toBe(2);
|
|
75
|
+
expect(results[0]).toEqual({'i': 1, 'sum': [20]});
|
|
76
|
+
expect(results[1]).toEqual({'i': 2, 'sum': [20]});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('Test aggregated return with multiple aggregates', async () => {
|
|
80
|
+
const runner = new Runner('unwind [1, 1, 2, 2] as i unwind [1, 2, 3, 4] as j return i, sum(j) as sum, avg(j) as avg');
|
|
81
|
+
await runner.run();
|
|
82
|
+
const results = runner.results;
|
|
83
|
+
expect(results.length).toBe(2);
|
|
84
|
+
expect(results[0]).toEqual({'i': 1, 'sum': 20, 'avg': 2.5});
|
|
85
|
+
expect(results[1]).toEqual({'i': 2, 'sum': 20, 'avg': 2.5});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('Test avg with null', async () => {
|
|
89
|
+
const runner = new Runner('return avg(null) as avg');
|
|
90
|
+
await runner.run();
|
|
91
|
+
const results = runner.results;
|
|
92
|
+
expect(results.length).toBe(1);
|
|
93
|
+
expect(results[0]).toEqual({'avg': null});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('Test sum with null', async () => {
|
|
97
|
+
const runner = new Runner('return sum(null) as sum');
|
|
98
|
+
await runner.run();
|
|
99
|
+
const results = runner.results;
|
|
100
|
+
expect(results.length).toBe(1);
|
|
101
|
+
expect(results[0]).toEqual({'sum': null});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('Test avg with one value', async () => {
|
|
105
|
+
const runner = new Runner('return avg(1) as avg');
|
|
106
|
+
await runner.run();
|
|
107
|
+
const results = runner.results;
|
|
108
|
+
expect(results.length).toBe(1);
|
|
109
|
+
expect(results[0]).toEqual({'avg': 1});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('Test with and return', async () => {
|
|
113
|
+
const runner = new Runner('with 1 as a return a');
|
|
114
|
+
await runner.run();
|
|
115
|
+
const results = runner.results;
|
|
116
|
+
expect(results.length).toBe(1);
|
|
117
|
+
expect(results[0]).toEqual({'a': 1});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('Test nested aggregate functions', async () => {
|
|
121
|
+
expect(() => {
|
|
122
|
+
new Runner('unwind [1, 2, 3, 4] as i return sum(sum(i)) as sum')
|
|
123
|
+
}).toThrow('Aggregate functions cannot be nested');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('Test with and return with unwind', async () => {
|
|
127
|
+
const runner = new Runner('with [1, 2, 3] as a unwind a as b return b as renamed');
|
|
128
|
+
await runner.run();
|
|
129
|
+
const results = runner.results;
|
|
130
|
+
expect(results.length).toBe(3);
|
|
131
|
+
expect(results[0]).toEqual({'renamed': 1});
|
|
132
|
+
expect(results[1]).toEqual({'renamed': 2});
|
|
133
|
+
expect(results[2]).toEqual({'renamed': 3});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('Test predicate function', async () => {
|
|
137
|
+
const runner = new Runner('RETURN sum(n in [1, 2, 3] | n where n > 1) as sum');
|
|
138
|
+
await runner.run();
|
|
139
|
+
const results = runner.results;
|
|
140
|
+
expect(results.length).toBe(1);
|
|
141
|
+
expect(results[0]).toEqual({'sum': 5});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('Test predicate without where', async () => {
|
|
145
|
+
const runner = new Runner('RETURN sum(n in [1, 2, 3] | n) as sum');
|
|
146
|
+
await runner.run();
|
|
147
|
+
const results = runner.results;
|
|
148
|
+
expect(results.length).toBe(1);
|
|
149
|
+
expect(results[0]).toEqual({'sum': 6});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('Test predicate with return expression', async () => {
|
|
153
|
+
const runner = new Runner('RETURN sum(n in [1+2+3, 2, 3] | n^2) as sum');
|
|
154
|
+
await runner.run();
|
|
155
|
+
const results = runner.results;
|
|
156
|
+
expect(results.length).toBe(1);
|
|
157
|
+
expect(results[0]).toEqual({'sum': 49});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('Test range function', async () => {
|
|
161
|
+
const runner = new Runner('RETURN range(1, 3) as range');
|
|
162
|
+
await runner.run();
|
|
163
|
+
const results = runner.results;
|
|
164
|
+
expect(results.length).toBe(1);
|
|
165
|
+
expect(results[0]).toEqual({'range': [1, 2, 3]});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('Test range function with unwind and case', async () => {
|
|
169
|
+
const runner = new Runner('unwind range(1, 3) as num return case when num > 1 then num else null end as ret');
|
|
170
|
+
await runner.run();
|
|
171
|
+
const results = runner.results;
|
|
172
|
+
expect(results.length).toBe(3);
|
|
173
|
+
expect(results[0]).toEqual({'ret': null});
|
|
174
|
+
expect(results[1]).toEqual({'ret': 2});
|
|
175
|
+
expect(results[2]).toEqual({'ret': 3});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('Test size function', async () => {
|
|
179
|
+
const runner = new Runner('RETURN size([1, 2, 3]) as size');
|
|
180
|
+
await runner.run();
|
|
181
|
+
const results = runner.results;
|
|
182
|
+
expect(results.length).toBe(1);
|
|
183
|
+
expect(results[0]).toEqual({'size': 3});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('Test rand and round functions', async () => {
|
|
187
|
+
const runner = new Runner('RETURN round(rand() * 10) as rand');
|
|
188
|
+
await runner.run();
|
|
189
|
+
const results = runner.results;
|
|
190
|
+
expect(results.length).toBe(1);
|
|
191
|
+
expect(results[0].rand).toBeLessThanOrEqual(10);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('Test split function', async () => {
|
|
195
|
+
const runner = new Runner('RETURN split("a,b,c", ",") as split');
|
|
196
|
+
await runner.run();
|
|
197
|
+
const results = runner.results;
|
|
198
|
+
expect(results.length).toBe(1);
|
|
199
|
+
expect(results[0]).toEqual({'split': ['a', 'b', 'c']});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('Test f-string', async () => {
|
|
203
|
+
const runner = new Runner('with range(1,3) as numbers RETURN f"hello {sum(n in numbers | n)}" as f');
|
|
204
|
+
await runner.run();
|
|
205
|
+
const results = runner.results;
|
|
206
|
+
expect(results.length).toBe(1);
|
|
207
|
+
expect(results[0]).toEqual({'f': 'hello 6'});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test('Test aggregated with and return', async () => {
|
|
211
|
+
const runner = new Runner(
|
|
212
|
+
`
|
|
213
|
+
unwind [1, 1, 2, 2] as i
|
|
214
|
+
unwind range(1, 3) as j
|
|
215
|
+
with i, sum(j) as sum
|
|
216
|
+
return i, sum
|
|
217
|
+
`
|
|
218
|
+
);
|
|
219
|
+
await runner.run();
|
|
220
|
+
const results = runner.results;
|
|
221
|
+
expect(results.length).toBe(2);
|
|
222
|
+
expect(results[0]).toEqual({'i': 1, 'sum': 12});
|
|
223
|
+
expect(results[1]).toEqual({'i': 2, 'sum': 12});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('Test aggregated with using collect and return', async () => {
|
|
227
|
+
const runner = new Runner(
|
|
228
|
+
`
|
|
229
|
+
unwind [1, 1, 2, 2] as i
|
|
230
|
+
unwind range(1, 3) as j
|
|
231
|
+
with i, collect(j) as collected
|
|
232
|
+
return i, collected
|
|
233
|
+
`
|
|
234
|
+
);
|
|
235
|
+
await runner.run();
|
|
236
|
+
const results = runner.results;
|
|
237
|
+
expect(results.length).toBe(2);
|
|
238
|
+
expect(results[0]).toEqual({'i': 1, 'collected': [1, 2, 3, 1, 2, 3]});
|
|
239
|
+
expect(results[1]).toEqual({'i': 2, 'collected': [1, 2, 3, 1, 2, 3]});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test('Test collect distinct', async () => {
|
|
243
|
+
const runner = new Runner(
|
|
244
|
+
`
|
|
245
|
+
unwind [1, 1, 2, 2] as i
|
|
246
|
+
unwind range(1, 3) as j
|
|
247
|
+
with i, collect(distinct j) as collected
|
|
248
|
+
return i, collected
|
|
249
|
+
`
|
|
250
|
+
);
|
|
251
|
+
await runner.run();
|
|
252
|
+
const results = runner.results;
|
|
253
|
+
expect(results.length).toBe(2);
|
|
254
|
+
expect(results[0]).toEqual({'i': 1, 'collected': [1, 2, 3]});
|
|
255
|
+
expect(results[1]).toEqual({'i': 2, 'collected': [1, 2, 3]});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test('Test collect distinct with associative array', async () => {
|
|
259
|
+
const runner = new Runner(
|
|
260
|
+
`
|
|
261
|
+
unwind [1, 1, 2, 2] as i
|
|
262
|
+
unwind range(1, 3) as j
|
|
263
|
+
with i, collect(distinct {j: j}) as collected
|
|
264
|
+
return i, collected
|
|
265
|
+
`
|
|
266
|
+
);
|
|
267
|
+
await runner.run();
|
|
268
|
+
const results = runner.results;
|
|
269
|
+
expect(results.length).toBe(2);
|
|
270
|
+
expect(results[0]).toEqual({'i': 1, 'collected': [{'j': 1}, {'j': 2}, {'j': 3}]});
|
|
271
|
+
expect(results[1]).toEqual({'i': 2, 'collected': [{'j': 1}, {'j': 2}, {'j': 3}]});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test('Test join function', async () => {
|
|
275
|
+
const runner = new Runner('RETURN join(["a", "b", "c"], ",") as join');
|
|
276
|
+
await runner.run();
|
|
277
|
+
const results = runner.results;
|
|
278
|
+
expect(results.length).toBe(1);
|
|
279
|
+
expect(results[0]).toEqual({'join': 'a,b,c'});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('Test join function with empty array', async () => {
|
|
283
|
+
const runner = new Runner('RETURN join([], ",") as join');
|
|
284
|
+
await runner.run();
|
|
285
|
+
const results = runner.results;
|
|
286
|
+
expect(results.length).toBe(1);
|
|
287
|
+
expect(results[0]).toEqual({'join': ''});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test('Test tojson function', async () => {
|
|
291
|
+
const runner = new Runner('RETURN tojson(\'{"a": 1, "b": 2}\') as tojson');
|
|
292
|
+
await runner.run();
|
|
293
|
+
const results = runner.results;
|
|
294
|
+
expect(results.length).toBe(1);
|
|
295
|
+
expect(results[0]).toEqual({'tojson': {'a': 1, 'b': 2}});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test('Test tojson function with lookup', async () => {
|
|
299
|
+
const runner = new Runner('RETURN tojson(\'{"a": 1, "b": 2}\').a as tojson');
|
|
300
|
+
await runner.run();
|
|
301
|
+
const results = runner.results;
|
|
302
|
+
expect(results.length).toBe(1);
|
|
303
|
+
expect(results[0]).toEqual({'tojson': 1});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
test('Test replace function', async () => {
|
|
307
|
+
const runner = new Runner('RETURN replace("hello", "l", "x") as replace');
|
|
308
|
+
await runner.run();
|
|
309
|
+
const results = runner.results;
|
|
310
|
+
expect(results.length).toBe(1);
|
|
311
|
+
expect(results[0]).toEqual({'replace': 'hexxo'});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('Test f-string with escaped braces', async () => {
|
|
315
|
+
const runner = new Runner('with range(1,3) as numbers RETURN f"hello {{sum(n in numbers | n)}}" as f');
|
|
316
|
+
await runner.run();
|
|
317
|
+
const results = runner.results;
|
|
318
|
+
expect(results.length).toBe(1);
|
|
319
|
+
expect(results[0]).toEqual({'f': 'hello {sum(n in numbers | n)}'});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test('Test predicate function with collection from lookup', async () => {
|
|
323
|
+
const runner = new Runner('RETURN sum(n in tojson(\'{"a": [1, 2, 3]}\').a | n) as sum');
|
|
324
|
+
await runner.run();
|
|
325
|
+
const results = runner.results;
|
|
326
|
+
expect(results.length).toBe(1);
|
|
327
|
+
expect(results[0]).toEqual({'sum': 6});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('Test stringify function', async () => {
|
|
331
|
+
const runner = new Runner('RETURN stringify({a: 1, b: 2}) as stringify');
|
|
332
|
+
await runner.run();
|
|
333
|
+
const results = runner.results;
|
|
334
|
+
expect(results.length).toBe(1);
|
|
335
|
+
expect(results[0]).toEqual({
|
|
336
|
+
'stringify': '{\n "a": 1,\n "b": 2\n}'
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
test('Test associative array with key which is keyword', async () => {
|
|
341
|
+
const runner = new Runner('RETURN {return: 1} as aa');
|
|
342
|
+
await runner.run();
|
|
343
|
+
const results = runner.results;
|
|
344
|
+
expect(results.length).toBe(1);
|
|
345
|
+
expect(results[0]).toEqual({'aa': {'return': 1}});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test('Test lookup which is keyword', async () => {
|
|
349
|
+
const runner = new Runner('RETURN {return: 1}.return as aa');
|
|
350
|
+
await runner.run();
|
|
351
|
+
const results = runner.results;
|
|
352
|
+
expect(results.length).toBe(1);
|
|
353
|
+
expect(results[0]).toEqual({'aa': 1});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test('Test lookup which is keyword', async () => {
|
|
357
|
+
const runner = new Runner('RETURN {return: 1}["return"] as aa');
|
|
358
|
+
await runner.run();
|
|
359
|
+
const results = runner.results;
|
|
360
|
+
expect(results.length).toBe(1);
|
|
361
|
+
expect(results[0]).toEqual({'aa': 1});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test('Test return with expression alias which starts with keyword', async () => {
|
|
365
|
+
const runner = new Runner('RETURN 1 as return1, ["hello", "world"] as notes');
|
|
366
|
+
await runner.run();
|
|
367
|
+
const results = runner.results;
|
|
368
|
+
expect(results.length).toBe(1);
|
|
369
|
+
expect(results[0]).toEqual({'return1': 1, 'notes': ['hello', 'world']});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test('Test load which should throw error', async () => {
|
|
373
|
+
const runner = new Runner('load json from "http://non_existing" as data return data');
|
|
374
|
+
runner.run().then().catch(e => {
|
|
375
|
+
expect(e.message).toBe('Failed to load data from http://non_existing. Error: TypeError: fetch failed');
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
test('Test return with where clause', async () => {
|
|
380
|
+
const runner = new Runner('unwind range(1,100) as n with n return n where n >= 20 and n <= 30');
|
|
381
|
+
await runner.run();
|
|
382
|
+
const results = runner.results;
|
|
383
|
+
expect(results.length).toBe(11);
|
|
384
|
+
expect(results[0]).toEqual({'n': 20});
|
|
385
|
+
expect(results[10]).toEqual({'n': 30});
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
test('Test return with where clause and expression alias', async () => {
|
|
389
|
+
const runner = new Runner('unwind range(1,100) as n with n return n as number where n >= 20 and n <= 30');
|
|
390
|
+
await runner.run();
|
|
391
|
+
const results = runner.results;
|
|
392
|
+
expect(results.length).toBe(11);
|
|
393
|
+
expect(results[0]).toEqual({'number': 20});
|
|
394
|
+
expect(results[10]).toEqual({'number': 30});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test('Test aggregated return with where clause', async () => {
|
|
398
|
+
const runner = new Runner('unwind range(1,100) as n with n where n >= 20 and n <= 30 return sum(n) as sum');
|
|
399
|
+
await runner.run();
|
|
400
|
+
const results = runner.results;
|
|
401
|
+
expect(results.length).toBe(1);
|
|
402
|
+
expect(results[0]).toEqual({'sum': 275});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test('Test chained aggregated return with where clause', async () => {
|
|
406
|
+
const runner = new Runner(
|
|
407
|
+
`
|
|
408
|
+
unwind [1, 1, 2, 2] as i
|
|
409
|
+
unwind range(1, 4) as j
|
|
410
|
+
return i, sum(j) as sum
|
|
411
|
+
where i = 1
|
|
412
|
+
`
|
|
413
|
+
);
|
|
414
|
+
await runner.run();
|
|
415
|
+
const results = runner.results;
|
|
416
|
+
expect(results.length).toBe(1);
|
|
417
|
+
expect(results[0]).toEqual({'i': 1, 'sum': 20});
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test('Test predicate function with collection from function', async () => {
|
|
421
|
+
const runner = new Runner(
|
|
422
|
+
`
|
|
423
|
+
unwind range(1, 10) as i
|
|
424
|
+
unwind range(1, 10) as j
|
|
425
|
+
return i, sum(j), avg(j), sum(n in collect(j) | n) as sum
|
|
426
|
+
`
|
|
427
|
+
);
|
|
428
|
+
await runner.run();
|
|
429
|
+
const results = runner.results;
|
|
430
|
+
expect(results.length).toBe(10);
|
|
431
|
+
expect(results[0]).toEqual({'i': 1, 'expr1': 55, 'expr2': 5.5, 'sum': 55});
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
test('Test limit', async () => {
|
|
435
|
+
const runner = new Runner(
|
|
436
|
+
`
|
|
437
|
+
unwind range(1, 10) as i
|
|
438
|
+
unwind range(1, 10) as j
|
|
439
|
+
limit 5
|
|
440
|
+
return j
|
|
441
|
+
`
|
|
442
|
+
);
|
|
443
|
+
await runner.run();
|
|
444
|
+
const results = runner.results;
|
|
445
|
+
expect(results.length).toBe(50);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test('Test range lookup', async () => {
|
|
449
|
+
const runner = new Runner(
|
|
450
|
+
`
|
|
451
|
+
with range(1, 10) as numbers
|
|
452
|
+
return
|
|
453
|
+
numbers[:] as subset1,
|
|
454
|
+
numbers[0:3] as subset2,
|
|
455
|
+
numbers[:-2] as subset3
|
|
456
|
+
`
|
|
457
|
+
);
|
|
458
|
+
await runner.run();
|
|
459
|
+
const results = runner.results;
|
|
460
|
+
expect(results.length).toBe(1);
|
|
461
|
+
expect(results[0]).toEqual({
|
|
462
|
+
'subset1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
|
463
|
+
'subset2': [1, 2, 3],
|
|
464
|
+
'subset3': [1, 2, 3, 4, 5, 6, 7, 8]
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test('Test return -1', async () => {
|
|
469
|
+
const runner = new Runner('return -1 as num');
|
|
470
|
+
await runner.run();
|
|
471
|
+
const results = runner.results;
|
|
472
|
+
expect(results.length).toBe(1);
|
|
473
|
+
expect(results[0]).toEqual({'num': -1});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test('Unwind range lookup', async () => {
|
|
477
|
+
const runner = new Runner(`
|
|
478
|
+
with range(1,10) as arr
|
|
479
|
+
unwind arr[2:-2] as a
|
|
480
|
+
return a
|
|
481
|
+
`);
|
|
482
|
+
await runner.run();
|
|
483
|
+
const results = runner.results;
|
|
484
|
+
expect(results.length).toBe(6);
|
|
485
|
+
expect(results[0]).toEqual({'a': 3});
|
|
486
|
+
expect(results[5]).toEqual({'a': 8});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test('Test range with size', async () => {
|
|
490
|
+
const runner = new Runner(`
|
|
491
|
+
with range(1,10) as data
|
|
492
|
+
return range(0, size(data)-1) as indices
|
|
493
|
+
`);
|
|
494
|
+
await runner.run();
|
|
495
|
+
const results = runner.results;
|
|
496
|
+
expect(results.length).toBe(1);
|
|
497
|
+
expect(results[0]).toEqual({'indices': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]});
|
|
498
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Context from "../../src/parsing/context";
|
|
2
|
+
import Sum from "../../src/parsing/functions/sum";
|
|
3
|
+
import AggregateFunction from "../../src/parsing/functions/aggregate_function";
|
|
4
|
+
|
|
5
|
+
test('Test Context containsType', () => {
|
|
6
|
+
const context = new Context();
|
|
7
|
+
const sum = new Sum();
|
|
8
|
+
context.push(sum);
|
|
9
|
+
expect(context.containsType(AggregateFunction)).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('Test Context containsType false', () => {
|
|
13
|
+
const context = new Context();
|
|
14
|
+
expect(context.containsType(AggregateFunction)).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Test Context push and pop', () => {
|
|
18
|
+
const context = new Context();
|
|
19
|
+
const sum = new Sum();
|
|
20
|
+
context.push(sum);
|
|
21
|
+
expect(context.pop()).toBe(sum);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('Test Context pop undefined', () => {
|
|
25
|
+
const context = new Context();
|
|
26
|
+
expect(context.pop()).toBe(undefined);
|
|
27
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import Expression from "../../src/parsing/expressions/expression";
|
|
2
|
+
import { Add, Subtract, Multiply, Power, GreaterThan, And } from "../../src/parsing/expressions/operator";
|
|
3
|
+
import Number from "../../src/parsing/expressions/number";
|
|
4
|
+
|
|
5
|
+
test('Test Expression Shunting Yard algorithm', () => {
|
|
6
|
+
const expression = new Expression();
|
|
7
|
+
expression.addNode(new Number('2'));
|
|
8
|
+
expression.addNode(new Add());
|
|
9
|
+
expression.addNode(new Number('3'));
|
|
10
|
+
expression.addNode(new Multiply());
|
|
11
|
+
expression.addNode(new Number('4'));
|
|
12
|
+
expression.addNode(new Subtract());
|
|
13
|
+
expression.addNode(new Number('2'));
|
|
14
|
+
expression.addNode(new Power());
|
|
15
|
+
expression.addNode(new Number('2'));
|
|
16
|
+
expression.finish();
|
|
17
|
+
expect(expression.value()).toBe(10);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('Test Expression with and operator', () => {
|
|
21
|
+
const expression = new Expression();
|
|
22
|
+
expression.addNode(new Number('2'));
|
|
23
|
+
expression.addNode(new And());
|
|
24
|
+
expression.addNode(new Number('3'));
|
|
25
|
+
expression.finish();
|
|
26
|
+
expect(expression.value()).toBe(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('Test 1 > 0 and 2 > 1', () => {
|
|
30
|
+
const expression = new Expression();
|
|
31
|
+
expression.addNode(new Number('1'));
|
|
32
|
+
expression.addNode(new GreaterThan());
|
|
33
|
+
expression.addNode(new Number('0'));
|
|
34
|
+
expression.addNode(new And());
|
|
35
|
+
expression.addNode(new Number('2'));
|
|
36
|
+
expression.addNode(new GreaterThan());
|
|
37
|
+
expression.addNode(new Number('1'));
|
|
38
|
+
expression.finish();
|
|
39
|
+
expect(expression.value()).toBe(1);
|
|
40
|
+
});
|