flowquery 1.0.14 → 1.0.16
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/.editorconfig +21 -0
- package/.husky/pre-commit +1 -0
- package/.prettierrc +22 -0
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/expressions/expression_map.d.ts +9 -0
- package/dist/parsing/expressions/expression_map.d.ts.map +1 -0
- package/dist/parsing/expressions/expression_map.js +24 -0
- package/dist/parsing/expressions/expression_map.js.map +1 -0
- package/dist/parsing/operations/call.d.ts +17 -0
- package/dist/parsing/operations/call.d.ts.map +1 -0
- package/dist/parsing/operations/call.js +105 -0
- package/dist/parsing/operations/call.js.map +1 -0
- package/dist/parsing/operations/load.d.ts +6 -6
- package/dist/parsing/operations/load.d.ts.map +1 -1
- package/dist/parsing/operations/load.js +8 -6
- package/dist/parsing/operations/load.js.map +1 -1
- package/dist/parsing/operations/operation.d.ts +1 -0
- package/dist/parsing/operations/operation.d.ts.map +1 -1
- package/dist/parsing/operations/operation.js +6 -5
- package/dist/parsing/operations/operation.js.map +1 -1
- package/dist/parsing/operations/projection.d.ts +1 -1
- package/dist/parsing/operations/projection.d.ts.map +1 -1
- package/dist/parsing/operations/projection.js.map +1 -1
- package/dist/parsing/parser.d.ts +1 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +148 -99
- package/dist/parsing/parser.js.map +1 -1
- package/dist/parsing/token_to_node.d.ts +2 -2
- package/dist/parsing/token_to_node.d.ts.map +1 -1
- package/dist/parsing/token_to_node.js +12 -12
- package/dist/parsing/token_to_node.js.map +1 -1
- package/dist/tokenization/token.d.ts +5 -1
- package/dist/tokenization/token.d.ts.map +1 -1
- package/dist/tokenization/token.js +17 -5
- package/dist/tokenization/token.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/package.json +1 -1
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +21 -26
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +65 -0
- package/misc/apps/RAG/src/plugins/loaders/Form.ts +163 -147
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +106 -92
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +80 -58
- package/misc/apps/RAG/src/plugins/loaders/Table.ts +106 -103
- package/misc/apps/RAG/src/plugins/loaders/Weather.ts +50 -38
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +77 -78
- package/package.json +12 -2
- package/src/parsing/expressions/expression_map.ts +22 -0
- package/src/parsing/operations/call.ts +69 -0
- package/src/parsing/operations/load.ts +123 -120
- package/src/parsing/operations/operation.ts +14 -13
- package/src/parsing/operations/projection.ts +3 -3
- package/src/parsing/parser.ts +303 -239
- package/src/parsing/token_to_node.ts +67 -50
- package/src/tokenization/token.ts +29 -14
- package/tests/compute/runner.test.ts +277 -165
- package/tests/parsing/parser.test.ts +352 -303
- package/tests/tokenization/tokenizer.test.ts +17 -17
- package/vscode-settings.json.recommended +16 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FlowQuery System Prompt Generator
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Generates a system prompt that instructs the LLM to create FlowQuery statements
|
|
5
5
|
* based on natural language queries, with awareness of available loader plugins.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Uses FlowQuery's built-in functions() introspection to dynamically discover
|
|
8
8
|
* available async data loaders and their metadata.
|
|
9
9
|
*/
|
|
10
|
+
import { FunctionMetadata, OutputSchema, ParameterSchema } from "flowquery/extensibility";
|
|
10
11
|
|
|
11
|
-
import {
|
|
12
|
-
import { getAllPluginMetadata, getAvailableLoaders } from '../plugins';
|
|
12
|
+
import { getAllPluginMetadata, getAvailableLoaders } from "../plugins";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* FlowQuery language reference documentation.
|
|
@@ -28,25 +28,29 @@ FlowQuery is a declarative query language for data processing pipelines. It uses
|
|
|
28
28
|
WITH expression1 AS var1, expression2 AS var2
|
|
29
29
|
\`\`\`
|
|
30
30
|
|
|
31
|
-
2. **LOAD JSON FROM** - Load data from a URL
|
|
31
|
+
2. **LOAD JSON FROM** - Load data from a URL
|
|
32
32
|
\`\`\`
|
|
33
33
|
LOAD JSON FROM 'https://api.example.com/data' AS item
|
|
34
|
-
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
3. **CALL ... YIELD** - Call an async data provider function and yield its fields
|
|
37
|
+
\`\`\`
|
|
38
|
+
CALL myFunction(arg1, arg2) YIELD field1, field2, field3
|
|
35
39
|
\`\`\`
|
|
36
40
|
|
|
37
|
-
**IMPORTANT**: Async data providers (functions used
|
|
41
|
+
**IMPORTANT**: Async data providers (functions used with CALL) cannot be nested inside other function calls. If you need to pass data from one async provider to another, first load the data into a variable using collect(), then pass that variable:
|
|
38
42
|
\`\`\`
|
|
39
43
|
// WRONG - async providers cannot be nested:
|
|
40
|
-
//
|
|
44
|
+
// CALL table(mockProducts(5), 'Products') YIELD html
|
|
41
45
|
|
|
42
46
|
// CORRECT - collect data first, then pass to next provider:
|
|
43
|
-
|
|
44
|
-
WITH collect(
|
|
45
|
-
|
|
46
|
-
RETURN
|
|
47
|
+
CALL mockProducts(5) YIELD id, name, price
|
|
48
|
+
WITH collect({ id: id, name: name, price: price }) AS products
|
|
49
|
+
CALL table(products, 'Products') YIELD html
|
|
50
|
+
RETURN html
|
|
47
51
|
\`\`\`
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
4. **LOAD JSON FROM ... HEADERS ... POST** - Make HTTP requests with headers and body
|
|
50
54
|
\`\`\`
|
|
51
55
|
LOAD JSON FROM 'https://api.example.com/data'
|
|
52
56
|
HEADERS {
|
|
@@ -59,42 +63,26 @@ FlowQuery is a declarative query language for data processing pipelines. It uses
|
|
|
59
63
|
} AS response
|
|
60
64
|
\`\`\`
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
5. **UNWIND** - Expand arrays into individual rows
|
|
63
67
|
\`\`\`
|
|
64
68
|
UNWIND [1, 2, 3] AS number
|
|
65
69
|
UNWIND myArray AS item
|
|
66
70
|
UNWIND range(0, 10) AS index
|
|
67
71
|
\`\`\`
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
6. **WHERE** - Filter results
|
|
70
74
|
\`\`\`
|
|
71
75
|
WHERE item.active = true
|
|
72
76
|
WHERE user.age > 18 AND user.name CONTAINS 'John'
|
|
73
77
|
\`\`\`
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
7. **RETURN** - Specify output columns
|
|
76
80
|
\`\`\`
|
|
77
81
|
RETURN item.name, item.value
|
|
78
82
|
RETURN item.name AS Name, item.price AS Price
|
|
79
83
|
RETURN * -- Return all fields
|
|
80
84
|
\`\`\`
|
|
81
85
|
|
|
82
|
-
7. **ORDER BY** - Sort results
|
|
83
|
-
\`\`\`
|
|
84
|
-
ORDER BY item.name ASC
|
|
85
|
-
ORDER BY item.price DESC, item.name ASC
|
|
86
|
-
\`\`\`
|
|
87
|
-
|
|
88
|
-
8. **LIMIT** - Limit number of results
|
|
89
|
-
\`\`\`
|
|
90
|
-
LIMIT 10
|
|
91
|
-
\`\`\`
|
|
92
|
-
|
|
93
|
-
9. **SKIP** - Skip a number of results
|
|
94
|
-
\`\`\`
|
|
95
|
-
SKIP 5
|
|
96
|
-
\`\`\`
|
|
97
|
-
|
|
98
86
|
### Built-in Functions
|
|
99
87
|
|
|
100
88
|
- **String Functions**: \`size()\`, \`substring()\`, \`trim()\`, \`toLower()\`, \`toUpper()\`, \`split()\`, \`join()\`, \`replace()\`, \`startsWith()\`, \`endsWith()\`, \`contains()\`
|
|
@@ -154,9 +142,12 @@ export class FlowQuerySystemPrompt {
|
|
|
154
142
|
* Format a parameter schema into a readable string.
|
|
155
143
|
*/
|
|
156
144
|
private static formatParameter(param: ParameterSchema): string {
|
|
157
|
-
const required = param.required ?
|
|
158
|
-
const defaultVal =
|
|
159
|
-
|
|
145
|
+
const required = param.required ? " (required)" : " (optional)";
|
|
146
|
+
const defaultVal =
|
|
147
|
+
param.default !== undefined ? `, default: ${JSON.stringify(param.default)}` : "";
|
|
148
|
+
const enumVals = param.enum
|
|
149
|
+
? `, values: [${param.enum.map((v) => JSON.stringify(v)).join(", ")}]`
|
|
150
|
+
: "";
|
|
160
151
|
return ` - \`${param.name}\`: ${param.type}${required}${defaultVal}${enumVals} - ${param.description}`;
|
|
161
152
|
}
|
|
162
153
|
|
|
@@ -165,18 +156,18 @@ export class FlowQuerySystemPrompt {
|
|
|
165
156
|
*/
|
|
166
157
|
private static formatOutput(output: OutputSchema): string {
|
|
167
158
|
let result = ` Returns: ${output.type} - ${output.description}`;
|
|
168
|
-
|
|
159
|
+
|
|
169
160
|
if (output.properties) {
|
|
170
|
-
result +=
|
|
161
|
+
result += "\n Output properties:";
|
|
171
162
|
for (const [key, prop] of Object.entries(output.properties)) {
|
|
172
163
|
result += `\n - \`${key}\`: ${prop.type} - ${prop.description}`;
|
|
173
164
|
}
|
|
174
165
|
}
|
|
175
|
-
|
|
166
|
+
|
|
176
167
|
if (output.example) {
|
|
177
168
|
result += `\n Example output: ${JSON.stringify(output.example, null, 2)}`;
|
|
178
169
|
}
|
|
179
|
-
|
|
170
|
+
|
|
180
171
|
return result;
|
|
181
172
|
}
|
|
182
173
|
|
|
@@ -185,38 +176,38 @@ export class FlowQuerySystemPrompt {
|
|
|
185
176
|
*/
|
|
186
177
|
private static formatPluginDocumentation(plugin: FunctionMetadata): string {
|
|
187
178
|
const lines: string[] = [];
|
|
188
|
-
|
|
179
|
+
|
|
189
180
|
lines.push(`### \`${plugin.name}\``);
|
|
190
181
|
lines.push(`**Description**: ${plugin.description}`);
|
|
191
|
-
|
|
182
|
+
|
|
192
183
|
if (plugin.category) {
|
|
193
184
|
lines.push(`**Category**: ${plugin.category}`);
|
|
194
185
|
}
|
|
195
|
-
|
|
186
|
+
|
|
196
187
|
if (plugin.parameters.length > 0) {
|
|
197
|
-
lines.push(
|
|
188
|
+
lines.push("\n**Parameters**:");
|
|
198
189
|
for (const param of plugin.parameters) {
|
|
199
190
|
lines.push(this.formatParameter(param));
|
|
200
191
|
}
|
|
201
192
|
} else {
|
|
202
|
-
lines.push(
|
|
193
|
+
lines.push("\n**Parameters**: None");
|
|
203
194
|
}
|
|
204
|
-
|
|
205
|
-
lines.push(
|
|
195
|
+
|
|
196
|
+
lines.push("\n**Output**:");
|
|
206
197
|
lines.push(this.formatOutput(plugin.output));
|
|
207
|
-
|
|
198
|
+
|
|
208
199
|
if (plugin.examples && plugin.examples.length > 0) {
|
|
209
|
-
lines.push(
|
|
200
|
+
lines.push("\n**Usage Examples**:");
|
|
210
201
|
for (const example of plugin.examples) {
|
|
211
202
|
lines.push(`\`\`\`\n${example}\n\`\`\``);
|
|
212
203
|
}
|
|
213
204
|
}
|
|
214
|
-
|
|
205
|
+
|
|
215
206
|
if (plugin.notes) {
|
|
216
207
|
lines.push(`\n**Notes**: ${plugin.notes}`);
|
|
217
208
|
}
|
|
218
|
-
|
|
219
|
-
return lines.join(
|
|
209
|
+
|
|
210
|
+
return lines.join("\n");
|
|
220
211
|
}
|
|
221
212
|
|
|
222
213
|
/**
|
|
@@ -224,33 +215,37 @@ export class FlowQuerySystemPrompt {
|
|
|
224
215
|
*/
|
|
225
216
|
private static generatePluginDocumentation(plugins: FunctionMetadata[]): string {
|
|
226
217
|
if (plugins.length === 0) {
|
|
227
|
-
return
|
|
218
|
+
return "No data loader plugins are currently available.";
|
|
228
219
|
}
|
|
229
|
-
|
|
220
|
+
|
|
230
221
|
const sections: string[] = [];
|
|
231
|
-
|
|
222
|
+
|
|
232
223
|
// Group plugins by category
|
|
233
224
|
const byCategory = new Map<string, FunctionMetadata[]>();
|
|
234
225
|
for (const plugin of plugins) {
|
|
235
|
-
const category = plugin.category ||
|
|
226
|
+
const category = plugin.category || "general";
|
|
236
227
|
if (!byCategory.has(category)) {
|
|
237
228
|
byCategory.set(category, []);
|
|
238
229
|
}
|
|
239
230
|
byCategory.get(category)!.push(plugin);
|
|
240
231
|
}
|
|
241
|
-
|
|
242
|
-
sections.push(
|
|
243
|
-
sections.push(
|
|
244
|
-
|
|
232
|
+
|
|
233
|
+
sections.push("## Available Data Loader Plugins\n");
|
|
234
|
+
sections.push(
|
|
235
|
+
"The following async data loader functions are available for use with `CALL ... YIELD`:\n"
|
|
236
|
+
);
|
|
237
|
+
|
|
245
238
|
for (const [category, categoryPlugins] of byCategory) {
|
|
246
|
-
sections.push(
|
|
239
|
+
sections.push(
|
|
240
|
+
`\n### Category: ${category.charAt(0).toUpperCase() + category.slice(1)}\n`
|
|
241
|
+
);
|
|
247
242
|
for (const plugin of categoryPlugins) {
|
|
248
243
|
sections.push(this.formatPluginDocumentation(plugin));
|
|
249
|
-
sections.push(
|
|
244
|
+
sections.push("---");
|
|
250
245
|
}
|
|
251
246
|
}
|
|
252
|
-
|
|
253
|
-
return sections.join(
|
|
247
|
+
|
|
248
|
+
return sections.join("\n");
|
|
254
249
|
}
|
|
255
250
|
|
|
256
251
|
/**
|
|
@@ -296,15 +291,15 @@ ${FLOWQUERY_LANGUAGE_REFERENCE}
|
|
|
296
291
|
|
|
297
292
|
${pluginDocs}
|
|
298
293
|
|
|
299
|
-
${additionalContext ? `## Additional Context\n\n${additionalContext}` :
|
|
294
|
+
${additionalContext ? `## Additional Context\n\n${additionalContext}` : ""}
|
|
300
295
|
|
|
301
296
|
## Example Response Format
|
|
302
297
|
|
|
303
298
|
**When a query is needed**:
|
|
304
299
|
\`\`\`flowquery
|
|
305
|
-
|
|
306
|
-
WHERE
|
|
307
|
-
RETURN
|
|
300
|
+
CALL pluginName(args) YIELD field1, field2, field3
|
|
301
|
+
WHERE field1 = 'value'
|
|
302
|
+
RETURN field1 AS Name, field2 AS Value
|
|
308
303
|
\`\`\`
|
|
309
304
|
|
|
310
305
|
**When no query is needed** (e.g., general questions about FlowQuery):
|
|
@@ -317,7 +312,7 @@ Now help the user with their request.`;
|
|
|
317
312
|
/**
|
|
318
313
|
* Generate the complete FlowQuery system prompt.
|
|
319
314
|
* Uses FlowQuery's introspection via functions() as the single source of truth.
|
|
320
|
-
*
|
|
315
|
+
*
|
|
321
316
|
* @param additionalContext - Optional additional context to include in the prompt
|
|
322
317
|
* @returns The complete system prompt string
|
|
323
318
|
*/
|
|
@@ -325,14 +320,14 @@ Now help the user with their request.`;
|
|
|
325
320
|
// Uses FlowQuery's introspection to get available async providers
|
|
326
321
|
const plugins = getAllPluginMetadata();
|
|
327
322
|
const pluginDocs = this.generatePluginDocumentation(plugins);
|
|
328
|
-
|
|
323
|
+
|
|
329
324
|
return this.buildSystemPrompt(pluginDocs, additionalContext);
|
|
330
325
|
}
|
|
331
326
|
|
|
332
327
|
/**
|
|
333
328
|
* Generate a system prompt for the interpretation phase.
|
|
334
329
|
* Used after FlowQuery execution to interpret results.
|
|
335
|
-
*
|
|
330
|
+
*
|
|
336
331
|
* @returns The interpretation system prompt string
|
|
337
332
|
*/
|
|
338
333
|
public static generateInterpretationPrompt(): string {
|
|
@@ -363,8 +358,8 @@ You are now receiving the execution results. Your job is to:
|
|
|
363
358
|
*/
|
|
364
359
|
public static getMinimalPrompt(): string {
|
|
365
360
|
const plugins = getAllPluginMetadata();
|
|
366
|
-
const pluginList = plugins.map(p => `- \`${p.name}\`: ${p.description}`).join(
|
|
367
|
-
|
|
361
|
+
const pluginList = plugins.map((p) => `- \`${p.name}\`: ${p.description}`).join("\n");
|
|
362
|
+
|
|
368
363
|
return `You are a FlowQuery assistant. Generate FlowQuery statements based on user requests.
|
|
369
364
|
|
|
370
365
|
Available data loader plugins:
|
|
@@ -379,7 +374,7 @@ Always wrap FlowQuery code in \`\`\`flowquery code blocks.`;
|
|
|
379
374
|
/**
|
|
380
375
|
* Generate the FlowQuery system prompt asynchronously using functions() introspection.
|
|
381
376
|
* This is the preferred method that uses FlowQuery's built-in introspection.
|
|
382
|
-
*
|
|
377
|
+
*
|
|
383
378
|
* @param additionalContext - Optional additional context to include in the prompt
|
|
384
379
|
* @returns Promise resolving to the complete system prompt string
|
|
385
380
|
*/
|
|
@@ -387,15 +382,19 @@ Always wrap FlowQuery code in \`\`\`flowquery code blocks.`;
|
|
|
387
382
|
// Use FlowQuery's functions() introspection to discover available loaders
|
|
388
383
|
const plugins = await getAvailableLoaders();
|
|
389
384
|
const pluginDocs = this.generatePluginDocumentation(plugins);
|
|
390
|
-
|
|
385
|
+
|
|
391
386
|
return this.buildSystemPrompt(pluginDocs, additionalContext);
|
|
392
387
|
}
|
|
393
388
|
}
|
|
394
389
|
|
|
395
390
|
// Export functions for backward compatibility
|
|
396
|
-
export const generateFlowQuerySystemPrompt =
|
|
397
|
-
|
|
398
|
-
export const
|
|
399
|
-
|
|
391
|
+
export const generateFlowQuerySystemPrompt =
|
|
392
|
+
FlowQuerySystemPrompt.generate.bind(FlowQuerySystemPrompt);
|
|
393
|
+
export const generateInterpretationPrompt =
|
|
394
|
+
FlowQuerySystemPrompt.generateInterpretationPrompt.bind(FlowQuerySystemPrompt);
|
|
395
|
+
export const getMinimalFlowQueryPrompt =
|
|
396
|
+
FlowQuerySystemPrompt.getMinimalPrompt.bind(FlowQuerySystemPrompt);
|
|
397
|
+
export const generateFlowQuerySystemPromptAsync =
|
|
398
|
+
FlowQuerySystemPrompt.generateAsync.bind(FlowQuerySystemPrompt);
|
|
400
399
|
|
|
401
400
|
export default FlowQuerySystemPrompt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowquery",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "A declarative query language for data processing pipelines.",
|
|
5
5
|
"main": "dist/index.node.js",
|
|
6
6
|
"types": "dist/index.node.d.ts",
|
|
@@ -31,16 +31,26 @@
|
|
|
31
31
|
"build:node": "tsc",
|
|
32
32
|
"build:browser": "webpack",
|
|
33
33
|
"main": "tsc & node dist/index.js",
|
|
34
|
-
"docs": "typedoc --out docs/api src/index.node.ts"
|
|
34
|
+
"docs": "typedoc --out docs/api src/index.node.ts",
|
|
35
|
+
"prepare": "husky",
|
|
36
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\""
|
|
37
|
+
},
|
|
38
|
+
"lint-staged": {
|
|
39
|
+
"*.{ts,js}": "prettier --write",
|
|
40
|
+
"*.{json,md}": "prettier --write"
|
|
35
41
|
},
|
|
36
42
|
"keywords": [],
|
|
37
43
|
"author": "",
|
|
38
44
|
"license": "ISC",
|
|
39
45
|
"devDependencies": {
|
|
46
|
+
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
40
47
|
"@types/jest": "^29.5.14",
|
|
41
48
|
"@types/node": "^25.0.3",
|
|
42
49
|
"copyfiles": "^2.4.1",
|
|
50
|
+
"husky": "^9.1.7",
|
|
43
51
|
"jest": "^29.7.0",
|
|
52
|
+
"lint-staged": "^15.2.11",
|
|
53
|
+
"prettier": "^3.4.2",
|
|
44
54
|
"ts-jest": "^29.2.5",
|
|
45
55
|
"ts-loader": "^9.5.1",
|
|
46
56
|
"ts-node": "^10.9.2",
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Expression from "./expression";
|
|
2
|
+
|
|
3
|
+
class ExpressionMap {
|
|
4
|
+
private _map: Map<string, Expression> = new Map();
|
|
5
|
+
public get(alias: string): Expression | undefined {
|
|
6
|
+
return this._map.get(alias);
|
|
7
|
+
}
|
|
8
|
+
public has(alias: string): boolean {
|
|
9
|
+
return this._map.has(alias);
|
|
10
|
+
}
|
|
11
|
+
public set map(expressions: Expression[]) {
|
|
12
|
+
this._map.clear();
|
|
13
|
+
for (const expr of expressions) {
|
|
14
|
+
if (expr.alias == undefined) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
this._map.set(expr.alias, expr);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default ExpressionMap;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import Expression from "../expressions/expression";
|
|
2
|
+
import ExpressionMap from "../expressions/expression_map";
|
|
3
|
+
import AsyncFunction from "../functions/async_function";
|
|
4
|
+
import Projection from "./projection";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_VARIABLE_NAME: string = "value";
|
|
7
|
+
|
|
8
|
+
class Call extends Projection {
|
|
9
|
+
protected _function: AsyncFunction | null = null;
|
|
10
|
+
private _map: ExpressionMap = new ExpressionMap();
|
|
11
|
+
protected _results: Record<string, any>[] = [];
|
|
12
|
+
constructor() {
|
|
13
|
+
super([]);
|
|
14
|
+
}
|
|
15
|
+
public set function(asyncFunction: AsyncFunction) {
|
|
16
|
+
this._function = asyncFunction;
|
|
17
|
+
}
|
|
18
|
+
public get function(): AsyncFunction | null {
|
|
19
|
+
return this._function;
|
|
20
|
+
}
|
|
21
|
+
public set yielded(expressions: Expression[]) {
|
|
22
|
+
this.children = expressions;
|
|
23
|
+
this._map.map = expressions;
|
|
24
|
+
}
|
|
25
|
+
public get hasYield(): boolean {
|
|
26
|
+
return this.children.length > 0;
|
|
27
|
+
}
|
|
28
|
+
public async run(): Promise<void> {
|
|
29
|
+
if (this._function === null) {
|
|
30
|
+
throw new Error("No function set for Call operation.");
|
|
31
|
+
}
|
|
32
|
+
const args = this._function.getArguments();
|
|
33
|
+
for await (const item of this._function.generate(...args)) {
|
|
34
|
+
if (!this.isLast) {
|
|
35
|
+
if (typeof item == "object" && !Array.isArray(item)) {
|
|
36
|
+
for (const [key, value] of Object.entries(item)) {
|
|
37
|
+
const expression = this._map.get(key);
|
|
38
|
+
if (expression) {
|
|
39
|
+
expression.overridden = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
const expression = this._map.get(DEFAULT_VARIABLE_NAME);
|
|
44
|
+
if (expression) {
|
|
45
|
+
expression.overridden = item;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
await this.next?.run();
|
|
49
|
+
} else {
|
|
50
|
+
const record: Map<string, any> = new Map();
|
|
51
|
+
if (typeof item == "object" && !Array.isArray(item)) {
|
|
52
|
+
for (const [key, value] of Object.entries(item)) {
|
|
53
|
+
if (this._map.has(key) || !this.hasYield) {
|
|
54
|
+
record.set(key, value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
record.set(DEFAULT_VARIABLE_NAME, item);
|
|
59
|
+
}
|
|
60
|
+
this._results.push(Object.fromEntries(record));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
public get results(): Record<string, any>[] {
|
|
65
|
+
return this._results;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default Call;
|