flowquery 1.0.6 → 1.0.7

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.
Files changed (49) hide show
  1. package/README.md +30 -138
  2. package/dist/compute/runner.d.ts +1 -22
  3. package/dist/compute/runner.d.ts.map +1 -1
  4. package/dist/compute/runner.js.map +1 -1
  5. package/dist/extensibility.d.ts +28 -2
  6. package/dist/extensibility.d.ts.map +1 -1
  7. package/dist/extensibility.js +39 -15
  8. package/dist/extensibility.js.map +1 -1
  9. package/dist/flowquery.min.js +1 -1
  10. package/dist/index.browser.d.ts.map +1 -1
  11. package/dist/index.browser.js +0 -80
  12. package/dist/index.browser.js.map +1 -1
  13. package/dist/index.node.d.ts +3 -3
  14. package/dist/index.node.d.ts.map +1 -1
  15. package/dist/index.node.js +0 -80
  16. package/dist/index.node.js.map +1 -1
  17. package/dist/parsing/functions/function_factory.d.ts +3 -80
  18. package/dist/parsing/functions/function_factory.d.ts.map +1 -1
  19. package/dist/parsing/functions/function_factory.js +8 -127
  20. package/dist/parsing/functions/function_factory.js.map +1 -1
  21. package/dist/parsing/functions/function_metadata.d.ts +32 -22
  22. package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
  23. package/dist/parsing/functions/function_metadata.js +53 -1
  24. package/dist/parsing/functions/function_metadata.js.map +1 -1
  25. package/docs/flowquery.min.js +1 -1
  26. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
  27. package/misc/apps/RAG/package.json +1 -1
  28. package/misc/apps/RAG/src/plugins/index.ts +29 -33
  29. package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +28 -32
  30. package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +29 -33
  31. package/misc/apps/RAG/src/plugins/loaders/Llm.ts +55 -59
  32. package/misc/apps/RAG/src/plugins/loaders/MockData.ts +61 -71
  33. package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +8 -8
  34. package/package.json +1 -1
  35. package/src/compute/runner.ts +1 -26
  36. package/src/extensibility.ts +38 -2
  37. package/src/index.browser.ts +2 -88
  38. package/src/index.node.ts +3 -92
  39. package/src/parsing/functions/function_factory.ts +13 -154
  40. package/src/parsing/functions/function_metadata.ts +68 -25
  41. package/tests/extensibility.test.ts +563 -0
  42. package/dist/parsing/functions/extensibility/index.d.ts +0 -37
  43. package/dist/parsing/functions/extensibility/index.d.ts.map +0 -1
  44. package/dist/parsing/functions/extensibility/index.js +0 -50
  45. package/dist/parsing/functions/extensibility/index.js.map +0 -1
  46. package/misc/apps/RAG/src/plugins/PluginRegistry.ts +0 -136
  47. package/misc/apps/RAG/src/plugins/types.ts +0 -52
  48. package/src/parsing/functions/extensibility/index.ts +0 -54
  49. package/tests/parsing/function_plugins.test.ts +0 -369
@@ -7,100 +7,14 @@
7
7
  */
8
8
 
9
9
  import {default as FlowQuery} from "./compute/runner";
10
- import FunctionFactory, { FunctionCreator, AsyncDataProvider } from "./parsing/functions/function_factory";
10
+ import FunctionFactory from "./parsing/functions/function_factory";
11
11
  import {
12
12
  FunctionMetadata,
13
13
  ParameterSchema,
14
- OutputSchema,
15
- RegisterFunctionOptions,
16
- RegisterAsyncProviderOptions
14
+ OutputSchema
17
15
  } from "./parsing/functions/function_metadata";
18
16
  import Function from "./parsing/functions/function";
19
17
 
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
18
  /**
105
19
  * List all registered functions with their metadata.
106
20
  *
package/src/index.node.ts CHANGED
@@ -7,100 +7,14 @@
7
7
  */
8
8
 
9
9
  import {default as FlowQuery} from "./compute/runner";
10
- import FunctionFactory, { FunctionCreator, AsyncDataProvider } from "./parsing/functions/function_factory";
10
+ import FunctionFactory, { AsyncDataProvider } from "./parsing/functions/function_factory";
11
11
  import {
12
12
  FunctionMetadata,
13
13
  ParameterSchema,
14
- OutputSchema,
15
- RegisterFunctionOptions,
16
- RegisterAsyncProviderOptions
14
+ OutputSchema
17
15
  } from "./parsing/functions/function_metadata";
