flowquery 1.0.5 → 1.0.6
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/README.md +182 -0
- package/dist/extensibility.d.ts +9 -0
- package/dist/extensibility.d.ts.map +1 -0
- package/dist/extensibility.js +25 -0
- package/dist/extensibility.js.map +1 -0
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/functions/avg.d.ts.map +1 -1
- package/dist/parsing/functions/avg.js +20 -2
- package/dist/parsing/functions/avg.js.map +1 -1
- package/dist/parsing/functions/collect.d.ts.map +1 -1
- package/dist/parsing/functions/collect.js +20 -2
- package/dist/parsing/functions/collect.js.map +1 -1
- package/dist/parsing/functions/extensibility/index.d.ts +37 -0
- package/dist/parsing/functions/extensibility/index.d.ts.map +1 -0
- package/dist/parsing/functions/extensibility/index.js +50 -0
- package/dist/parsing/functions/extensibility/index.js.map +1 -0
- package/dist/parsing/functions/function_factory.d.ts +23 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +44 -47
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/function_metadata.d.ts +57 -6
- package/dist/parsing/functions/function_metadata.d.ts.map +1 -1
- package/dist/parsing/functions/function_metadata.js +103 -153
- package/dist/parsing/functions/function_metadata.js.map +1 -1
- package/dist/parsing/functions/functions.d.ts.map +1 -1
- package/dist/parsing/functions/functions.js +37 -2
- package/dist/parsing/functions/functions.js.map +1 -1
- package/dist/parsing/functions/join.d.ts.map +1 -1
- package/dist/parsing/functions/join.js +21 -2
- package/dist/parsing/functions/join.js.map +1 -1
- package/dist/parsing/functions/predicate_function.d.ts +1 -0
- package/dist/parsing/functions/predicate_function.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_function.js +3 -0
- package/dist/parsing/functions/predicate_function.js.map +1 -1
- package/dist/parsing/functions/predicate_sum.d.ts.map +1 -1
- package/dist/parsing/functions/predicate_sum.js +23 -2
- package/dist/parsing/functions/predicate_sum.js.map +1 -1
- package/dist/parsing/functions/rand.d.ts.map +1 -1
- package/dist/parsing/functions/rand.js +18 -2
- package/dist/parsing/functions/rand.js.map +1 -1
- package/dist/parsing/functions/range.d.ts.map +1 -1
- package/dist/parsing/functions/range.js +21 -2
- package/dist/parsing/functions/range.js.map +1 -1
- package/dist/parsing/functions/replace.d.ts.map +1 -1
- package/dist/parsing/functions/replace.js +22 -2
- package/dist/parsing/functions/replace.js.map +1 -1
- package/dist/parsing/functions/round.d.ts.map +1 -1
- package/dist/parsing/functions/round.js +20 -2
- package/dist/parsing/functions/round.js.map +1 -1
- package/dist/parsing/functions/size.d.ts.map +1 -1
- package/dist/parsing/functions/size.js +20 -2
- package/dist/parsing/functions/size.js.map +1 -1
- package/dist/parsing/functions/split.d.ts.map +1 -1
- package/dist/parsing/functions/split.js +21 -2
- package/dist/parsing/functions/split.js.map +1 -1
- package/dist/parsing/functions/stringify.d.ts.map +1 -1
- package/dist/parsing/functions/stringify.js +20 -2
- package/dist/parsing/functions/stringify.js.map +1 -1
- package/dist/parsing/functions/sum.d.ts.map +1 -1
- package/dist/parsing/functions/sum.js +20 -2
- package/dist/parsing/functions/sum.js.map +1 -1
- package/dist/parsing/functions/to_json.d.ts.map +1 -1
- package/dist/parsing/functions/to_json.js +20 -2
- package/dist/parsing/functions/to_json.js.map +1 -1
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +1 -2
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/.env.example +14 -0
- package/misc/apps/RAG/README.md +0 -7
- package/misc/apps/RAG/package.json +16 -7
- package/misc/apps/RAG/public/index.html +18 -0
- package/misc/apps/RAG/src/App.css +42 -0
- package/misc/apps/RAG/src/App.tsx +50 -0
- package/misc/apps/RAG/src/components/ApiKeySettings.tsx +245 -0
- package/misc/apps/RAG/src/components/ChatContainer.css +67 -0
- package/misc/apps/RAG/src/components/ChatContainer.tsx +239 -0
- package/misc/apps/RAG/src/components/ChatInput.css +23 -0
- package/misc/apps/RAG/src/components/ChatInput.tsx +62 -0
- package/misc/apps/RAG/src/components/ChatMessage.css +136 -0
- package/misc/apps/RAG/src/components/ChatMessage.tsx +152 -0
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +390 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.css +104 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +332 -0
- package/misc/apps/RAG/src/components/index.ts +15 -0
- package/misc/apps/RAG/src/index.tsx +17 -0
- package/misc/apps/RAG/src/plugins/PluginRegistry.ts +136 -0
- package/misc/apps/RAG/src/plugins/README.md +139 -0
- package/misc/apps/RAG/src/plugins/index.ts +72 -0
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +79 -0
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +71 -0
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +441 -0
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +161 -0
- package/misc/apps/RAG/src/plugins/types.ts +52 -0
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +385 -0
- package/misc/apps/RAG/src/prompts/index.ts +10 -0
- package/misc/apps/RAG/src/utils/FlowQueryExecutor.ts +131 -0
- package/misc/apps/RAG/src/utils/FlowQueryExtractor.ts +203 -0
- package/misc/apps/RAG/src/utils/index.ts +9 -0
- package/misc/apps/RAG/tsconfig.json +4 -2
- package/misc/apps/RAG/webpack.config.js +23 -12
- package/package.json +7 -1
- package/src/extensibility.ts +9 -0
- package/src/parsing/functions/avg.ts +10 -0
- package/src/parsing/functions/collect.ts +10 -0
- package/src/parsing/functions/extensibility/index.ts +54 -0
- package/src/parsing/functions/function_factory.ts +51 -48
- package/src/parsing/functions/function_metadata.ts +132 -156
- package/src/parsing/functions/functions.ts +27 -0
- package/src/parsing/functions/join.ts +11 -0
- package/src/parsing/functions/predicate_function.ts +4 -0
- package/src/parsing/functions/predicate_sum.ts +13 -0
- package/src/parsing/functions/rand.ts +8 -0
- package/src/parsing/functions/range.ts +11 -0
- package/src/parsing/functions/replace.ts +12 -0
- package/src/parsing/functions/round.ts +10 -0
- package/src/parsing/functions/size.ts +10 -0
- package/src/parsing/functions/split.ts +11 -0
- package/src/parsing/functions/stringify.ts +10 -0
- package/src/parsing/functions/sum.ts +10 -0
- package/src/parsing/functions/to_json.ts +10 -0
- package/src/parsing/parser.ts +1 -2
- package/tests/parsing/function_plugins.test.ts +11 -11
- package/tsconfig.json +1 -0
- package/dist/parsing/functions/predicate_function_factory.d.ts +0 -6
- package/dist/parsing/functions/predicate_function_factory.d.ts.map +0 -1
- package/dist/parsing/functions/predicate_function_factory.js +0 -19
- package/dist/parsing/functions/predicate_function_factory.js.map +0 -1
- package/misc/apps/RAG/src/index.ts +0 -20
- package/src/parsing/functions/predicate_function_factory.ts +0 -15
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowQuery Extraction Utility
|
|
3
|
+
*
|
|
4
|
+
* Extracts FlowQuery statements from LLM responses.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extraction result containing the query and any explanation text.
|
|
9
|
+
*/
|
|
10
|
+
export interface FlowQueryExtraction {
|
|
11
|
+
/** The extracted FlowQuery statement, if found */
|
|
12
|
+
query: string | null;
|
|
13
|
+
/** Whether a query was successfully extracted */
|
|
14
|
+
found: boolean;
|
|
15
|
+
/** Any explanation text before the code block */
|
|
16
|
+
explanation?: string;
|
|
17
|
+
/** Whether the LLM indicated no query is needed */
|
|
18
|
+
noQueryNeeded?: boolean;
|
|
19
|
+
/** Message from the LLM if no query is needed */
|
|
20
|
+
directResponse?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* FlowQuery Extractor class for extracting FlowQuery statements from LLM responses.
|
|
25
|
+
*
|
|
26
|
+
* Looks for code blocks with flowquery, cypher, or sql language tags,
|
|
27
|
+
* or generic code blocks that appear to contain FlowQuery syntax.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const extractor = new FlowQueryExtractor();
|
|
32
|
+
* const response = `Here's the query:
|
|
33
|
+
* \`\`\`flowquery
|
|
34
|
+
* LOAD JSON FROM somePlugin(5) AS item
|
|
35
|
+
* RETURN item.text
|
|
36
|
+
* \`\`\``;
|
|
37
|
+
*
|
|
38
|
+
* const extraction = extractor.extract(response);
|
|
39
|
+
* console.log(extraction.query); // "LOAD JSON FROM somePlugin(5) AS item\nRETURN item.text"
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class FlowQueryExtractor {
|
|
43
|
+
/** Regex patterns for matching code blocks with language tags */
|
|
44
|
+
private readonly codeBlockPatterns: RegExp[] = [
|
|
45
|
+
/```(?:flowquery|cypher|fql)\s*\n([\s\S]*?)```/i,
|
|
46
|
+
/```(?:sql)\s*\n([\s\S]*?)```/i,
|
|
47
|
+
/```\s*\n([\s\S]*?)```/, // Generic code block
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
/** Keywords that indicate a FlowQuery statement */
|
|
51
|
+
private readonly flowQueryKeywords: RegExp[] = [
|
|
52
|
+
/\bWITH\b/i,
|
|
53
|
+
/\bLOAD\s+JSON\s+FROM\b/i,
|
|
54
|
+
/\bUNWIND\b/i,
|
|
55
|
+
/\bRETURN\b/i,
|
|
56
|
+
/\bWHERE\b/i,
|
|
57
|
+
/\bORDER\s+BY\b/i,
|
|
58
|
+
/\bLIMIT\b/i,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
/** Keywords that can start a FlowQuery statement */
|
|
62
|
+
private readonly startKeywords = /^(WITH|LOAD\s+JSON\s+FROM|UNWIND)\b/i;
|
|
63
|
+
|
|
64
|
+
/** Keywords that can continue a FlowQuery statement */
|
|
65
|
+
private readonly continueKeywords = /^(WITH|LOAD|UNWIND|WHERE|RETURN|ORDER|LIMIT|SKIP|HEADERS|POST|AS)\b/i;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Extract a FlowQuery statement from an LLM response.
|
|
69
|
+
*
|
|
70
|
+
* @param llmResponse - The full text response from the LLM
|
|
71
|
+
* @returns The extraction result
|
|
72
|
+
*/
|
|
73
|
+
public extract(llmResponse: string): FlowQueryExtraction {
|
|
74
|
+
if (!llmResponse || llmResponse.trim() === '') {
|
|
75
|
+
return { query: null, found: false };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check for explicit "NO_QUERY_NEEDED" marker
|
|
79
|
+
if (llmResponse.includes('[NO_QUERY_NEEDED]') ||
|
|
80
|
+
llmResponse.includes('NO_QUERY_NEEDED')) {
|
|
81
|
+
// Extract the direct response after the marker
|
|
82
|
+
const directMatch = llmResponse.match(/\[NO_QUERY_NEEDED\]\s*([\s\S]*)/i);
|
|
83
|
+
return {
|
|
84
|
+
query: null,
|
|
85
|
+
found: false,
|
|
86
|
+
noQueryNeeded: true,
|
|
87
|
+
directResponse: directMatch ? directMatch[1].trim() : llmResponse
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Try to match code blocks with specific language tags
|
|
92
|
+
for (const pattern of this.codeBlockPatterns) {
|
|
93
|
+
const match = llmResponse.match(pattern);
|
|
94
|
+
if (match && match[1]) {
|
|
95
|
+
const query = match[1].trim();
|
|
96
|
+
|
|
97
|
+
// Verify it looks like a FlowQuery statement
|
|
98
|
+
if (this.isLikelyFlowQuery(query)) {
|
|
99
|
+
// Extract explanation text before the code block
|
|
100
|
+
const beforeMatch = llmResponse.substring(0, llmResponse.indexOf(match[0])).trim();
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
query,
|
|
104
|
+
found: true,
|
|
105
|
+
explanation: beforeMatch || undefined
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Try to extract inline FlowQuery if no code block found
|
|
112
|
+
// Look for lines starting with FlowQuery keywords
|
|
113
|
+
const inlineQuery = this.extractInlineQuery(llmResponse);
|
|
114
|
+
if (inlineQuery) {
|
|
115
|
+
return {
|
|
116
|
+
query: inlineQuery,
|
|
117
|
+
found: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { query: null, found: false };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Extract multiple FlowQuery statements from an LLM response.
|
|
126
|
+
* Useful when the LLM provides alternative queries.
|
|
127
|
+
*
|
|
128
|
+
* @param llmResponse - The full text response from the LLM
|
|
129
|
+
* @returns Array of extracted queries
|
|
130
|
+
*/
|
|
131
|
+
public extractAll(llmResponse: string): string[] {
|
|
132
|
+
if (!llmResponse) return [];
|
|
133
|
+
|
|
134
|
+
const queries: string[] = [];
|
|
135
|
+
const codeBlockPattern = /```(?:flowquery|cypher|fql|sql)?\s*\n([\s\S]*?)```/gi;
|
|
136
|
+
|
|
137
|
+
let match;
|
|
138
|
+
while ((match = codeBlockPattern.exec(llmResponse)) !== null) {
|
|
139
|
+
if (match[1]) {
|
|
140
|
+
const query = match[1].trim();
|
|
141
|
+
if (this.isLikelyFlowQuery(query)) {
|
|
142
|
+
queries.push(query);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return queries;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if a string looks like a FlowQuery statement.
|
|
152
|
+
*/
|
|
153
|
+
private isLikelyFlowQuery(text: string): boolean {
|
|
154
|
+
// Must contain at least one FlowQuery keyword
|
|
155
|
+
return this.flowQueryKeywords.some(pattern => pattern.test(text));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Try to extract a FlowQuery statement that's not in a code block.
|
|
160
|
+
*/
|
|
161
|
+
private extractInlineQuery(text: string): string | null {
|
|
162
|
+
const lines = text.split('\n');
|
|
163
|
+
const queryLines: string[] = [];
|
|
164
|
+
let inQuery = false;
|
|
165
|
+
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
const trimmedLine = line.trim();
|
|
168
|
+
|
|
169
|
+
if (!inQuery && this.startKeywords.test(trimmedLine)) {
|
|
170
|
+
inQuery = true;
|
|
171
|
+
queryLines.push(trimmedLine);
|
|
172
|
+
} else if (inQuery) {
|
|
173
|
+
// Check if this line continues the query
|
|
174
|
+
if (this.continueKeywords.test(trimmedLine) ||
|
|
175
|
+
trimmedLine.startsWith('{') ||
|
|
176
|
+
trimmedLine.startsWith('}') ||
|
|
177
|
+
trimmedLine === '' ||
|
|
178
|
+
/^[A-Za-z_][A-Za-z0-9_]*\./.test(trimmedLine) ||
|
|
179
|
+
/^\s+/.test(line)) { // Indented line
|
|
180
|
+
queryLines.push(trimmedLine);
|
|
181
|
+
} else {
|
|
182
|
+
// End of query
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const query = queryLines.join('\n').trim();
|
|
189
|
+
return query && this.isLikelyFlowQuery(query) ? query : null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Convenience function for backward compatibility
|
|
194
|
+
export function extractFlowQuery(llmResponse: string): FlowQueryExtraction {
|
|
195
|
+
return new FlowQueryExtractor().extract(llmResponse);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Convenience function for backward compatibility
|
|
199
|
+
export function extractAllFlowQueries(llmResponse: string): string[] {
|
|
200
|
+
return new FlowQueryExtractor().extractAll(llmResponse);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export default FlowQueryExtractor;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utils module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { FlowQueryExecutor } from './FlowQueryExecutor';
|
|
6
|
+
export type { FlowQueryExecutionResult } from './FlowQueryExecutor';
|
|
7
|
+
|
|
8
|
+
export { FlowQueryExtractor, extractFlowQuery, extractAllFlowQueries } from './FlowQueryExtractor';
|
|
9
|
+
export type { FlowQueryExtraction } from './FlowQueryExtractor';
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"outDir": "./dist",
|
|
4
4
|
"rootDir": "./src",
|
|
5
5
|
"target": "ES2020",
|
|
6
|
-
"module": "
|
|
7
|
-
"moduleResolution": "
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
8
|
"esModuleInterop": true,
|
|
9
9
|
"forceConsistentCasingInFileNames": true,
|
|
10
10
|
"strict": true,
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"declaration": true,
|
|
13
13
|
"sourceMap": true,
|
|
14
14
|
"resolveJsonModule": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
15
17
|
"types": ["node"]
|
|
16
18
|
},
|
|
17
19
|
"include": ["src/**/*"],
|
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
2
3
|
|
|
3
4
|
module.exports = {
|
|
4
|
-
mode: '
|
|
5
|
-
entry: './src/index.
|
|
6
|
-
target: '
|
|
5
|
+
mode: 'development',
|
|
6
|
+
entry: './src/index.tsx',
|
|
7
|
+
target: 'web',
|
|
7
8
|
output: {
|
|
8
|
-
filename: '
|
|
9
|
+
filename: 'bundle.js',
|
|
9
10
|
path: path.resolve(__dirname, 'dist'),
|
|
10
|
-
|
|
11
|
+
clean: true
|
|
11
12
|
},
|
|
12
13
|
resolve: {
|
|
13
|
-
extensions: ['.ts', '.js']
|
|
14
|
+
extensions: ['.tsx', '.ts', '.js', '.jsx']
|
|
14
15
|
},
|
|
15
16
|
module: {
|
|
16
17
|
rules: [
|
|
17
18
|
{
|
|
18
|
-
test: /\.
|
|
19
|
+
test: /\.tsx?$/,
|
|
19
20
|
use: 'ts-loader',
|
|
20
21
|
exclude: /node_modules/
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
test: /\.css$/,
|
|
25
|
+
use: ['style-loader', 'css-loader']
|
|
21
26
|
}
|
|
22
27
|
]
|
|
23
28
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
plugins: [
|
|
30
|
+
new HtmlWebpackPlugin({
|
|
31
|
+
template: './public/index.html'
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
devServer: {
|
|
35
|
+
static: './dist',
|
|
36
|
+
port: 3000,
|
|
37
|
+
open: true,
|
|
38
|
+
hot: true
|
|
28
39
|
},
|
|
29
40
|
optimization: {
|
|
30
|
-
minimize:
|
|
41
|
+
minimize: false
|
|
31
42
|
}
|
|
32
43
|
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowquery",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
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",
|
|
7
|
+
"sideEffects": true,
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
10
|
"import": "./dist/index.node.js",
|
|
@@ -13,6 +14,11 @@
|
|
|
13
14
|
"./browser": {
|
|
14
15
|
"import": "./dist/flowquery.min.js",
|
|
15
16
|
"require": "./dist/flowquery.min.js"
|
|
17
|
+
},
|
|
18
|
+
"./extensibility": {
|
|
19
|
+
"import": "./dist/extensibility.js",
|
|
20
|
+
"require": "./dist/extensibility.js",
|
|
21
|
+
"types": "./dist/extensibility.d.ts"
|
|
16
22
|
}
|
|
17
23
|
},
|
|
18
24
|
"bin": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import AggregateFunction from "./aggregate_function";
|
|
2
2
|
import ASTNode from "../ast_node";
|
|
3
3
|
import ReducerElement from "./reducer_element";
|
|
4
|
+
import { FunctionDef } from "./function_metadata";
|
|
4
5
|
|
|
5
6
|
class AvgReducerElement extends ReducerElement {
|
|
6
7
|
private _count: number = 0;
|
|
@@ -21,6 +22,15 @@ class AvgReducerElement extends ReducerElement {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
@FunctionDef({
|
|
26
|
+
description: "Calculates the average of numeric values across grouped rows",
|
|
27
|
+
category: "aggregate",
|
|
28
|
+
parameters: [
|
|
29
|
+
{ name: "value", description: "Numeric value to average", type: "number" }
|
|
30
|
+
],
|
|
31
|
+
output: { description: "Average of all values", type: "number", example: 50 },
|
|
32
|
+
examples: ["WITH [10, 20, 30] AS nums UNWIND nums AS n RETURN avg(n)"]
|
|
33
|
+
})
|
|
24
34
|
class Avg extends AggregateFunction {
|
|
25
35
|
constructor() {
|
|
26
36
|
super("avg");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import AggregateFunction from "./aggregate_function";
|
|
2
2
|
import ReducerElement from "./reducer_element";
|
|
3
|
+
import { FunctionDef } from "./function_metadata";
|
|
3
4
|
|
|
4
5
|
class CollectReducerElement extends ReducerElement {
|
|
5
6
|
private _value: any[] = [];
|
|
@@ -24,6 +25,15 @@ class DistinctCollectReducerElement extends ReducerElement {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
@FunctionDef({
|
|
29
|
+
description: "Collects values into an array across grouped rows",
|
|
30
|
+
category: "aggregate",
|
|
31
|
+
parameters: [
|
|
32
|
+
{ name: "value", description: "Value to collect", type: "any" }
|
|
33
|
+
],
|
|
34
|
+
output: { description: "Array of collected values", type: "array", example: [1, 2, 3] },
|
|
35
|
+
examples: ["WITH [1, 2, 3] AS nums UNWIND nums AS n RETURN collect(n)"]
|
|
36
|
+
})
|
|
27
37
|
class Collect extends AggregateFunction {
|
|
28
38
|
private _distinct: boolean = false;
|
|
29
39
|
constructor() {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowQuery Extensibility API
|
|
3
|
+
*
|
|
4
|
+
* This module provides all the exports needed to create custom FlowQuery functions.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { Function, FunctionDef } from '../parsing/functions/extensibility';
|
|
11
|
+
*
|
|
12
|
+
* @FunctionDef({
|
|
13
|
+
* description: "Converts a string to uppercase",
|
|
14
|
+
* category: "string",
|
|
15
|
+
* parameters: [{ name: "text", description: "String to convert", type: "string" }],
|
|
16
|
+
* output: { description: "Uppercase string", type: "string" }
|
|
17
|
+
* })
|
|
18
|
+
* class UpperCase extends Function {
|
|
19
|
+
* constructor() {
|
|
20
|
+
* super("uppercase");
|
|
21
|
+
* this._expectedParameterCount = 1;
|
|
22
|
+
* }
|
|
23
|
+
* public value(): string {
|
|
24
|
+
* return String(this.getChildren()[0].value()).toUpperCase();
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// Base function classes for creating custom functions
|
|
31
|
+
export { default as Function } from "../function";
|
|
32
|
+
export { default as AggregateFunction } from "../aggregate_function";
|
|
33
|
+
export { default as PredicateFunction } from "../predicate_function";
|
|
34
|
+
export { default as ReducerElement } from "../reducer_element";
|
|
35
|
+
|
|
36
|
+
// Decorator and metadata types for function registration
|
|
37
|
+
export {
|
|
38
|
+
FunctionDef,
|
|
39
|
+
FunctionMetadata,
|
|
40
|
+
FunctionDefOptions,
|
|
41
|
+
ParameterSchema,
|
|
42
|
+
OutputSchema,
|
|
43
|
+
FunctionCategory
|
|
44
|
+
} from "../function_metadata";
|
|
45
|
+
|
|
46
|
+
// Factory for advanced usage
|
|
47
|
+
export { default as FunctionFactory } from "../function_factory";
|
|
48
|
+
export type { FunctionCreator, AsyncDataProvider } from "../function_factory";
|
|
49
|
+
|
|
50
|
+
// Registration option types
|
|
51
|
+
export type {
|
|
52
|
+
RegisterFunctionOptions,
|
|
53
|
+
RegisterAsyncProviderOptions
|
|
54
|
+
} from "../function_metadata";
|
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import Sum from "./sum";
|
|
2
|
-
import Collect from "./collect";
|
|
3
|
-
import Avg from "./avg";
|
|
4
|
-
import Range from "./range";
|
|
5
|
-
import Rand from "./rand";
|
|
6
|
-
import Round from "./round";
|
|
7
|
-
import Split from "./split";
|
|
8
|
-
import Join from "./join";
|
|
9
|
-
import ToJson from "./to_json";
|
|
10
|
-
import Replace from "./replace";
|
|
11
|
-
import Stringify from "./stringify";
|
|
12
|
-
import Size from "./size";
|
|
13
|
-
import Functions from "./functions";
|
|
14
1
|
import Function from "./function";
|
|
2
|
+
import PredicateFunction from "./predicate_function";
|
|
3
|
+
// Import built-in functions to ensure their @FunctionDef decorators run
|
|
4
|
+
import "./sum";
|
|
5
|
+
import "./collect";
|
|
6
|
+
import "./avg";
|
|
7
|
+
import "./range";
|
|
8
|
+
import "./rand";
|
|
9
|
+
import "./round";
|
|
10
|
+
import "./split";
|
|
11
|
+
import "./join";
|
|
12
|
+
import "./to_json";
|
|
13
|
+
import "./replace";
|
|
14
|
+
import "./stringify";
|
|
15
|
+
import "./size";
|
|
16
|
+
import "./functions";
|
|
17
|
+
import "./predicate_sum";
|
|
15
18
|
import {
|
|
16
19
|
FunctionMetadata,
|
|
17
20
|
RegisterFunctionOptions,
|
|
18
21
|
RegisterAsyncProviderOptions,
|
|
19
|
-
|
|
22
|
+
getRegisteredFunctionMetadata,
|
|
23
|
+
getFunctionMetadata,
|
|
24
|
+
getRegisteredFunctionFactory
|
|
20
25
|
} from "./function_metadata";
|
|
21
26
|
|
|
22
27
|
/**
|
|
@@ -182,8 +187,8 @@ class FunctionFactory {
|
|
|
182
187
|
if (FunctionFactory.metadata.has(lowerName)) {
|
|
183
188
|
return FunctionFactory.metadata.get(lowerName);
|
|
184
189
|
}
|
|
185
|
-
// Fall back to
|
|
186
|
-
return
|
|
190
|
+
// Fall back to decorator-registered metadata
|
|
191
|
+
return getFunctionMetadata(lowerName);
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
/**
|
|
@@ -202,9 +207,9 @@ class FunctionFactory {
|
|
|
202
207
|
const result: FunctionMetadata[] = [];
|
|
203
208
|
const includeBuiltins = options?.includeBuiltins !== false;
|
|
204
209
|
|
|
205
|
-
// Add
|
|
210
|
+
// Add decorator-registered functions (built-ins)
|
|
206
211
|
if (includeBuiltins) {
|
|
207
|
-
for (const meta of
|
|
212
|
+
for (const meta of getRegisteredFunctionMetadata()) {
|
|
208
213
|
if (options?.category && meta.category !== options.category) continue;
|
|
209
214
|
if (options?.asyncOnly) continue; // Built-ins are sync
|
|
210
215
|
result.push(meta);
|
|
@@ -228,7 +233,7 @@ class FunctionFactory {
|
|
|
228
233
|
* @returns Array of function names
|
|
229
234
|
*/
|
|
230
235
|
public static listFunctionNames(): string[] {
|
|
231
|
-
const builtinNames =
|
|
236
|
+
const builtinNames = getRegisteredFunctionMetadata().map(m => m.name);
|
|
232
237
|
const pluginNames = Array.from(FunctionFactory.plugins.keys());
|
|
233
238
|
const asyncNames = Array.from(FunctionFactory.asyncProviders.keys());
|
|
234
239
|
return [...new Set([...builtinNames, ...pluginNames, ...asyncNames])];
|
|
@@ -259,36 +264,34 @@ class FunctionFactory {
|
|
|
259
264
|
return FunctionFactory.plugins.get(lowerName)!();
|
|
260
265
|
}
|
|
261
266
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return new Collect();
|
|
267
|
-
case "avg":
|
|
268
|
-
return new Avg();
|
|
269
|
-
case "range":
|
|
270
|
-
return new Range();
|
|
271
|
-
case "rand":
|
|
272
|
-
return new Rand();
|
|
273
|
-
case "round":
|
|
274
|
-
return new Round();
|
|
275
|
-
case "split":
|
|
276
|
-
return new Split();
|
|
277
|
-
case "join":
|
|
278
|
-
return new Join();
|
|
279
|
-
case "tojson":
|
|
280
|
-
return new ToJson();
|
|
281
|
-
case "replace":
|
|
282
|
-
return new Replace();
|
|
283
|
-
case "stringify":
|
|
284
|
-
return new Stringify();
|
|
285
|
-
case "size":
|
|
286
|
-
return new Size();
|
|
287
|
-
case "functions":
|
|
288
|
-
return new Functions();
|
|
289
|
-
default:
|
|
290
|
-
return new Function(name);
|
|
267
|
+
// Check decorator-registered functions (built-ins use @FunctionDef)
|
|
268
|
+
const decoratorFactory = getRegisteredFunctionFactory(lowerName);
|
|
269
|
+
if (decoratorFactory) {
|
|
270
|
+
return decoratorFactory();
|
|
291
271
|
}
|
|
272
|
+
|
|
273
|
+
// Unknown function - return generic Function instance
|
|
274
|
+
return new Function(name);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Creates a predicate function instance by name.
|
|
279
|
+
* Predicate functions are used in WHERE clauses with quantifiers (e.g., ANY, ALL).
|
|
280
|
+
*
|
|
281
|
+
* @param name - The function name (case-insensitive)
|
|
282
|
+
* @returns A PredicateFunction instance of the appropriate type
|
|
283
|
+
*/
|
|
284
|
+
public static createPredicate(name: string): PredicateFunction {
|
|
285
|
+
const lowerName = name.toLowerCase();
|
|
286
|
+
|
|
287
|
+
// Check decorator-registered predicate functions
|
|
288
|
+
const decoratorFactory = getRegisteredFunctionFactory(lowerName, 'predicate');
|
|
289
|
+
if (decoratorFactory) {
|
|
290
|
+
return decoratorFactory();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Unknown predicate function - return generic PredicateFunction instance
|
|
294
|
+
return new PredicateFunction(name);
|
|
292
295
|
}
|
|
293
296
|
}
|
|
294
297
|
|