flowquery 1.0.16 → 1.0.17
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/python-publish.yml +97 -0
- package/dist/compute/runner.d.ts +3 -2
- package/dist/compute/runner.d.ts.map +1 -1
- package/dist/compute/runner.js +7 -7
- package/dist/compute/runner.js.map +1 -1
- package/dist/flowquery.min.js +1 -1
- package/dist/graph/data.d.ts +31 -0
- package/dist/graph/data.d.ts.map +1 -0
- package/dist/graph/data.js +110 -0
- package/dist/graph/data.js.map +1 -0
- package/dist/graph/database.d.ts +20 -0
- package/dist/graph/database.d.ts.map +1 -0
- package/dist/graph/database.js +77 -0
- package/dist/graph/database.js.map +1 -0
- package/dist/graph/hops.d.ts +11 -0
- package/dist/graph/hops.d.ts.map +1 -0
- package/dist/graph/hops.js +25 -0
- package/dist/graph/hops.js.map +1 -0
- package/dist/graph/node.d.ts +35 -0
- package/dist/graph/node.d.ts.map +1 -0
- package/dist/graph/node.js +113 -0
- package/dist/graph/node.js.map +1 -0
- package/dist/graph/node_data.d.ts +11 -0
- package/dist/graph/node_data.d.ts.map +1 -0
- package/dist/graph/node_data.js +20 -0
- package/dist/graph/node_data.js.map +1 -0
- package/dist/graph/node_reference.d.ts +10 -0
- package/dist/graph/node_reference.d.ts.map +1 -0
- package/dist/graph/node_reference.js +52 -0
- package/dist/graph/node_reference.js.map +1 -0
- package/dist/graph/pattern.d.ts +18 -0
- package/dist/graph/pattern.d.ts.map +1 -0
- package/dist/graph/pattern.js +114 -0
- package/dist/graph/pattern.js.map +1 -0
- package/dist/graph/pattern_expression.d.ts +14 -0
- package/dist/graph/pattern_expression.d.ts.map +1 -0
- package/dist/graph/pattern_expression.js +58 -0
- package/dist/graph/pattern_expression.js.map +1 -0
- package/dist/graph/patterns.d.ts +11 -0
- package/dist/graph/patterns.d.ts.map +1 -0
- package/dist/graph/patterns.js +49 -0
- package/dist/graph/patterns.js.map +1 -0
- package/dist/graph/physical_node.d.ts +10 -0
- package/dist/graph/physical_node.d.ts.map +1 -0
- package/dist/graph/physical_node.js +40 -0
- package/dist/graph/physical_node.js.map +1 -0
- package/dist/graph/physical_relationship.d.ts +10 -0
- package/dist/graph/physical_relationship.d.ts.map +1 -0
- package/dist/graph/physical_relationship.js +40 -0
- package/dist/graph/physical_relationship.js.map +1 -0
- package/dist/graph/relationship.d.ts +40 -0
- package/dist/graph/relationship.d.ts.map +1 -0
- package/dist/graph/relationship.js +124 -0
- package/dist/graph/relationship.js.map +1 -0
- package/dist/graph/relationship_data.d.ts +12 -0
- package/dist/graph/relationship_data.d.ts.map +1 -0
- package/dist/graph/relationship_data.js +40 -0
- package/dist/graph/relationship_data.js.map +1 -0
- package/dist/graph/relationship_match_collector.d.ts +19 -0
- package/dist/graph/relationship_match_collector.d.ts.map +1 -0
- package/dist/graph/relationship_match_collector.js +55 -0
- package/dist/graph/relationship_match_collector.js.map +1 -0
- package/dist/graph/relationship_reference.d.ts +8 -0
- package/dist/graph/relationship_reference.d.ts.map +1 -0
- package/dist/graph/relationship_reference.js +37 -0
- package/dist/graph/relationship_reference.js.map +1 -0
- package/dist/parsing/base_parser.d.ts +1 -0
- package/dist/parsing/base_parser.d.ts.map +1 -1
- package/dist/parsing/base_parser.js +4 -1
- package/dist/parsing/base_parser.js.map +1 -1
- package/dist/parsing/context.d.ts +2 -2
- package/dist/parsing/context.js +5 -5
- package/dist/parsing/expressions/boolean.d.ts +8 -0
- package/dist/parsing/expressions/boolean.d.ts.map +1 -0
- package/dist/parsing/expressions/boolean.js +26 -0
- package/dist/parsing/expressions/boolean.js.map +1 -0
- package/dist/parsing/expressions/expression.d.ts +4 -1
- package/dist/parsing/expressions/expression.d.ts.map +1 -1
- package/dist/parsing/expressions/expression.js +15 -8
- package/dist/parsing/expressions/expression.js.map +1 -1
- package/dist/parsing/expressions/operator.d.ts +1 -1
- package/dist/parsing/expressions/operator.d.ts.map +1 -1
- package/dist/parsing/expressions/operator.js.map +1 -1
- package/dist/parsing/functions/function_factory.d.ts +13 -13
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +20 -18
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/operations/create_node.d.ts +14 -0
- package/dist/parsing/operations/create_node.d.ts.map +1 -0
- package/dist/parsing/operations/create_node.js +51 -0
- package/dist/parsing/operations/create_node.js.map +1 -0
- package/dist/parsing/operations/create_relationship.d.ts +14 -0
- package/dist/parsing/operations/create_relationship.d.ts.map +1 -0
- package/dist/parsing/operations/create_relationship.js +51 -0
- package/dist/parsing/operations/create_relationship.js.map +1 -0
- package/dist/parsing/operations/match.d.ts +15 -0
- package/dist/parsing/operations/match.d.ts.map +1 -0
- package/dist/parsing/operations/match.js +45 -0
- package/dist/parsing/operations/match.js.map +1 -0
- 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 -0
- package/dist/parsing/operations/operation.js.map +1 -1
- package/dist/parsing/operations/return.d.ts +1 -0
- package/dist/parsing/operations/return.d.ts.map +1 -1
- package/dist/parsing/operations/return.js +7 -1
- package/dist/parsing/operations/return.js.map +1 -1
- package/dist/parsing/operations/where.d.ts +1 -1
- package/dist/parsing/operations/where.d.ts.map +1 -1
- package/dist/parsing/operations/where.js +4 -0
- package/dist/parsing/operations/where.js.map +1 -1
- package/dist/parsing/parser.d.ts +10 -0
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +344 -5
- package/dist/parsing/parser.js.map +1 -1
- package/dist/parsing/token_to_node.d.ts.map +1 -1
- package/dist/parsing/token_to_node.js +7 -0
- package/dist/parsing/token_to_node.js.map +1 -1
- package/dist/tokenization/keyword.d.ts +1 -0
- package/dist/tokenization/keyword.d.ts.map +1 -1
- package/dist/tokenization/keyword.js +1 -0
- package/dist/tokenization/keyword.js.map +1 -1
- package/dist/tokenization/token.d.ts +4 -0
- package/dist/tokenization/token.d.ts.map +1 -1
- package/dist/tokenization/token.js +14 -1
- package/dist/tokenization/token.js.map +1 -1
- package/dist/tokenization/token_type.d.ts +1 -0
- package/dist/tokenization/token_type.d.ts.map +1 -1
- package/dist/tokenization/token_type.js +1 -0
- package/dist/tokenization/token_type.js.map +1 -1
- package/dist/tokenization/tokenizer.d.ts +2 -1
- package/dist/tokenization/tokenizer.d.ts.map +1 -1
- package/dist/tokenization/tokenizer.js +25 -12
- package/dist/tokenization/tokenizer.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/README.md +166 -0
- package/flowquery-py/pyproject.toml +75 -0
- package/flowquery-py/setup_env.ps1 +92 -0
- package/flowquery-py/setup_env.sh +87 -0
- package/flowquery-py/src/__init__.py +34 -0
- package/flowquery-py/src/__main__.py +10 -0
- package/flowquery-py/src/compute/__init__.py +5 -0
- package/flowquery-py/src/compute/runner.py +60 -0
- package/flowquery-py/src/extensibility.py +52 -0
- package/flowquery-py/src/graph/__init__.py +31 -0
- package/flowquery-py/src/graph/data.py +118 -0
- package/flowquery-py/src/graph/database.py +82 -0
- package/flowquery-py/src/graph/hops.py +43 -0
- package/flowquery-py/src/graph/node.py +112 -0
- package/flowquery-py/src/graph/node_data.py +26 -0
- package/flowquery-py/src/graph/node_reference.py +49 -0
- package/flowquery-py/src/graph/pattern.py +125 -0
- package/flowquery-py/src/graph/pattern_expression.py +62 -0
- package/flowquery-py/src/graph/patterns.py +42 -0
- package/flowquery-py/src/graph/physical_node.py +40 -0
- package/flowquery-py/src/graph/physical_relationship.py +36 -0
- package/flowquery-py/src/graph/relationship.py +135 -0
- package/flowquery-py/src/graph/relationship_data.py +33 -0
- package/flowquery-py/src/graph/relationship_match_collector.py +77 -0
- package/flowquery-py/src/graph/relationship_reference.py +21 -0
- package/flowquery-py/src/io/__init__.py +5 -0
- package/flowquery-py/src/io/command_line.py +67 -0
- package/flowquery-py/src/parsing/__init__.py +17 -0
- package/flowquery-py/src/parsing/alias.py +20 -0
- package/flowquery-py/src/parsing/alias_option.py +11 -0
- package/flowquery-py/src/parsing/ast_node.py +146 -0
- package/flowquery-py/src/parsing/base_parser.py +84 -0
- package/flowquery-py/src/parsing/components/__init__.py +19 -0
- package/flowquery-py/src/parsing/components/csv.py +8 -0
- package/flowquery-py/src/parsing/components/from_.py +10 -0
- package/flowquery-py/src/parsing/components/headers.py +12 -0
- package/flowquery-py/src/parsing/components/json.py +8 -0
- package/flowquery-py/src/parsing/components/null.py +10 -0
- package/flowquery-py/src/parsing/components/post.py +8 -0
- package/flowquery-py/src/parsing/components/text.py +8 -0
- package/flowquery-py/src/parsing/context.py +50 -0
- package/flowquery-py/src/parsing/data_structures/__init__.py +15 -0
- package/flowquery-py/src/parsing/data_structures/associative_array.py +41 -0
- package/flowquery-py/src/parsing/data_structures/json_array.py +30 -0
- package/flowquery-py/src/parsing/data_structures/key_value_pair.py +38 -0
- package/flowquery-py/src/parsing/data_structures/lookup.py +49 -0
- package/flowquery-py/src/parsing/data_structures/range_lookup.py +42 -0
- package/flowquery-py/src/parsing/expressions/__init__.py +57 -0
- package/flowquery-py/src/parsing/expressions/boolean.py +20 -0
- package/flowquery-py/src/parsing/expressions/expression.py +138 -0
- package/flowquery-py/src/parsing/expressions/expression_map.py +26 -0
- package/flowquery-py/src/parsing/expressions/f_string.py +27 -0
- package/flowquery-py/src/parsing/expressions/identifier.py +20 -0
- package/flowquery-py/src/parsing/expressions/number.py +32 -0
- package/flowquery-py/src/parsing/expressions/operator.py +169 -0
- package/flowquery-py/src/parsing/expressions/reference.py +47 -0
- package/flowquery-py/src/parsing/expressions/string.py +27 -0
- package/flowquery-py/src/parsing/functions/__init__.py +75 -0
- package/flowquery-py/src/parsing/functions/aggregate_function.py +60 -0
- package/flowquery-py/src/parsing/functions/async_function.py +62 -0
- package/flowquery-py/src/parsing/functions/avg.py +55 -0
- package/flowquery-py/src/parsing/functions/collect.py +75 -0
- package/flowquery-py/src/parsing/functions/function.py +68 -0
- package/flowquery-py/src/parsing/functions/function_factory.py +173 -0
- package/flowquery-py/src/parsing/functions/function_metadata.py +149 -0
- package/flowquery-py/src/parsing/functions/functions.py +59 -0
- package/flowquery-py/src/parsing/functions/join.py +47 -0
- package/flowquery-py/src/parsing/functions/keys.py +34 -0
- package/flowquery-py/src/parsing/functions/predicate_function.py +46 -0
- package/flowquery-py/src/parsing/functions/predicate_sum.py +47 -0
- package/flowquery-py/src/parsing/functions/rand.py +28 -0
- package/flowquery-py/src/parsing/functions/range_.py +34 -0
- package/flowquery-py/src/parsing/functions/reducer_element.py +15 -0
- package/flowquery-py/src/parsing/functions/replace.py +37 -0
- package/flowquery-py/src/parsing/functions/round_.py +32 -0
- package/flowquery-py/src/parsing/functions/size.py +32 -0
- package/flowquery-py/src/parsing/functions/split.py +47 -0
- package/flowquery-py/src/parsing/functions/stringify.py +47 -0
- package/flowquery-py/src/parsing/functions/sum.py +51 -0
- package/flowquery-py/src/parsing/functions/to_json.py +33 -0
- package/flowquery-py/src/parsing/functions/type_.py +47 -0
- package/flowquery-py/src/parsing/functions/value_holder.py +24 -0
- package/flowquery-py/src/parsing/logic/__init__.py +15 -0
- package/flowquery-py/src/parsing/logic/case.py +29 -0
- package/flowquery-py/src/parsing/logic/else_.py +12 -0
- package/flowquery-py/src/parsing/logic/end.py +8 -0
- package/flowquery-py/src/parsing/logic/then.py +12 -0
- package/flowquery-py/src/parsing/logic/when.py +10 -0
- package/flowquery-py/src/parsing/operations/__init__.py +35 -0
- package/flowquery-py/src/parsing/operations/aggregated_return.py +24 -0
- package/flowquery-py/src/parsing/operations/aggregated_with.py +22 -0
- package/flowquery-py/src/parsing/operations/call.py +74 -0
- package/flowquery-py/src/parsing/operations/create_node.py +34 -0
- package/flowquery-py/src/parsing/operations/create_relationship.py +34 -0
- package/flowquery-py/src/parsing/operations/group_by.py +130 -0
- package/flowquery-py/src/parsing/operations/limit.py +22 -0
- package/flowquery-py/src/parsing/operations/load.py +140 -0
- package/flowquery-py/src/parsing/operations/match.py +29 -0
- package/flowquery-py/src/parsing/operations/operation.py +69 -0
- package/flowquery-py/src/parsing/operations/projection.py +21 -0
- package/flowquery-py/src/parsing/operations/return_op.py +50 -0
- package/flowquery-py/src/parsing/operations/unwind.py +37 -0
- package/flowquery-py/src/parsing/operations/where.py +41 -0
- package/flowquery-py/src/parsing/operations/with_op.py +18 -0
- package/flowquery-py/src/parsing/parser.py +1011 -0
- package/flowquery-py/src/parsing/token_to_node.py +109 -0
- package/flowquery-py/src/tokenization/__init__.py +23 -0
- package/flowquery-py/src/tokenization/keyword.py +48 -0
- package/flowquery-py/src/tokenization/operator.py +29 -0
- package/flowquery-py/src/tokenization/string_walker.py +158 -0
- package/flowquery-py/src/tokenization/symbol.py +19 -0
- package/flowquery-py/src/tokenization/token.py +659 -0
- package/flowquery-py/src/tokenization/token_mapper.py +52 -0
- package/flowquery-py/src/tokenization/token_type.py +21 -0
- package/flowquery-py/src/tokenization/tokenizer.py +214 -0
- package/flowquery-py/src/tokenization/trie.py +124 -0
- package/flowquery-py/src/utils/__init__.py +6 -0
- package/flowquery-py/src/utils/object_utils.py +20 -0
- package/flowquery-py/src/utils/string_utils.py +113 -0
- package/flowquery-py/tests/__init__.py +1 -0
- package/flowquery-py/tests/compute/__init__.py +1 -0
- package/flowquery-py/tests/compute/test_runner.py +1335 -0
- package/flowquery-py/tests/graph/__init__.py +1 -0
- package/flowquery-py/tests/graph/test_create.py +56 -0
- package/flowquery-py/tests/graph/test_data.py +73 -0
- package/flowquery-py/tests/graph/test_match.py +40 -0
- package/flowquery-py/tests/parsing/__init__.py +1 -0
- package/flowquery-py/tests/parsing/test_context.py +34 -0
- package/flowquery-py/tests/parsing/test_expression.py +49 -0
- package/flowquery-py/tests/parsing/test_parser.py +674 -0
- package/flowquery-py/tests/test_extensibility.py +611 -0
- package/flowquery-py/tests/tokenization/__init__.py +1 -0
- package/flowquery-py/tests/tokenization/test_token_mapper.py +60 -0
- package/flowquery-py/tests/tokenization/test_tokenizer.py +164 -0
- package/flowquery-py/tests/tokenization/test_trie.py +30 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/package.json +1 -1
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +76 -8
- package/misc/apps/RAG/src/components/index.ts +19 -10
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +70 -140
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
- package/package.json +1 -1
- package/src/compute/runner.ts +24 -19
- package/src/graph/data.ts +112 -0
- package/src/graph/database.ts +63 -0
- package/src/graph/hops.ts +22 -0
- package/src/graph/node.ts +99 -0
- package/src/graph/node_data.ts +18 -0
- package/src/graph/node_reference.ts +33 -0
- package/src/graph/pattern.ts +101 -0
- package/src/graph/pattern_expression.ts +37 -0
- package/src/graph/patterns.ts +36 -0
- package/src/graph/physical_node.ts +23 -0
- package/src/graph/physical_relationship.ts +23 -0
- package/src/graph/relationship.ts +116 -0
- package/src/graph/relationship_data.ts +27 -0
- package/src/graph/relationship_match_collector.ts +58 -0
- package/src/graph/relationship_reference.ts +24 -0
- package/src/parsing/base_parser.ts +20 -14
- package/src/parsing/context.ts +14 -14
- package/src/parsing/expressions/boolean.ts +21 -0
- package/src/parsing/expressions/expression.ts +34 -26
- package/src/parsing/expressions/operator.ts +19 -1
- package/src/parsing/functions/function_factory.ts +45 -45
- package/src/parsing/operations/create_node.ts +39 -0
- package/src/parsing/operations/create_relationship.ts +38 -0
- package/src/parsing/operations/match.ts +31 -0
- package/src/parsing/operations/operation.ts +3 -0
- package/src/parsing/operations/return.ts +11 -7
- package/src/parsing/operations/where.ts +10 -6
- package/src/parsing/parser.ts +346 -8
- package/src/parsing/token_to_node.ts +6 -0
- package/src/tokenization/keyword.ts +41 -40
- package/src/tokenization/token.ts +21 -1
- package/src/tokenization/token_type.ts +2 -1
- package/src/tokenization/tokenizer.ts +52 -31
- package/tests/compute/runner.test.ts +654 -0
- package/tests/extensibility.test.ts +97 -93
- package/tests/graph/create.test.ts +36 -0
- package/tests/graph/data.test.ts +58 -0
- package/tests/graph/match.test.ts +29 -0
- package/tests/parsing/parser.test.ts +273 -2
- package/tests/tokenization/tokenizer.test.ts +90 -0
|
@@ -235,10 +235,16 @@ export class AdaptiveCardRenderer extends React.Component<AdaptiveCardRendererPr
|
|
|
235
235
|
this.containerRef.current.innerHTML = '';
|
|
236
236
|
|
|
237
237
|
try {
|
|
238
|
+
// Normalize the card to standard Adaptive Card format
|
|
239
|
+
let cardPayload = normalizeAdaptiveCard(card);
|
|
240
|
+
|
|
241
|
+
if (!cardPayload) {
|
|
242
|
+
throw new Error('Invalid Adaptive Card format');
|
|
243
|
+
}
|
|
244
|
+
|
|
238
245
|
// Apply data binding if data is provided
|
|
239
|
-
let cardPayload = card;
|
|
240
246
|
if (data) {
|
|
241
|
-
const template = new ACData.Template(
|
|
247
|
+
const template = new ACData.Template(cardPayload);
|
|
242
248
|
cardPayload = template.expand({
|
|
243
249
|
$root: data
|
|
244
250
|
});
|
|
@@ -299,14 +305,76 @@ export class AdaptiveCardRenderer extends React.Component<AdaptiveCardRendererPr
|
|
|
299
305
|
}
|
|
300
306
|
|
|
301
307
|
/**
|
|
302
|
-
* Helper function to check if an object looks like an Adaptive Card
|
|
308
|
+
* Helper function to check if an object looks like an Adaptive Card.
|
|
309
|
+
* Supports both standard format (type: 'AdaptiveCard') and alternative format (cardType: 'AdaptiveCard').
|
|
303
310
|
*/
|
|
304
311
|
export function isAdaptiveCard(obj: unknown): obj is Record<string, unknown> {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const card = obj as Record<string, unknown>;
|
|
317
|
+
|
|
318
|
+
// Standard Adaptive Card format
|
|
319
|
+
if (card.type === 'AdaptiveCard') {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Alternative format with cardType/cardBody
|
|
324
|
+
if (card.cardType === 'AdaptiveCard') {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Check if it's an array containing Adaptive Cards
|
|
329
|
+
if (Array.isArray(obj) && obj.length > 0) {
|
|
330
|
+
return obj.some(item => isAdaptiveCard(item));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Normalizes a card payload to the standard Adaptive Card format.
|
|
338
|
+
* Handles:
|
|
339
|
+
* - Arrays of cards (returns the first card)
|
|
340
|
+
* - Alternative format with cardType/cardBody properties
|
|
341
|
+
* - Standard format (passed through unchanged)
|
|
342
|
+
*/
|
|
343
|
+
export function normalizeAdaptiveCard(obj: unknown): Record<string, unknown> | null {
|
|
344
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Handle arrays - extract the first valid card
|
|
349
|
+
if (Array.isArray(obj)) {
|
|
350
|
+
for (const item of obj) {
|
|
351
|
+
const normalized = normalizeAdaptiveCard(item);
|
|
352
|
+
if (normalized) {
|
|
353
|
+
return normalized;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const card = obj as Record<string, unknown>;
|
|
360
|
+
|
|
361
|
+
// Standard format - return as-is
|
|
362
|
+
if (card.type === 'AdaptiveCard') {
|
|
363
|
+
return card;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Alternative format - convert to standard format
|
|
367
|
+
if (card.cardType === 'AdaptiveCard') {
|
|
368
|
+
return {
|
|
369
|
+
type: 'AdaptiveCard',
|
|
370
|
+
$schema: 'http://adaptivecards.io/schemas/adaptive-card.json',
|
|
371
|
+
version: (card.version as string) || '1.5',
|
|
372
|
+
body: card.cardBody || card.body || [],
|
|
373
|
+
actions: card.actions || []
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return null;
|
|
310
378
|
}
|
|
311
379
|
|
|
312
380
|
export default AdaptiveCardRenderer;
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
// Chat components exports
|
|
2
|
-
export { ChatContainer } from
|
|
3
|
-
export { ChatMessage } from
|
|
4
|
-
export { ChatInput } from
|
|
5
|
-
export { ApiKeySettings } from
|
|
2
|
+
export { ChatContainer } from "./ChatContainer";
|
|
3
|
+
export { ChatMessage } from "./ChatMessage";
|
|
4
|
+
export { ChatInput } from "./ChatInput";
|
|
5
|
+
export { ApiKeySettings } from "./ApiKeySettings";
|
|
6
6
|
|
|
7
7
|
// FlowQuery Runner
|
|
8
|
-
export { FlowQueryRunner } from
|
|
8
|
+
export { FlowQueryRunner } from "./FlowQueryRunner";
|
|
9
9
|
|
|
10
10
|
// Adaptive Card Renderer
|
|
11
|
-
export {
|
|
11
|
+
export {
|
|
12
|
+
AdaptiveCardRenderer,
|
|
13
|
+
isAdaptiveCard,
|
|
14
|
+
normalizeAdaptiveCard,
|
|
15
|
+
} from "./AdaptiveCardRenderer";
|
|
12
16
|
|
|
13
17
|
// FlowQuery Agent
|
|
14
|
-
export { processQuery, processQueryStream } from
|
|
15
|
-
export type {
|
|
18
|
+
export { processQuery, processQueryStream } from "./FlowQueryAgent";
|
|
19
|
+
export type {
|
|
20
|
+
AgentStep,
|
|
21
|
+
AgentResult,
|
|
22
|
+
FlowQueryAgentOptions,
|
|
23
|
+
AgentStreamCallback,
|
|
24
|
+
} from "./FlowQueryAgent";
|
|
16
25
|
|
|
17
26
|
// Types
|
|
18
|
-
export type { Message } from
|
|
19
|
-
export type { AdaptiveCardRendererProps } from
|
|
27
|
+
export type { Message } from "./ChatMessage";
|
|
28
|
+
export type { AdaptiveCardRendererProps } from "./AdaptiveCardRenderer";
|
|
@@ -1,171 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example plugin: Generate mock data for testing.
|
|
3
|
-
*
|
|
4
|
-
* Usage in FlowQuery:
|
|
5
|
-
* CALL mockUsers(10) YIELD name, email
|
|
6
|
-
*/
|
|
7
1
|
import { AsyncFunction, FunctionDef } from "flowquery/extensibility";
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
const usersData = [
|
|
4
|
+
{ id: 1, name: "Alice Johnson", email: "alice@example.com", age: 28 },
|
|
5
|
+
{ id: 2, name: "Bob Smith", email: "bob@example.com", age: 34 },
|
|
6
|
+
{ id: 3, name: "Charlie Brown", email: "charlie@example.com", age: 22 },
|
|
7
|
+
{ id: 4, name: "Diana Ross", email: "diana@example.com", age: 45 },
|
|
8
|
+
{ id: 5, name: "Eve Wilson", email: "eve@example.com", age: 31 },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const productsData = [
|
|
12
|
+
{ id: 101, name: "Laptop", price: 999.99, category: "Electronics", stock: 50 },
|
|
13
|
+
{ id: 102, name: "Headphones", price: 149.99, category: "Electronics", stock: 200 },
|
|
14
|
+
{ id: 103, name: "Coffee Mug", price: 12.99, category: "Kitchen", stock: 500 },
|
|
15
|
+
{ id: 104, name: "Notebook", price: 8.99, category: "Office", stock: 300 },
|
|
16
|
+
{ id: 105, name: "Backpack", price: 59.99, category: "Accessories", stock: 75 },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const ordersData = [
|
|
20
|
+
{ id: 1001, userId: 1, productId: 101, quantity: 1, total: 999.99, date: "2025-12-01" },
|
|
21
|
+
{ id: 1002, userId: 2, productId: 102, quantity: 2, total: 299.98, date: "2025-12-05" },
|
|
22
|
+
{ id: 1003, userId: 1, productId: 103, quantity: 4, total: 51.96, date: "2025-12-10" },
|
|
23
|
+
{ id: 1004, userId: 3, productId: 104, quantity: 10, total: 89.9, date: "2025-12-15" },
|
|
24
|
+
{ id: 1005, userId: 4, productId: 105, quantity: 1, total: 59.99, date: "2025-12-20" },
|
|
25
|
+
{ id: 1006, userId: 5, productId: 101, quantity: 1, total: 999.99, date: "2025-12-25" },
|
|
26
|
+
];
|
|
27
|
+
|
|
12
28
|
@FunctionDef({
|
|
13
|
-
description: "
|
|
29
|
+
description: "Returns mock user data",
|
|
14
30
|
category: "async",
|
|
15
|
-
parameters: [
|
|
16
|
-
{
|
|
17
|
-
name: "count",
|
|
18
|
-
description: "Number of mock users to generate",
|
|
19
|
-
type: "number",
|
|
20
|
-
required: false,
|
|
21
|
-
default: 5,
|
|
22
|
-
},
|
|
23
|
-
],
|
|
31
|
+
parameters: [],
|
|
24
32
|
output: {
|
|
25
|
-
description: "
|
|
33
|
+
description: "User object",
|
|
26
34
|
type: "object",
|
|
27
35
|
properties: {
|
|
28
36
|
id: { description: "User ID", type: "number" },
|
|
29
|
-
name: { description: "
|
|
30
|
-
email: { description: "
|
|
31
|
-
age: { description: "
|
|
32
|
-
active: { description: "Whether user is active", type: "boolean" },
|
|
37
|
+
name: { description: "User name", type: "string" },
|
|
38
|
+
email: { description: "User email", type: "string" },
|
|
39
|
+
age: { description: "User age", type: "number" },
|
|
33
40
|
},
|
|
34
41
|
},
|
|
35
|
-
examples: [
|
|
36
|
-
"CALL mockUsers(10) YIELD name, email",
|
|
37
|
-
"CALL mockUsers(20) YIELD name, email, active WHERE active = true",
|
|
38
|
-
],
|
|
42
|
+
examples: ["CALL users() YIELD id, name, email, age"],
|
|
39
43
|
})
|
|
40
|
-
export class
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
constructor(
|
|
46
|
-
firstNames: string[] = [
|
|
47
|
-
"Alice",
|
|
48
|
-
"Bob",
|
|
49
|
-
"Charlie",
|
|
50
|
-
"Diana",
|
|
51
|
-
"Eve",
|
|
52
|
-
"Frank",
|
|
53
|
-
"Grace",
|
|
54
|
-
"Henry",
|
|
55
|
-
"Ivy",
|
|
56
|
-
"Jack",
|
|
57
|
-
],
|
|
58
|
-
lastNames: string[] = [
|
|
59
|
-
"Smith",
|
|
60
|
-
"Johnson",
|
|
61
|
-
"Williams",
|
|
62
|
-
"Brown",
|
|
63
|
-
"Jones",
|
|
64
|
-
"Garcia",
|
|
65
|
-
"Miller",
|
|
66
|
-
"Davis",
|
|
67
|
-
"Rodriguez",
|
|
68
|
-
"Martinez",
|
|
69
|
-
],
|
|
70
|
-
domains: string[] = ["example.com", "test.org", "demo.net"]
|
|
71
|
-
) {
|
|
72
|
-
super();
|
|
73
|
-
this.firstNames = firstNames;
|
|
74
|
-
this.lastNames = lastNames;
|
|
75
|
-
this.domains = domains;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Generates mock user data.
|
|
80
|
-
*
|
|
81
|
-
* @param count - Number of mock users to generate
|
|
82
|
-
*/
|
|
83
|
-
async *generate(count: number = 5): AsyncGenerator<any, void, unknown> {
|
|
84
|
-
for (let i = 0; i < count; i++) {
|
|
85
|
-
const firstName = this.firstNames[Math.floor(Math.random() * this.firstNames.length)];
|
|
86
|
-
const lastName = this.lastNames[Math.floor(Math.random() * this.lastNames.length)];
|
|
87
|
-
const domain = this.domains[Math.floor(Math.random() * this.domains.length)];
|
|
88
|
-
|
|
89
|
-
yield {
|
|
90
|
-
id: i + 1,
|
|
91
|
-
name: `${firstName} ${lastName}`,
|
|
92
|
-
email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@${domain}`,
|
|
93
|
-
age: Math.floor(Math.random() * 50) + 18,
|
|
94
|
-
active: Math.random() > 0.3,
|
|
95
|
-
};
|
|
44
|
+
export class Users extends AsyncFunction {
|
|
45
|
+
async *generate(): AsyncGenerator<any, void, unknown> {
|
|
46
|
+
for (const user of usersData) {
|
|
47
|
+
yield user;
|
|
96
48
|
}
|
|
97
49
|
}
|
|
98
50
|
}
|
|
99
51
|
|
|
100
|
-
/**
|
|
101
|
-
* MockProducts class - generates mock product data for testing.
|
|
102
|
-
*/
|
|
103
52
|
@FunctionDef({
|
|
104
|
-
description: "
|
|
53
|
+
description: "Returns mock product data",
|
|
105
54
|
category: "async",
|
|
106
|
-
parameters: [
|
|
107
|
-
{
|
|
108
|
-
name: "count",
|
|
109
|
-
description: "Number of mock products to generate",
|
|
110
|
-
type: "number",
|
|
111
|
-
required: false,
|
|
112
|
-
default: 5,
|
|
113
|
-
},
|
|
114
|
-
],
|
|
55
|
+
parameters: [],
|
|
115
56
|
output: {
|
|
116
|
-
description: "
|
|
57
|
+
description: "Product object",
|
|
117
58
|
type: "object",
|
|
118
59
|
properties: {
|
|
119
60
|
id: { description: "Product ID", type: "number" },
|
|
120
61
|
name: { description: "Product name", type: "string" },
|
|
62
|
+
price: { description: "Product price", type: "number" },
|
|
121
63
|
category: { description: "Product category", type: "string" },
|
|
122
|
-
|
|
123
|
-
inStock: { description: "Whether product is in stock", type: "boolean" },
|
|
124
|
-
rating: { description: "Customer rating (0-5)", type: "number" },
|
|
64
|
+
stock: { description: "Stock quantity", type: "number" },
|
|
125
65
|
},
|
|
126
66
|
},
|
|
127
|
-
examples: [
|
|
128
|
-
"CALL mockProducts(10) YIELD name, price",
|
|
129
|
-
"CALL mockProducts(50) YIELD name, price, category WHERE category = 'Electronics'",
|
|
130
|
-
],
|
|
67
|
+
examples: ["CALL products() YIELD id, name, price, category, stock"],
|
|
131
68
|
})
|
|
132
|
-
export class
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
constructor(
|
|
138
|
-
categories: string[] = ["Electronics", "Clothing", "Books", "Home", "Sports"],
|
|
139
|
-
adjectives: string[] = ["Premium", "Basic", "Pro", "Ultra", "Classic"],
|
|
140
|
-
nouns: string[] = ["Widget", "Gadget", "Item", "Product", "Thing"]
|
|
141
|
-
) {
|
|
142
|
-
super();
|
|
143
|
-
this.categories = categories;
|
|
144
|
-
this.adjectives = adjectives;
|
|
145
|
-
this.nouns = nouns;
|
|
69
|
+
export class Products extends AsyncFunction {
|
|
70
|
+
async *generate(): AsyncGenerator<any, void, unknown> {
|
|
71
|
+
for (const product of productsData) {
|
|
72
|
+
yield product;
|
|
73
|
+
}
|
|
146
74
|
}
|
|
75
|
+
}
|
|
147
76
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
77
|
+
@FunctionDef({
|
|
78
|
+
description: "Returns mock order data",
|
|
79
|
+
category: "async",
|
|
80
|
+
parameters: [],
|
|
81
|
+
output: {
|
|
82
|
+
description: "Order object",
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
id: { description: "Order ID", type: "number" },
|
|
86
|
+
userId: { description: "User ID who placed the order", type: "number" },
|
|
87
|
+
productId: { description: "Product ID ordered", type: "number" },
|
|
88
|
+
quantity: { description: "Quantity ordered", type: "number" },
|
|
89
|
+
total: { description: "Order total", type: "number" },
|
|
90
|
+
date: { description: "Order date", type: "string" },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
examples: ["CALL orders() YIELD id, userId, productId, quantity, total, date"],
|
|
94
|
+
})
|
|
95
|
+
export class Orders extends AsyncFunction {
|
|
96
|
+
async *generate(): AsyncGenerator<any, void, unknown> {
|
|
97
|
+
for (const order of ordersData) {
|
|
98
|
+
yield order;
|
|
167
99
|
}
|
|
168
100
|
}
|
|
169
101
|
}
|
|
170
|
-
|
|
171
|
-
export { MockUsers as default };
|
|
@@ -69,6 +69,18 @@ FlowQuery is a declarative query language for data processing pipelines. It uses
|
|
|
69
69
|
UNWIND myArray AS item
|
|
70
70
|
UNWIND range(0, 10) AS index
|
|
71
71
|
\`\`\`
|
|
72
|
+
|
|
73
|
+
**IMPORTANT**: An UNWIND statement cannot be followed directly by a WHERE statement. If you need to filter after unwinding, use a WITH clause in between:
|
|
74
|
+
\`\`\`
|
|
75
|
+
// WRONG - UNWIND cannot be directly followed by WHERE:
|
|
76
|
+
// UNWIND items AS item
|
|
77
|
+
// WHERE item.active = true
|
|
78
|
+
|
|
79
|
+
// CORRECT - use WITH between UNWIND and WHERE:
|
|
80
|
+
UNWIND items AS item
|
|
81
|
+
WITH item
|
|
82
|
+
WHERE item.active = true
|
|
83
|
+
\`\`\`
|
|
72
84
|
|
|
73
85
|
6. **WHERE** - Filter results
|
|
74
86
|
\`\`\`
|
package/package.json
CHANGED
package/src/compute/runner.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
2
|
+
import Function from "../parsing/functions/function";
|
|
3
|
+
import { FunctionMetadata } from "../parsing/functions/function_metadata";
|
|
1
4
|
import Operation from "../parsing/operations/operation";
|
|
2
5
|
import Parser from "../parsing/parser";
|
|
3
|
-
import { FunctionMetadata } from "../parsing/functions/function_metadata";
|
|
4
|
-
import Function from "../parsing/functions/function";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Executes a FlowQuery statement and retrieves the results.
|
|
8
|
-
*
|
|
9
|
+
*
|
|
9
10
|
* The Runner class parses a FlowQuery statement into an AST and executes it,
|
|
10
11
|
* managing the execution flow from the first operation to the final return statement.
|
|
11
|
-
*
|
|
12
|
+
*
|
|
12
13
|
* @example
|
|
13
14
|
* ```typescript
|
|
14
15
|
* const runner = new Runner("WITH 1 as x RETURN x");
|
|
@@ -24,7 +25,11 @@ class Runner {
|
|
|
24
25
|
* List all registered functions with their metadata.
|
|
25
26
|
* Added dynamically in index.browser.ts / index.node.ts
|
|
26
27
|
*/
|
|
27
|
-
static listFunctions: (options?: {
|
|
28
|
+
static listFunctions: (options?: {
|
|
29
|
+
category?: string;
|
|
30
|
+
asyncOnly?: boolean;
|
|
31
|
+
syncOnly?: boolean;
|
|
32
|
+
}) => FunctionMetadata[];
|
|
28
33
|
|
|
29
34
|
/**
|
|
30
35
|
* Get metadata for a specific function.
|
|
@@ -37,32 +42,32 @@ class Runner {
|
|
|
37
42
|
* Added dynamically in index.browser.ts / index.node.ts
|
|
38
43
|
*/
|
|
39
44
|
static Function: typeof Function;
|
|
40
|
-
|
|
45
|
+
|
|
41
46
|
/**
|
|
42
47
|
* Creates a new Runner instance and parses the FlowQuery statement.
|
|
43
|
-
*
|
|
48
|
+
*
|
|
44
49
|
* @param statement - The FlowQuery statement to execute
|
|
45
50
|
* @throws {Error} If the statement is null, empty, or contains syntax errors
|
|
46
51
|
*/
|
|
47
|
-
constructor(statement: string | null = null) {
|
|
48
|
-
if(statement === null || statement === "") {
|
|
49
|
-
throw new Error("
|
|
52
|
+
constructor(statement: string | null = null, ast: ASTNode | null = null) {
|
|
53
|
+
if ((statement === null || statement === "") && ast === null) {
|
|
54
|
+
throw new Error("Either statement or AST must be provided");
|
|
50
55
|
}
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
this.
|
|
54
|
-
this.last = ast.lastChild() as Operation;
|
|
56
|
+
const _ast = ast !== null ? ast : new Parser().parse(statement!);
|
|
57
|
+
this.first = _ast.firstChild() as Operation;
|
|
58
|
+
this.last = _ast.lastChild() as Operation;
|
|
55
59
|
}
|
|
56
|
-
|
|
60
|
+
|
|
57
61
|
/**
|
|
58
62
|
* Executes the parsed FlowQuery statement.
|
|
59
|
-
*
|
|
63
|
+
*
|
|
60
64
|
* @returns A promise that resolves when execution completes
|
|
61
65
|
* @throws {Error} If an error occurs during execution
|
|
62
66
|
*/
|
|
63
67
|
public async run(): Promise<void> {
|
|
64
68
|
return new Promise<void>(async (resolve, reject) => {
|
|
65
69
|
try {
|
|
70
|
+
await this.first.initialize();
|
|
66
71
|
await this.first.run();
|
|
67
72
|
await this.first.finish();
|
|
68
73
|
resolve();
|
|
@@ -71,10 +76,10 @@ class Runner {
|
|
|
71
76
|
}
|
|
72
77
|
});
|
|
73
78
|
}
|
|
74
|
-
|
|
79
|
+
|
|
75
80
|
/**
|
|
76
81
|
* Gets the results from the executed statement.
|
|
77
|
-
*
|
|
82
|
+
*
|
|
78
83
|
* @returns The results from the last operation (typically a RETURN statement)
|
|
79
84
|
*/
|
|
80
85
|
public get results(): any {
|
|
@@ -82,4 +87,4 @@ class Runner {
|
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
export default Runner;
|
|
90
|
+
export default Runner;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
class IndexEntry {
|
|
2
|
+
private _positions: number[];
|
|
3
|
+
private _index: number = -1;
|
|
4
|
+
|
|
5
|
+
constructor(positions: number[] = []) {
|
|
6
|
+
this._positions = positions;
|
|
7
|
+
}
|
|
8
|
+
public add(position: number): void {
|
|
9
|
+
this._positions.push(position);
|
|
10
|
+
}
|
|
11
|
+
public get position(): number {
|
|
12
|
+
return this._positions[this._index];
|
|
13
|
+
}
|
|
14
|
+
public reset(): void {
|
|
15
|
+
this._index = -1;
|
|
16
|
+
}
|
|
17
|
+
public next(): boolean {
|
|
18
|
+
if (this._index < this._positions.length - 1) {
|
|
19
|
+
this._index++;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
public clone(): IndexEntry {
|
|
25
|
+
return new IndexEntry([...this._positions]);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class Layer {
|
|
30
|
+
private _index: Map<string, IndexEntry> = new Map();
|
|
31
|
+
private _current: number = -1;
|
|
32
|
+
constructor(index: Map<string, IndexEntry>) {
|
|
33
|
+
this._index = index;
|
|
34
|
+
}
|
|
35
|
+
public get index(): Map<string, IndexEntry> {
|
|
36
|
+
return this._index;
|
|
37
|
+
}
|
|
38
|
+
public get current(): number {
|
|
39
|
+
return this._current;
|
|
40
|
+
}
|
|
41
|
+
public set current(value: number) {
|
|
42
|
+
this._current = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class Data {
|
|
47
|
+
protected _records: Record<string, any>[] = [];
|
|
48
|
+
private _layers: Map<number, Layer> = new Map();
|
|
49
|
+
|
|
50
|
+
constructor(records: Record<string, any>[] = []) {
|
|
51
|
+
this._records = records;
|
|
52
|
+
this._layers.set(0, new Layer(new Map()));
|
|
53
|
+
}
|
|
54
|
+
protected _buildIndex(key: string, level: number = 0): void {
|
|
55
|
+
this.layer(level).index.clear();
|
|
56
|
+
this._records.forEach((record, idx) => {
|
|
57
|
+
if (record.hasOwnProperty(key)) {
|
|
58
|
+
if (!this.layer(level).index.has(record[key])) {
|
|
59
|
+
this.layer(level).index.set(record[key], new IndexEntry());
|
|
60
|
+
}
|
|
61
|
+
this.layer(level).index.get(record[key])!.add(idx);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
public layer(level: number = 0): Layer {
|
|
66
|
+
if (!this._layers.has(level)) {
|
|
67
|
+
const first = this._layers.get(0)!;
|
|
68
|
+
const cloned = new Map<string, IndexEntry>();
|
|
69
|
+
for (const [key, entry] of first.index) {
|
|
70
|
+
cloned.set(key, entry.clone());
|
|
71
|
+
}
|
|
72
|
+
this._layers.set(level, new Layer(cloned));
|
|
73
|
+
}
|
|
74
|
+
return this._layers.get(level)!;
|
|
75
|
+
}
|
|
76
|
+
protected _find(key: string, level: number = 0): boolean {
|
|
77
|
+
if (!this.layer(level).index.has(key)) {
|
|
78
|
+
this.layer(level).current = this._records.length; // Move to end
|
|
79
|
+
return false;
|
|
80
|
+
} else {
|
|
81
|
+
const entry = this.layer(level).index.get(key)!;
|
|
82
|
+
const more = entry.next();
|
|
83
|
+
if (!more) {
|
|
84
|
+
this.layer(level).current = this._records.length; // Move to end
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
this.layer(level).current = entry.position;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
public reset(): void {
|
|
92
|
+
this.layer(0).current = -1;
|
|
93
|
+
for (const entry of this.layer(0).index.values()) {
|
|
94
|
+
entry.reset();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
public next(level: number = 0): boolean {
|
|
98
|
+
if (this.layer(level).current < this._records.length - 1) {
|
|
99
|
+
this.layer(level).current++;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
public current(level: number = 0): Record<string, any> | null {
|
|
105
|
+
if (this.layer(level).current < this._records.length) {
|
|
106
|
+
return this._records[this.layer(level).current];
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export default Data;
|