18
16
  import Function from "./parsing/functions/function";
19
17
 
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
18
  /**
105
19
  * List all registered functions with their metadata.
106
20
  *
@@ -131,11 +45,8 @@ export {
131
45
  FlowQuery,
132
46
  Function,
133
47
  FunctionFactory,
134
- FunctionCreator,
135
48
  AsyncDataProvider,
136
49
  FunctionMetadata,
137
50
  ParameterSchema,
138
- OutputSchema,
139
- RegisterFunctionOptions,
140
- RegisterAsyncProviderOptions
51
+ OutputSchema
141
52
  };
@@ -17,27 +17,20 @@ import "./functions";
17
17
  import "./predicate_sum";
18
18
  import {
19
19
  FunctionMetadata,
20
- RegisterFunctionOptions,
21
- RegisterAsyncProviderOptions,
22
20
  getRegisteredFunctionMetadata,
23
21
  getFunctionMetadata,
24
- getRegisteredFunctionFactory
22
+ getRegisteredFunctionFactory,
23
+ getRegisteredAsyncProvider,
24
+ AsyncDataProvider
25
25
  } from "./function_metadata";
26
26
 
27
- /**
28
- * Type for synchronous function factories.
29
- */
30
- export type FunctionCreator = () => Function;
31
-
32
- /**
33
- * Type for async data provider functions used in LOAD operations.
34
- * These functions can yield data asynchronously.
35
- */
36
- export type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
27
+ // Re-export AsyncDataProvider for backwards compatibility
28
+ export { AsyncDataProvider };
37
29
 
38
30
  /**
39
31
  * Factory for creating function instances by name.
40
32
  *
33
+ * All functions are registered via the @FunctionDef decorator.
41
34
  * Maps function names (case-insensitive) to their corresponding implementation classes.
42
35
  * Supports built-in functions like sum, avg, collect, range, split, join, etc.
43
36
  *
@@ -48,113 +41,6 @@ export type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, un
48
41
  * ```
49
42
  */
