flowquery 1.0.0 → 1.0.2
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 +2 -0
- package/.github/workflows/release.yml +24 -9
- package/dist/compute/runner.js +75 -0
- package/dist/compute/runner.js.map +1 -0
- package/dist/flowquery.min.js +1 -0
- package/dist/index.browser.js +119 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/index.node.js +123 -0
- package/dist/index.node.js.map +1 -0
- package/dist/io/command_line.js +102 -0
- package/dist/io/command_line.js.map +1 -0
- package/dist/parsing/alias.js +23 -0
- package/dist/parsing/alias.js.map +1 -0
- package/dist/parsing/alias_option.js +11 -0
- package/dist/parsing/alias_option.js.map +1 -0
- package/dist/parsing/ast_node.js +145 -0
- package/dist/parsing/ast_node.js.map +1 -0
- package/dist/parsing/base_parser.js +92 -0
- package/dist/parsing/base_parser.js.map +1 -0
- package/dist/parsing/components/csv.js +13 -0
- package/dist/parsing/components/csv.js.map +1 -0
- package/dist/parsing/components/from.js +16 -0
- package/dist/parsing/components/from.js.map +1 -0
- package/dist/parsing/components/headers.js +16 -0
- package/dist/parsing/components/headers.js.map +1 -0
- package/dist/parsing/components/json.js +13 -0
- package/dist/parsing/components/json.js.map +1 -0
- package/dist/parsing/components/null.js +13 -0
- package/dist/parsing/components/null.js.map +1 -0
- package/dist/parsing/components/post.js +13 -0
- package/dist/parsing/components/post.js.map +1 -0
- package/dist/parsing/components/text.js +13 -0
- package/dist/parsing/components/text.js.map +1 -0
- package/dist/parsing/context.js +47 -0
- package/dist/parsing/context.js.map +1 -0
- package/dist/parsing/data_structures/associative_array.js +45 -0
- package/dist/parsing/data_structures/associative_array.js.map +1 -0
- package/dist/parsing/data_structures/json_array.js +35 -0
- package/dist/parsing/data_structures/json_array.js.map +1 -0
- package/dist/parsing/data_structures/key_value_pair.js +41 -0
- package/dist/parsing/data_structures/key_value_pair.js.map +1 -0
- package/dist/parsing/data_structures/lookup.js +44 -0
- package/dist/parsing/data_structures/lookup.js.map +1 -0
- package/dist/parsing/data_structures/range_lookup.js +40 -0
- package/dist/parsing/data_structures/range_lookup.js.map +1 -0
- package/dist/parsing/expressions/expression.js +142 -0
- package/dist/parsing/expressions/expression.js.map +1 -0
- package/dist/parsing/expressions/f_string.js +29 -0
- package/dist/parsing/expressions/f_string.js.map +1 -0
- package/dist/parsing/expressions/identifier.js +26 -0
- package/dist/parsing/expressions/identifier.js.map +1 -0
- package/dist/parsing/expressions/number.js +41 -0
- package/dist/parsing/expressions/number.js.map +1 -0
- package/dist/parsing/expressions/operator.js +180 -0
- package/dist/parsing/expressions/operator.js.map +1 -0
- package/dist/parsing/expressions/reference.js +45 -0
- package/dist/parsing/expressions/reference.js.map +1 -0
- package/dist/parsing/expressions/string.js +34 -0
- package/dist/parsing/expressions/string.js.map +1 -0
- package/dist/parsing/functions/aggregate_function.js +58 -0
- package/dist/parsing/functions/aggregate_function.js.map +1 -0
- package/dist/parsing/functions/async_function.js +119 -0
- package/dist/parsing/functions/async_function.js.map +1 -0
- package/dist/parsing/functions/avg.js +43 -0
- package/dist/parsing/functions/avg.js.map +1 -0
- package/dist/parsing/functions/collect.js +52 -0
- package/dist/parsing/functions/collect.js.map +1 -0
- package/dist/parsing/functions/function.js +59 -0
- package/dist/parsing/functions/function.js.map +1 -0
- package/dist/parsing/functions/function_factory.js +259 -0
- package/dist/parsing/functions/function_factory.js.map +1 -0
- package/dist/parsing/functions/function_metadata.js +159 -0
- package/dist/parsing/functions/function_metadata.js.map +1 -0
- package/dist/parsing/functions/functions.js +47 -0
- package/dist/parsing/functions/functions.js.map +1 -0
- package/dist/parsing/functions/join.js +29 -0
- package/dist/parsing/functions/join.js.map +1 -0
- package/dist/parsing/functions/predicate_function.js +37 -0
- package/dist/parsing/functions/predicate_function.js.map +1 -0
- package/dist/parsing/functions/predicate_function_factory.js +19 -0
- package/dist/parsing/functions/predicate_function_factory.js.map +1 -0
- package/dist/parsing/functions/predicate_sum.js +33 -0
- package/dist/parsing/functions/predicate_sum.js.map +1 -0
- package/dist/parsing/functions/rand.js +17 -0
- package/dist/parsing/functions/rand.js.map +1 -0
- package/dist/parsing/functions/range.js +22 -0
- package/dist/parsing/functions/range.js.map +1 -0
- package/dist/parsing/functions/reducer_element.js +12 -0
- package/dist/parsing/functions/reducer_element.js.map +1 -0
- package/dist/parsing/functions/replace.js +23 -0
- package/dist/parsing/functions/replace.js.map +1 -0
- package/dist/parsing/functions/round.js +21 -0
- package/dist/parsing/functions/round.js.map +1 -0
- package/dist/parsing/functions/size.js +21 -0
- package/dist/parsing/functions/size.js.map +1 -0
- package/dist/parsing/functions/split.js +29 -0
- package/dist/parsing/functions/split.js.map +1 -0
- package/dist/parsing/functions/stringify.js +29 -0
- package/dist/parsing/functions/stringify.js.map +1 -0
- package/dist/parsing/functions/sum.js +38 -0
- package/dist/parsing/functions/sum.js.map +1 -0
- package/dist/parsing/functions/to_json.js +21 -0
- package/dist/parsing/functions/to_json.js.map +1 -0
- package/dist/parsing/functions/value_holder.js +16 -0
- package/dist/parsing/functions/value_holder.js.map +1 -0
- package/dist/parsing/logic/case.js +27 -0
- package/dist/parsing/logic/case.js.map +1 -0
- package/dist/parsing/logic/else.js +16 -0
- package/dist/parsing/logic/else.js.map +1 -0
- package/dist/parsing/logic/end.js +13 -0
- package/dist/parsing/logic/end.js.map +1 -0
- package/dist/parsing/logic/then.js +16 -0
- package/dist/parsing/logic/then.js.map +1 -0
- package/dist/parsing/logic/when.js +16 -0
- package/dist/parsing/logic/when.js.map +1 -0
- package/dist/parsing/operations/aggregated_return.js +35 -0
- package/dist/parsing/operations/aggregated_return.js.map +1 -0
- package/dist/parsing/operations/aggregated_with.js +41 -0
- package/dist/parsing/operations/aggregated_with.js.map +1 -0
- package/dist/parsing/operations/group_by.js +139 -0
- package/dist/parsing/operations/group_by.js.map +1 -0
- package/dist/parsing/operations/limit.js +38 -0
- package/dist/parsing/operations/limit.js.map +1 -0
- package/dist/parsing/operations/load.js +174 -0
- package/dist/parsing/operations/load.js.map +1 -0
- package/dist/parsing/operations/operation.js +81 -0
- package/dist/parsing/operations/operation.js.map +1 -0
- package/dist/parsing/operations/projection.js +21 -0
- package/dist/parsing/operations/projection.js.map +1 -0
- package/dist/parsing/operations/return.js +60 -0
- package/dist/parsing/operations/return.js.map +1 -0
- package/dist/parsing/operations/unwind.js +46 -0
- package/dist/parsing/operations/unwind.js.map +1 -0
- package/dist/parsing/operations/where.js +53 -0
- package/dist/parsing/operations/where.js.map +1 -0
- package/dist/parsing/operations/with.js +36 -0
- package/dist/parsing/operations/with.js.map +1 -0
- package/dist/parsing/parser.js +812 -0
- package/dist/parsing/parser.js.map +1 -0
- package/dist/parsing/token_to_node.js +121 -0
- package/dist/parsing/token_to_node.js.map +1 -0
- package/dist/tokenization/keyword.js +46 -0
- package/dist/tokenization/keyword.js.map +1 -0
- package/dist/tokenization/operator.js +28 -0
- package/dist/tokenization/operator.js.map +1 -0
- package/dist/tokenization/string_walker.js +165 -0
- package/dist/tokenization/string_walker.js.map +1 -0
- package/dist/tokenization/symbol.js +18 -0
- package/dist/tokenization/symbol.js.map +1 -0
- package/dist/tokenization/token.js +484 -0
- package/dist/tokenization/token.js.map +1 -0
- package/dist/tokenization/token_mapper.js +55 -0
- package/dist/tokenization/token_mapper.js.map +1 -0
- package/dist/tokenization/token_type.js +19 -0
- package/dist/tokenization/token_type.js.map +1 -0
- package/dist/tokenization/tokenizer.js +220 -0
- package/dist/tokenization/tokenizer.js.map +1 -0
- package/dist/tokenization/trie.js +111 -0
- package/dist/tokenization/trie.js.map +1 -0
- package/dist/utils/object_utils.js +19 -0
- package/dist/utils/object_utils.js.map +1 -0
- package/dist/utils/string_utils.js +110 -0
- package/dist/utils/string_utils.js.map +1 -0
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +22 -4
- package/src/compute/runner.ts +45 -0
- package/src/index.browser.ts +118 -0
- package/src/index.node.ts +141 -0
- package/src/parsing/functions/async_function.ts +95 -0
- package/src/parsing/functions/function_factory.ts +230 -1
- package/src/parsing/functions/function_metadata.ts +238 -0
- package/src/parsing/functions/functions.ts +43 -0
- package/src/parsing/operations/load.ts +51 -2
- package/src/parsing/parser.ts +45 -4
- package/tests/parsing/function_plugins.test.ts +369 -0
package/src/index.browser.ts
CHANGED
|
@@ -7,5 +7,123 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import {default as FlowQuery} from "./compute/runner";
|
|
10
|
+
import FunctionFactory, { FunctionCreator, AsyncDataProvider } from "./parsing/functions/function_factory";
|
|
11
|
+
import {
|
|
12
|
+
FunctionMetadata,
|
|
13
|
+
ParameterSchema,
|
|
14
|
+
OutputSchema,
|
|
15
|
+
RegisterFunctionOptions,
|
|
16
|
+
RegisterAsyncProviderOptions
|
|
17
|
+
} from "./parsing/functions/function_metadata";
|
|
18
|
+
import Function from "./parsing/functions/function";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a synchronous plugin function.
|
|
22
|
+
*
|
|
23
|
+
* @param name - The function name
|
|
24
|
+
* @param factoryOrOptions - Factory function or options object with metadata
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```javascript
|
|
28
|
+
* // Simple registration
|
|
29
|
+
* FlowQuery.registerFunction("uppercase", () => new MyUpperCaseFunction());
|
|
30
|
+
*
|
|
31
|
+
* // Registration with metadata for LLM consumption
|
|
32
|
+
* FlowQuery.registerFunction("uppercase", {
|
|
33
|
+
* factory: () => new MyUpperCaseFunction(),
|
|
34
|
+
* metadata: {
|
|
35
|
+
* name: "uppercase",
|
|
36
|
+
* description: "Converts a string to uppercase",
|
|
37
|
+
* category: "string",
|
|
38
|
+
* parameters: [{ name: "text", description: "String to convert", type: "string" }],
|
|
39
|
+
* output: { description: "Uppercase string", type: "string" },
|
|
40
|
+
* examples: ["WITH 'hello' AS s RETURN uppercase(s)"]
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
FlowQuery.registerFunction = function(name: string, factoryOrOptions: FunctionCreator | RegisterFunctionOptions): void {
|
|
46
|
+
FunctionFactory.register(name, factoryOrOptions);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Unregister a synchronous plugin function.
|
|
51
|
+
*
|
|
52
|
+
* @param name - The function name
|
|
53
|
+
*/
|
|
54
|
+
FlowQuery.unregisterFunction = function(name: string): void {
|
|
55
|
+
FunctionFactory.unregister(name);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Register an async data provider function for use in LOAD operations.
|
|
60
|
+
*
|
|
61
|
+
* @param name - The function name
|
|
62
|
+
* @param providerOrOptions - Async provider or options object with metadata
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```javascript
|
|
66
|
+
* // Registration with metadata for LLM consumption
|
|
67
|
+
* FlowQuery.registerAsyncProvider("fetchUsers", {
|
|
68
|
+
* provider: async function* (endpoint) {
|
|
69
|
+
* const response = await fetch(endpoint);
|
|
70
|
+
* const data = await response.json();
|
|
71
|
+
* for (const item of data) yield item;
|
|
72
|
+
* },
|
|
73
|
+
* metadata: {
|
|
74
|
+
* name: "fetchUsers",
|
|
75
|
+
* description: "Fetches user data from an API",
|
|
76
|
+
* category: "data",
|
|
77
|
+
* parameters: [{ name: "endpoint", description: "API URL", type: "string" }],
|
|
78
|
+
* output: {
|
|
79
|
+
* description: "User object",
|
|
80
|
+
* type: "object",
|
|
81
|
+
* properties: {
|
|
82
|
+
* id: { description: "User ID", type: "number" },
|
|
83
|
+
* name: { description: "User name", type: "string" }
|
|
84
|
+
* }
|
|
85
|
+
* },
|
|
86
|
+
* examples: ["LOAD JSON FROM fetchUsers('https://api.example.com/users') AS user"]
|
|
87
|
+
* }
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
FlowQuery.registerAsyncProvider = function(name: string, providerOrOptions: AsyncDataProvider | RegisterAsyncProviderOptions): void {
|
|
92
|
+
FunctionFactory.registerAsyncProvider(name, providerOrOptions);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Unregister an async data provider function.
|
|
97
|
+
*
|
|
98
|
+
* @param name - The function name
|
|
99
|
+
*/
|
|
100
|
+
FlowQuery.unregisterAsyncProvider = function(name: string): void {
|
|
101
|
+
FunctionFactory.unregisterAsyncProvider(name);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* List all registered functions with their metadata.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Optional filter options
|
|
108
|
+
* @returns Array of function metadata
|
|
109
|
+
*/
|
|
110
|
+
FlowQuery.listFunctions = function(options?: { category?: string; asyncOnly?: boolean; syncOnly?: boolean }): FunctionMetadata[] {
|
|
111
|
+
return FunctionFactory.listFunctions(options);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get metadata for a specific function.
|
|
116
|
+
*
|
|
117
|
+
* @param name - The function name
|
|
118
|
+
* @returns Function metadata or undefined
|
|
119
|
+
*/
|
|
120
|
+
FlowQuery.getFunctionMetadata = function(name: string): FunctionMetadata | undefined {
|
|
121
|
+
return FunctionFactory.getMetadata(name);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Base Function class for creating custom plugin functions.
|
|
126
|
+
*/
|
|
127
|
+
FlowQuery.Function = Function;
|
|
10
128
|
|
|
11
129
|
export default FlowQuery;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowQuery - A declarative query language for data processing pipelines.
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for the FlowQuery Node.js library usage.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {default as FlowQuery} from "./compute/runner";
|
|
10
|
+
import FunctionFactory, { FunctionCreator, AsyncDataProvider } from "./parsing/functions/function_factory";
|
|
11
|
+
import {
|
|
12
|
+
FunctionMetadata,
|
|
13
|
+
ParameterSchema,
|
|
14
|
+
OutputSchema,
|
|
15
|
+
RegisterFunctionOptions,
|
|
16
|
+
RegisterAsyncProviderOptions
|
|
17
|
+
} from "./parsing/functions/function_metadata";
|
|
18
|
+
import Function from "./parsing/functions/function";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a synchronous plugin function.
|
|
22
|
+
*
|
|
23
|
+
* @param name - The function name
|
|
24
|
+
* @param factoryOrOptions - Factory function or options object with metadata
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```javascript
|
|
28
|
+
* // Simple registration
|
|
29
|
+
* FlowQuery.registerFunction("uppercase", () => new MyUpperCaseFunction());
|
|
30
|
+
*
|
|
31
|
+
* // Registration with metadata for LLM consumption
|
|
32
|
+
* FlowQuery.registerFunction("uppercase", {
|
|
33
|
+
* factory: () => new MyUpperCaseFunction(),
|
|
34
|
+
* metadata: {
|
|
35
|
+
* name: "uppercase",
|
|
36
|
+
* description: "Converts a string to uppercase",
|
|
37
|
+
* category: "string",
|
|
38
|
+
* parameters: [{ name: "text", description: "String to convert", type: "string" }],
|
|
39
|
+
* output: { description: "Uppercase string", type: "string" },
|
|
40
|
+
* examples: ["WITH 'hello' AS s RETURN uppercase(s)"]
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
FlowQuery.registerFunction = function(name: string, factoryOrOptions: FunctionCreator | RegisterFunctionOptions): void {
|
|
46
|
+
FunctionFactory.register(name, factoryOrOptions);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Unregister a synchronous plugin function.
|
|
51
|
+
*
|
|
52
|
+
* @param name - The function name
|
|
53
|
+
*/
|
|
54
|
+
FlowQuery.unregisterFunction = function(name: string): void {
|
|
55
|
+
FunctionFactory.unregister(name);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Register an async data provider function for use in LOAD operations.
|
|
60
|
+
*
|
|
61
|
+
* @param name - The function name
|
|
62
|
+
* @param providerOrOptions - Async provider or options object with metadata
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```javascript
|
|
66
|
+
* // Registration with metadata for LLM consumption
|
|
67
|
+
* FlowQuery.registerAsyncProvider("fetchUsers", {
|
|
68
|
+
* provider: async function* (endpoint) {
|
|
69
|
+
* const response = await fetch(endpoint);
|
|
70
|
+
* const data = await response.json();
|
|
71
|
+
* for (const item of data) yield item;
|
|
72
|
+
* },
|
|
73
|
+
* metadata: {
|
|
74
|
+
* name: "fetchUsers",
|
|
75
|
+
* description: "Fetches user data from an API",
|
|
76
|
+
* category: "data",
|
|
77
|
+
* parameters: [{ name: "endpoint", description: "API URL", type: "string" }],
|
|
78
|
+
* output: {
|
|
79
|
+
* description: "User object",
|
|
80
|
+
* type: "object",
|
|
81
|
+
* properties: {
|
|
82
|
+
* id: { description: "User ID", type: "number" },
|
|
83
|
+
* name: { description: "User name", type: "string" }
|
|
84
|
+
* }
|
|
85
|
+
* },
|
|
86
|
+
* examples: ["LOAD JSON FROM fetchUsers('https://api.example.com/users') AS user"]
|
|
87
|
+
* }
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
FlowQuery.registerAsyncProvider = function(name: string, providerOrOptions: AsyncDataProvider | RegisterAsyncProviderOptions): void {
|
|
92
|
+
FunctionFactory.registerAsyncProvider(name, providerOrOptions);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Unregister an async data provider function.
|
|
97
|
+
*
|
|
98
|
+
* @param name - The function name
|
|
99
|
+
*/
|
|
100
|
+
FlowQuery.unregisterAsyncProvider = function(name: string): void {
|
|
101
|
+
FunctionFactory.unregisterAsyncProvider(name);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* List all registered functions with their metadata.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Optional filter options
|
|
108
|
+
* @returns Array of function metadata
|
|
109
|
+
*/
|
|
110
|
+
FlowQuery.listFunctions = function(options?: { category?: string; asyncOnly?: boolean; syncOnly?: boolean }): FunctionMetadata[] {
|
|
111
|
+
return FunctionFactory.listFunctions(options);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get metadata for a specific function.
|
|
116
|
+
*
|
|
117
|
+
* @param name - The function name
|
|
118
|
+
* @returns Function metadata or undefined
|
|
119
|
+
*/
|
|
120
|
+
FlowQuery.getFunctionMetadata = function(name: string): FunctionMetadata | undefined {
|
|
121
|
+
return FunctionFactory.getMetadata(name);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Base Function class for creating custom plugin functions.
|
|
126
|
+
*/
|
|
127
|
+
FlowQuery.Function = Function;
|
|
128
|
+
|
|
129
|
+
export default FlowQuery;
|
|
130
|
+
export {
|
|
131
|
+
FlowQuery,
|
|
132
|
+
Function,
|
|
133
|
+
FunctionFactory,
|
|
134
|
+
FunctionCreator,
|
|
135
|
+
AsyncDataProvider,
|
|
136
|
+
FunctionMetadata,
|
|
137
|
+
ParameterSchema,
|
|
138
|
+
OutputSchema,
|
|
139
|
+
RegisterFunctionOptions,
|
|
140
|
+
RegisterAsyncProviderOptions
|
|
141
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import ASTNode from "../ast_node";
|
|
2
|
+
import FunctionFactory from "./function_factory";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents an async data provider function call for use in LOAD operations.
|
|
6
|
+
*
|
|
7
|
+
* This class holds the function name and arguments, and provides async iteration
|
|
8
|
+
* over the results from a registered async data provider.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Used in: LOAD JSON FROM myDataSource('arg1', 'arg2') AS data
|
|
13
|
+
* const asyncFunc = new AsyncFunction("myDataSource");
|
|
14
|
+
* asyncFunc.parameters = [arg1Node, arg2Node];
|
|
15
|
+
* for await (const item of asyncFunc.execute()) {
|
|
16
|
+
* console.log(item);
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
class AsyncFunction extends ASTNode {
|
|
21
|
+
private _name: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new AsyncFunction with the given name.
|
|
25
|
+
*
|
|
26
|
+
* @param name - The function name (must be registered as an async provider)
|
|
27
|
+
*/
|
|
28
|
+
constructor(name: string) {
|
|
29
|
+
super();
|
|
30
|
+
this._name = name;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets the function name.
|
|
35
|
+
*/
|
|
36
|
+
public get name(): string {
|
|
37
|
+
return this._name;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Sets the function parameters.
|
|
42
|
+
*
|
|
43
|
+
* @param nodes - Array of AST nodes representing the function arguments
|
|
44
|
+
*/
|
|
45
|
+
public set parameters(nodes: ASTNode[]) {
|
|
46
|
+
this.children = nodes;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Evaluates all parameters and returns their values.
|
|
51
|
+
*
|
|
52
|
+
* @returns Array of parameter values
|
|
53
|
+
*/
|
|
54
|
+
private getArguments(): any[] {
|
|
55
|
+
return this.children.map(child => child.value());
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Executes the async data provider function and yields results.
|
|
60
|
+
*
|
|
61
|
+
* @yields Data items from the async provider
|
|
62
|
+
* @throws {Error} If the function is not registered as an async provider
|
|
63
|
+
*/
|
|
64
|
+
public async *execute(): AsyncGenerator<any, void, unknown> {
|
|
65
|
+
const provider = FunctionFactory.getAsyncProvider(this._name);
|
|
66
|
+
if (!provider) {
|
|
67
|
+
throw new Error(`Async data provider '${this._name}' is not registered`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const args = this.getArguments();
|
|
71
|
+
const result = provider(...args);
|
|
72
|
+
|
|
73
|
+
// Check if result is an async generator or a promise
|
|
74
|
+
if (result && typeof (result as AsyncGenerator).next === 'function') {
|
|
75
|
+
// It's an async generator
|
|
76
|
+
yield* result as AsyncGenerator<any, void, unknown>;
|
|
77
|
+
} else {
|
|
78
|
+
// It's a promise - await and yield the result
|
|
79
|
+
const data = await result;
|
|
80
|
+
if (Array.isArray(data)) {
|
|
81
|
+
for (const item of data) {
|
|
82
|
+
yield item;
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
yield data;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public toString(): string {
|
|
91
|
+
return `AsyncFunction (${this._name})`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default AsyncFunction;
|
|
@@ -10,7 +10,25 @@ import ToJson from "./to_json";
|
|
|
10
10
|
import Replace from "./replace";
|
|
11
11
|
import Stringify from "./stringify";
|
|
12
12
|
import Size from "./size";
|
|
13
|
+
import Functions from "./functions";
|
|
13
14
|
import Function from "./function";
|
|
15
|
+
import {
|
|
16
|
+
FunctionMetadata,
|
|
17
|
+
RegisterFunctionOptions,
|
|
18
|
+
RegisterAsyncProviderOptions,
|
|
19
|
+
BUILTIN_FUNCTION_METADATA
|
|
20
|
+
} from "./function_metadata";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Type for synchronous function factories.
|
|
24
|
+
*/
|
|
25
|
+
export type FunctionCreator = () => Function;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Type for async data provider functions used in LOAD operations.
|
|
29
|
+
* These functions can yield data asynchronously.
|
|
30
|
+
*/
|
|
31
|
+
export type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
|
|
14
32
|
|
|
15
33
|
/**
|
|
16
34
|
* Factory for creating function instances by name.
|
|
@@ -25,6 +43,208 @@ import Function from "./function";
|
|
|
25
43
|
* ```
|
|
26
44
|
*/
|
|
27
45
|
class FunctionFactory {
|
|
46
|
+
/**
|
|
47
|
+
* Registry for plugin functions (synchronous).
|
|
48
|
+
*/
|
|
49
|
+
private static plugins: Map<string, FunctionCreator> = new Map();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Registry for async data provider functions used in LOAD operations.
|
|
53
|
+
*/
|
|
54
|
+
private static asyncProviders: Map<string, AsyncDataProvider> = new Map();
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Registry for function metadata (both sync and async).
|
|
58
|
+
*/
|
|
59
|
+
private static metadata: Map<string, FunctionMetadata> = new Map();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Registers a synchronous plugin function.
|
|
63
|
+
*
|
|
64
|
+
* @param name - The function name (will be lowercased)
|
|
65
|
+
* @param factoryOrOptions - Factory function or options object with metadata
|
|
66
|
+
*/
|
|
67
|
+
public static register(name: string, factoryOrOptions: FunctionCreator | RegisterFunctionOptions): void {
|
|
68
|
+
const lowerName = name.toLowerCase();
|
|
69
|
+
if (typeof factoryOrOptions === 'function') {
|
|
70
|
+
FunctionFactory.plugins.set(lowerName, factoryOrOptions);
|
|
71
|
+
} else {
|
|
72
|
+
FunctionFactory.plugins.set(lowerName, factoryOrOptions.factory);
|
|
73
|
+
FunctionFactory.metadata.set(lowerName, {
|
|
74
|
+
...factoryOrOptions.metadata,
|
|
75
|
+
name: lowerName,
|
|
76
|
+
isAsyncProvider: false
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Unregisters a synchronous plugin function.
|
|
83
|
+
*
|
|
84
|
+
* @param name - The function name to unregister
|
|
85
|
+
*/
|
|
86
|
+
public static unregister(name: string): void {
|
|
87
|
+
const lowerName = name.toLowerCase();
|
|
88
|
+
FunctionFactory.plugins.delete(lowerName);
|
|
89
|
+
FunctionFactory.metadata.delete(lowerName);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Registers an async data provider function for use in LOAD operations.
|
|
94
|
+
*
|
|
95
|
+
* @param name - The function name (will be lowercased)
|
|
96
|
+
* @param providerOrOptions - Async provider or options object with metadata
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* // Register with metadata for LLM consumption
|
|
101
|
+
* FunctionFactory.registerAsyncProvider("fetchUsers", {
|
|
102
|
+
* provider: async function* (endpoint: string) {
|
|
103
|
+
* const response = await fetch(endpoint);
|
|
104
|
+
* const data = await response.json();
|
|
105
|
+
* for (const item of data) {
|
|
106
|
+
* yield item;
|
|
107
|
+
* }
|
|
108
|
+
* },
|
|
109
|
+
* metadata: {
|
|
110
|
+
* name: "fetchUsers",
|
|
111
|
+
* description: "Fetches user data from an API endpoint",
|
|
112
|
+
* parameters: [
|
|
113
|
+
* { name: "endpoint", description: "API endpoint URL", type: "string" }
|
|
114
|
+
* ],
|
|
115
|
+
* output: {
|
|
116
|
+
* description: "User objects",
|
|
117
|
+
* type: "object",
|
|
118
|
+
* properties: {
|
|
119
|
+
* id: { description: "User ID", type: "number" },
|
|
120
|
+
* name: { description: "User name", type: "string" }
|
|
121
|
+
* }
|
|
122
|
+
* },
|
|
123
|
+
* examples: ["LOAD JSON FROM fetchUsers('https://api.example.com/users') AS user"]
|
|
124
|
+
* }
|
|
125
|
+
* });
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
public static registerAsyncProvider(name: string, providerOrOptions: AsyncDataProvider | RegisterAsyncProviderOptions): void {
|
|
129
|
+
const lowerName = name.toLowerCase();
|
|
130
|
+
if (typeof providerOrOptions === 'function') {
|
|
131
|
+
FunctionFactory.asyncProviders.set(lowerName, providerOrOptions);
|
|
132
|
+
} else {
|
|
133
|
+
FunctionFactory.asyncProviders.set(lowerName, providerOrOptions.provider);
|
|
134
|
+
FunctionFactory.metadata.set(lowerName, {
|
|
135
|
+
...providerOrOptions.metadata,
|
|
136
|
+
name: lowerName,
|
|
137
|
+
isAsyncProvider: true
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Unregisters an async data provider function.
|
|
144
|
+
*
|
|
145
|
+
* @param name - The function name to unregister
|
|
146
|
+
*/
|
|
147
|
+
public static unregisterAsyncProvider(name: string): void {
|
|
148
|
+
const lowerName = name.toLowerCase();
|
|
149
|
+
FunctionFactory.asyncProviders.delete(lowerName);
|
|
150
|
+
FunctionFactory.metadata.delete(lowerName);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Gets an async data provider by name.
|
|
155
|
+
*
|
|
156
|
+
* @param name - The function name (case-insensitive)
|
|
157
|
+
* @returns The async data provider, or undefined if not found
|
|
158
|
+
*/
|
|
159
|
+
public static getAsyncProvider(name: string): AsyncDataProvider | undefined {
|
|
160
|
+
return FunctionFactory.asyncProviders.get(name.toLowerCase());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Checks if a function name is registered as an async data provider.
|
|
165
|
+
*
|
|
166
|
+
* @param name - The function name (case-insensitive)
|
|
167
|
+
* @returns True if the function is an async data provider
|
|
168
|
+
*/
|
|
169
|
+
public static isAsyncProvider(name: string): boolean {
|
|
170
|
+
return FunctionFactory.asyncProviders.has(name.toLowerCase());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Gets metadata for a specific function.
|
|
175
|
+
*
|
|
176
|
+
* @param name - The function name (case-insensitive)
|
|
177
|
+
* @returns The function metadata, or undefined if not found
|
|
178
|
+
*/
|
|
179
|
+
public static getMetadata(name: string): FunctionMetadata | undefined {
|
|
180
|
+
const lowerName = name.toLowerCase();
|
|
181
|
+
// Check plugin metadata first
|
|
182
|
+
if (FunctionFactory.metadata.has(lowerName)) {
|
|
183
|
+
return FunctionFactory.metadata.get(lowerName);
|
|
184
|
+
}
|
|
185
|
+
// Fall back to built-in metadata
|
|
186
|
+
return BUILTIN_FUNCTION_METADATA.find(m => m.name === lowerName);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Lists all registered functions with their metadata.
|
|
191
|
+
* Includes both built-in and plugin functions.
|
|
192
|
+
*
|
|
193
|
+
* @param options - Optional filter options
|
|
194
|
+
* @returns Array of function metadata
|
|
195
|
+
*/
|
|
196
|
+
public static listFunctions(options?: {
|
|
197
|
+
category?: string;
|
|
198
|
+
includeBuiltins?: boolean;
|
|
199
|
+
asyncOnly?: boolean;
|
|
200
|
+
syncOnly?: boolean;
|
|
201
|
+
}): FunctionMetadata[] {
|
|
202
|
+
const result: FunctionMetadata[] = [];
|
|
203
|
+
const includeBuiltins = options?.includeBuiltins !== false;
|
|
204
|
+
|
|
205
|
+
// Add built-in functions
|
|
206
|
+
if (includeBuiltins) {
|
|
207
|
+
for (const meta of BUILTIN_FUNCTION_METADATA) {
|
|
208
|
+
if (options?.category && meta.category !== options.category) continue;
|
|
209
|
+
if (options?.asyncOnly) continue; // Built-ins are sync
|
|
210
|
+
result.push(meta);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Add plugin functions
|
|
215
|
+
for (const [name, meta] of FunctionFactory.metadata) {
|
|
216
|
+
if (options?.category && meta.category !== options.category) continue;
|
|
217
|
+
if (options?.asyncOnly && !meta.isAsyncProvider) continue;
|
|
218
|
+
if (options?.syncOnly && meta.isAsyncProvider) continue;
|
|
219
|
+
result.push(meta);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Lists all registered function names.
|
|
227
|
+
*
|
|
228
|
+
* @returns Array of function names
|
|
229
|
+
*/
|
|
230
|
+
public static listFunctionNames(): string[] {
|
|
231
|
+
const builtinNames = BUILTIN_FUNCTION_METADATA.map(m => m.name);
|
|
232
|
+
const pluginNames = Array.from(FunctionFactory.plugins.keys());
|
|
233
|
+
const asyncNames = Array.from(FunctionFactory.asyncProviders.keys());
|
|
234
|
+
return [...new Set([...builtinNames, ...pluginNames, ...asyncNames])];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Gets all function metadata as a JSON-serializable object for LLM consumption.
|
|
239
|
+
*
|
|
240
|
+
* @returns Object with functions grouped by category
|
|
241
|
+
*/
|
|
242
|
+
public static toJSON(): { functions: FunctionMetadata[]; categories: string[] } {
|
|
243
|
+
const functions = FunctionFactory.listFunctions();
|
|
244
|
+
const categories = [...new Set(functions.map(f => f.category).filter(Boolean))] as string[];
|
|
245
|
+
return { functions, categories };
|
|
246
|
+
}
|
|
247
|
+
|
|
28
248
|
/**
|
|
29
249
|
* Creates a function instance by name.
|
|
30
250
|
*
|
|
@@ -32,7 +252,14 @@ class FunctionFactory {
|
|
|
32
252
|
* @returns A Function instance of the appropriate type
|
|
33
253
|
*/
|
|
34
254
|
public static create(name: string): Function {
|
|
35
|
-
|
|
255
|
+
const lowerName = name.toLowerCase();
|
|
256
|
+
|
|
257
|
+
// Check plugin registry first (allows overriding built-ins)
|
|
258
|
+
if (FunctionFactory.plugins.has(lowerName)) {
|
|
259
|
+
return FunctionFactory.plugins.get(lowerName)!();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
switch (lowerName) {
|
|
36
263
|
case "sum":
|
|
37
264
|
return new Sum();
|
|
38
265
|
case "collect":
|
|
@@ -57,6 +284,8 @@ class FunctionFactory {
|
|
|
57
284
|
return new Stringify();
|
|
58
285
|
case "size":
|
|
59
286
|
return new Size();
|
|
287
|
+
case "functions":
|
|
288
|
+
return new Functions();
|
|
60
289
|
default:
|
|
61
290
|
return new Function(name);
|
|
62
291
|
}
|