50
43
  class FunctionFactory {
51
- /**
52
- * Registry for plugin functions (synchronous).
53
- */
54
- private static plugins: Map<string, FunctionCreator> = new Map();
55
-
56
- /**
57
- * Registry for async data provider functions used in LOAD operations.
58
- */
59
- private static asyncProviders: Map<string, AsyncDataProvider> = new Map();
60
-
61
- /**
62
- * Registry for function metadata (both sync and async).
63
- */
64
- private static metadata: Map<string, FunctionMetadata> = new Map();
65
-
66
- /**
67
- * Registers a synchronous plugin function.
68
- *
69
- * @param name - The function name (will be lowercased)
70
- * @param factoryOrOptions - Factory function or options object with metadata
71
- */
72
- public static register(name: string, factoryOrOptions: FunctionCreator | RegisterFunctionOptions): void {
73
- const lowerName = name.toLowerCase();
74
- if (typeof factoryOrOptions === 'function') {
75
- FunctionFactory.plugins.set(lowerName, factoryOrOptions);
76
- } else {
77
- FunctionFactory.plugins.set(lowerName, factoryOrOptions.factory);
78
- FunctionFactory.metadata.set(lowerName, {
79
- ...factoryOrOptions.metadata,
80
- name: lowerName,
81
- isAsyncProvider: false
82
- });
83
- }
84
- }
85
-
86
- /**
87
- * Unregisters a synchronous plugin function.
88
- *
89
- * @param name - The function name to unregister
90
- */
91
- public static unregister(name: string): void {
92
- const lowerName = name.toLowerCase();
93
- FunctionFactory.plugins.delete(lowerName);
94
- FunctionFactory.metadata.delete(lowerName);
95
- }
96
-
97
- /**
98
- * Registers an async data provider function for use in LOAD operations.
99
- *
100
- * @param name - The function name (will be lowercased)
101
- * @param providerOrOptions - Async provider or options object with metadata
102
- *
103
- * @example
104
- * ```typescript
105
- * // Register with metadata for LLM consumption
106
- * FunctionFactory.registerAsyncProvider("fetchUsers", {
107
- * provider: async function* (endpoint: string) {
108
- * const response = await fetch(endpoint);
109
- * const data = await response.json();
110
- * for (const item of data) {
111
- * yield item;
112
- * }
113
- * },
114
- * metadata: {
115
- * name: "fetchUsers",
116
- * description: "Fetches user data from an API endpoint",
117
- * parameters: [
118
- * { name: "endpoint", description: "API endpoint URL", type: "string" }
119
- * ],
120
- * output: {
121
- * description: "User objects",
122
- * type: "object",
123
- * properties: {
124
- * id: { description: "User ID", type: "number" },
125
- * name: { description: "User name", type: "string" }
126
- * }
127
- * },
128
- * examples: ["LOAD JSON FROM fetchUsers('https://api.example.com/users') AS user"]
129
- * }
130
- * });
131
- * ```
132
- */
133
- public static registerAsyncProvider(name: string, providerOrOptions: AsyncDataProvider | RegisterAsyncProviderOptions): void {
134
- const lowerName = name.toLowerCase();
135
- if (typeof providerOrOptions === 'function') {
136
- FunctionFactory.asyncProviders.set(lowerName, providerOrOptions);
137
- } else {
138
- FunctionFactory.asyncProviders.set(lowerName, providerOrOptions.provider);
139
- FunctionFactory.metadata.set(lowerName, {
140
- ...providerOrOptions.metadata,
141
- name: lowerName,
142
- isAsyncProvider: true
143
- });
144
- }
145
- }
146
-
147
- /**
148
- * Unregisters an async data provider function.
149
- *
150
- * @param name - The function name to unregister
151
- */
152
- public static unregisterAsyncProvider(name: string): void {
153
- const lowerName = name.toLowerCase();
154
- FunctionFactory.asyncProviders.delete(lowerName);
155
- FunctionFactory.metadata.delete(lowerName);
156
- }
157
-
158
44
  /**
159
45
  * Gets an async data provider by name.
160
46
  *
@@ -162,7 +48,7 @@ class FunctionFactory {
162
48
  * @returns The async data provider, or undefined if not found
163
49
  */
164
50
  public static getAsyncProvider(name: string): AsyncDataProvider | undefined {
165
- return FunctionFactory.asyncProviders.get(name.toLowerCase());
51
+ return getRegisteredAsyncProvider(name.toLowerCase());
166
52
  }
167
53
 
168
54
  /**
@@ -172,7 +58,7 @@ class FunctionFactory {
172
58
  * @returns True if the function is an async data provider
173
59
  */
174
60
  public static isAsyncProvider(name: string): boolean {
175
- return FunctionFactory.asyncProviders.has(name.toLowerCase());
61
+ return getRegisteredAsyncProvider(name.toLowerCase()) !== undefined;
176
62
  }
177
63
 
178
64
  /**
@@ -182,45 +68,26 @@ class FunctionFactory {
182
68
  * @returns The function metadata, or undefined if not found
183
69
  */
184
70
  public static getMetadata(name: string): FunctionMetadata | undefined {
185
- const lowerName = name.toLowerCase();
186
- // Check plugin metadata first
187
- if (FunctionFactory.metadata.has(lowerName)) {
188
- return FunctionFactory.metadata.get(lowerName);
189
- }
190
- // Fall back to decorator-registered metadata
191
- return getFunctionMetadata(lowerName);
71
+ return getFunctionMetadata(name.toLowerCase());
192
72
  }
193
73
 
194
74
  /**
195
75
  * Lists all registered functions with their metadata.
196
- * Includes both built-in and plugin functions.
197
76
  *
198
77
  * @param options - Optional filter options
199
78
  * @returns Array of function metadata
200
79
  */
201
80
  public static listFunctions(options?: {
202
81
  category?: string;
203
- includeBuiltins?: boolean;
204
82
  asyncOnly?: boolean;
205
83
  syncOnly?: boolean;
206
84
  }): FunctionMetadata[] {
207
85
  const result: FunctionMetadata[] = [];
208
- const includeBuiltins = options?.includeBuiltins !== false;
209
-
210
- // Add decorator-registered functions (built-ins)
211
- if (includeBuiltins) {
212
- for (const meta of getRegisteredFunctionMetadata()) {
213
- if (options?.category && meta.category !== options.category) continue;
214
- if (options?.asyncOnly) continue; // Built-ins are sync
215
- result.push(meta);
216
- }
217
- }
218
86
 
219
- // Add plugin functions
220
- for (const [name, meta] of FunctionFactory.metadata) {
87
+ for (const meta of getRegisteredFunctionMetadata()) {
221
88
  if (options?.category && meta.category !== options.category) continue;
222
- if (options?.asyncOnly && !meta.isAsyncProvider) continue;
223
- if (options?.syncOnly && meta.isAsyncProvider) continue;
89
+ if (options?.asyncOnly && meta.category !== 'async') continue;
90
+ if (options?.syncOnly && meta.category === 'async') continue;
224
91
  result.push(meta);
225
92
  }
226
93
 
@@ -233,10 +100,7 @@ class FunctionFactory {
233
100
  * @returns Array of function names
234
101
  */
235
102
  public static listFunctionNames(): string[] {
236
- const builtinNames = getRegisteredFunctionMetadata().map(m => m.name);
237
- const pluginNames = Array.from(FunctionFactory.plugins.keys());
238
- const asyncNames = Array.from(FunctionFactory.asyncProviders.keys());
239
- return [...new Set([...builtinNames, ...pluginNames, ...asyncNames])];
103
+ return getRegisteredFunctionMetadata().map(m => m.name);
240
104
  }
241
105
 
242
106
  /**
@@ -259,11 +123,6 @@ class FunctionFactory {
259
123
  public static create(name: string): Function {
260
124
  const lowerName = name.toLowerCase();
261
125
 
262
- // Check plugin registry first (allows overriding built-ins)
263
- if (FunctionFactory.plugins.has(lowerName)) {
264
- return FunctionFactory.plugins.get(lowerName)!();
265
- }
266
-
267
126
  // Check decorator-registered functions (built-ins use @FunctionDef)
268
127
  const decoratorFactory = getRegisteredFunctionFactory(lowerName);
269
128
  if (decoratorFactory) {
@@ -3,7 +3,7 @@
3
3
  * Core categories: scalar, aggregate, predicate, async
4
4
  * Additional categories for organization: string, math, data, etc.
5
5
  */
6
- export type FunctionCategory = "scalar" | "aggregate" | "predicate" | "async" | "string" | "math" | "data" | "introspection" | string;
6
+ export type FunctionCategory = "scalar" | "aggregate" | "predicate" | "async" | string;
7
7
 
8
8
  /**
9
9
  * Schema definition for function arguments and outputs.
@@ -54,8 +54,8 @@ export interface FunctionMetadata {
54
54
  name: string;
55
55
  /** Human-readable description of what the function does */
56
56
  description: string;
57
- /** Category for grouping functions */
58
- category?: FunctionCategory;
57
+ /** Category that determines function type and behavior */
58
+ category: FunctionCategory;
59
59
  /** Array of parameter schemas */
60
60
  parameters: ParameterSchema[];
61
61
  /** Output schema */
@@ -64,40 +64,28 @@ export interface FunctionMetadata {
64
64
  examples?: string[];
65
65
  /** Additional notes or caveats */
66
66
  notes?: string;
67
- /** Whether this is an async data provider (for LOAD operations) */
68
- isAsyncProvider?: boolean;
69
67
  }
70
68
 
71
69
  /**
72
- * Options for registering a sync function with metadata.
70
+ * Registry for function metadata collected via decorators.
73
71
  */
74
- export interface RegisterFunctionOptions {
75
- /** Factory function that creates the Function instance */
76
- factory: () => any;
77
- /** Function metadata for documentation */
78
- metadata: FunctionMetadata;
79
- }
72
+ const functionMetadataRegistry: Map<string, FunctionMetadata> = new Map();
80
73
 
81
74
  /**
82
- * Options for registering an async data provider with metadata.
75
+ * Registry for function factories collected via decorators.
76
+ * Allows @FunctionDef to automatically register functions for instantiation.
83
77
  */
84
- export interface RegisterAsyncProviderOptions {
85
- /** Async generator or function that returns data */
86
- provider: (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
87
- /** Function metadata for documentation */
88
- metadata: FunctionMetadata;
89
- }
78
+ const functionFactoryRegistry: Map<string, () => any> = new Map();
90
79
 
91
80
  /**
92
- * Registry for function metadata collected via decorators.
81
+ * Type for async data provider functions used in LOAD operations.
93
82
  */
94
- const functionMetadataRegistry: Map<string, FunctionMetadata> = new Map();
83
+ export type AsyncDataProvider = (...args: any[]) => AsyncGenerator<any, void, unknown> | Promise<any>;
95
84
 
96
85
  /**
97
- * Registry for function factories collected via decorators.
98
- * Allows @FunctionDef to automatically register functions for instantiation.
86
+ * Registry for async data providers collected via decorators.
99
87
  */
100
- const functionFactoryRegistry: Map<string, () => any> = new Map();
88
+ const asyncProviderRegistry: Map<string, AsyncDataProvider> = new Map();
101
89
 
102
90
  /**
103
91
  * Decorator options - metadata without the name (derived from class).
@@ -106,13 +94,19 @@ export type FunctionDefOptions = Omit<FunctionMetadata, 'name'>;
106
94
 
107
95
  /**
108
96
  * Class decorator that registers function metadata.
109
- * The function name is derived from the class's constructor call to super().
97
+ * The function name is derived from the class's constructor call to super() for regular functions,
98
+ * or from the class name for async providers.
99
+ *
100
+ * For async providers (category: "async"), the class must have a `fetch` method that returns
101
+ * an AsyncGenerator. The function name is derived from the class name (removing 'Loader' suffix
102
+ * if present) and converted to camelCase.
110
103
  *
111
104
  * @param options - Function metadata (excluding name)
112
105
  * @returns Class decorator
113
106
  *
114
107
  * @example
115
108
  * ```typescript
109
+ * // Regular function
116
110
  * @FunctionDef({
117
111
  * description: "Calculates the sum of numeric values",
118
112
  * category: "aggregate",
@@ -121,10 +115,48 @@ export type FunctionDefOptions = Omit<FunctionMetadata, 'name'>;
121
115
  * examples: ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN sum(n)"]
122
116
  * })
123
117
  * class Sum extends AggregateFunction { ... }
118
+ *
119
+ * // Async data provider
120
+ * @FunctionDef({
121
+ * description: "Fetches random cat facts from the Cat Facts API",
122
+ * category: "async",
123
+ * parameters: [{ name: "count", description: "Number of facts", type: "number", required: false, default: 1 }],
124
+ * output: { description: "Cat fact object", type: "object" },
125
+ * examples: ["LOAD JSON FROM catFacts(5) AS fact RETURN fact.text"]
126
+ * })
127
+ * class CatFactsLoader {
128
+ * async *fetch(count: number = 1): AsyncGenerator<any> { ... }
129
+ * }
124
130
  * ```
125
131
  */
126
132
  export function FunctionDef(options: FunctionDefOptions) {
127
133
  return function <T extends new (...args: any[]) => any>(constructor: T): T {
134
+ // Handle async providers differently
135
+ if (options.category === 'async') {
136
+ // Derive the function name from the class name
137
+ // Remove 'Loader' suffix if present and convert to lowercase for registry
138
+ let baseName = constructor.name;
139
+ if (baseName.endsWith('Loader')) {
140
+ baseName = baseName.slice(0, -6);
141
+ }
142
+ // Keep display name in camelCase, but use lowercase for registry keys
143
+ const displayName = baseName.charAt(0).toLowerCase() + baseName.slice(1);
144
+ const registryKey = displayName.toLowerCase();
145
+
146
+ // Register metadata with display name
147
+ const metadata: FunctionMetadata = {
148
+ name: displayName,
149
+ ...options
150
+ };
151
+ functionMetadataRegistry.set(registryKey, metadata);
152
+
153
+ // Register the async provider (wraps the class's fetch method)
154
+ asyncProviderRegistry.set(registryKey, (...args: any[]) => new constructor().fetch(...args));
155
+
156
+ return constructor;
157
+ }
158
+
159
+ // Regular function handling
128
160
  // Create an instance to get the function name from super() call
129
161
  const instance = new constructor();
130
162
  const baseName = instance.name?.toLowerCase() || constructor.name.toLowerCase();
@@ -212,3 +244,14 @@ export function getFunctionMetadata(name: string, category?: string): FunctionMe
212
244
 
213
245
  return undefined;
214
246
  }
247
+
248
+ /**
249
+ * Gets a registered async data provider by name.
250
+ * Used by FunctionFactory to get decorator-registered async providers.
251
+ *
252
+ * @param name - Function name (case-insensitive)
253
+ * @returns Async data provider or undefined
254
+ */
255
+ export function getRegisteredAsyncProvider(name: string): AsyncDataProvider | undefined {
256
+ return asyncProviderRegistry.get(name.toLowerCase());
257
+ }