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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
2
|
+
import Node from "./node";
|
|
3
|
+
import NodeData, { NodeRecord } from "./node_data";
|
|
4
|
+
import PhysicalNode from "./physical_node";
|
|
5
|
+
import PhysicalRelationship from "./physical_relationship";
|
|
6
|
+
import Relationship from "./relationship";
|
|
7
|
+
import RelationshipData, { RelationshipRecord } from "./relationship_data";
|
|
8
|
+
|
|
9
|
+
class Database {
|
|
10
|
+
private static instance: Database;
|
|
11
|
+
private static nodes: Map<string, PhysicalNode> = new Map();
|
|
12
|
+
private static relationships: Map<string, PhysicalRelationship> = new Map();
|
|
13
|
+
|
|
14
|
+
public static getInstance(): Database {
|
|
15
|
+
if (!Database.instance) {
|
|
16
|
+
Database.instance = new Database();
|
|
17
|
+
}
|
|
18
|
+
return Database.instance;
|
|
19
|
+
}
|
|
20
|
+
public addNode(node: Node, statement: ASTNode): void {
|
|
21
|
+
if (node.label === null) {
|
|
22
|
+
throw new Error("Node label is null");
|
|
23
|
+
}
|
|
24
|
+
const physical = new PhysicalNode(null, node.label);
|
|
25
|
+
physical.statement = statement;
|
|
26
|
+
Database.nodes.set(node.label, physical);
|
|
27
|
+
}
|
|
28
|
+
public getNode(node: Node): PhysicalNode | null {
|
|
29
|
+
return Database.nodes.get(node.label!) || null;
|
|
30
|
+
}
|
|
31
|
+
public addRelationship(relationship: Relationship, statement: ASTNode): void {
|
|
32
|
+
if (relationship.type === null) {
|
|
33
|
+
throw new Error("Relationship type is null");
|
|
34
|
+
}
|
|
35
|
+
const physical = new PhysicalRelationship(null, relationship.type);
|
|
36
|
+
physical.statement = statement;
|
|
37
|
+
Database.relationships.set(relationship.type, physical);
|
|
38
|
+
}
|
|
39
|
+
public getRelationship(relationship: Relationship): PhysicalRelationship | null {
|
|
40
|
+
return Database.relationships.get(relationship.type!) || null;
|
|
41
|
+
}
|
|
42
|
+
public async getData(element: Node | Relationship): Promise<NodeData | RelationshipData> {
|
|
43
|
+
if (element instanceof Node) {
|
|
44
|
+
const node = this.getNode(element);
|
|
45
|
+
if (node === null) {
|
|
46
|
+
throw new Error(`Physical node not found for label ${element.label}`);
|
|
47
|
+
}
|
|
48
|
+
const data = await node.data();
|
|
49
|
+
return new NodeData(data as NodeRecord[]);
|
|
50
|
+
} else if (element instanceof Relationship) {
|
|
51
|
+
const relationship = this.getRelationship(element);
|
|
52
|
+
if (relationship === null) {
|
|
53
|
+
throw new Error(`Physical relationship not found for type ${element.type}`);
|
|
54
|
+
}
|
|
55
|
+
const data = await relationship.data();
|
|
56
|
+
return new RelationshipData(data as RelationshipRecord[]);
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error("Element is neither Node nor Relationship");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default Database;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class Hops {
|
|
2
|
+
private _min: number = 0;
|
|
3
|
+
private _max: number = 1;
|
|
4
|
+
|
|
5
|
+
public set min(min: number) {
|
|
6
|
+
this._min = min;
|
|
7
|
+
}
|
|
8
|
+
public get min(): number {
|
|
9
|
+
return this._min;
|
|
10
|
+
}
|
|
11
|
+
public set max(max: number) {
|
|
12
|
+
this._max = max;
|
|
13
|
+
}
|
|
14
|
+
public get max(): number {
|
|
15
|
+
return this._max;
|
|
16
|
+
}
|
|
17
|
+
public multi(): boolean {
|
|
18
|
+
return this._max > 1 || this._max === -1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default Hops;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
2
|
+
import Expression from "../parsing/expressions/expression";
|
|
3
|
+
import NodeData, { NodeRecord } from "./node_data";
|
|
4
|
+
import Relationship from "./relationship";
|
|
5
|
+
|
|
6
|
+
class Node extends ASTNode {
|
|
7
|
+
protected _identifier: string | null = null;
|
|
8
|
+
protected _label: string | null = null;
|
|
9
|
+
protected _properties: Map<string, Expression> = new Map();
|
|
10
|
+
protected _value: NodeRecord | null = null;
|
|
11
|
+
|
|
12
|
+
protected _incoming: Relationship | null = null;
|
|
13
|
+
protected _outgoing: Relationship | null = null;
|
|
14
|
+
|
|
15
|
+
private _data: NodeData | null = null;
|
|
16
|
+
|
|
17
|
+
// Function to be called after each 'next' and 'find' operation
|
|
18
|
+
// It is used to chain operations in a traversal
|
|
19
|
+
// For example, after matching on a graph pattern, we may want to
|
|
20
|
+
// continue to the next node or relationship in the pattern, or
|
|
21
|
+
// perform the next operation in a statement.
|
|
22
|
+
private _todoNext: (() => Promise<void>) | null = null;
|
|
23
|
+
|
|
24
|
+
constructor(identifier: string | null = null, label: string | null = null) {
|
|
25
|
+
super();
|
|
26
|
+
this._identifier = identifier;
|
|
27
|
+
this._label = label;
|
|
28
|
+
}
|
|
29
|
+
public set identifier(identifier: string) {
|
|
30
|
+
this._identifier = identifier;
|
|
31
|
+
}
|
|
32
|
+
public get identifier(): string | null {
|
|
33
|
+
return this._identifier;
|
|
34
|
+
}
|
|
35
|
+
public set label(label: string) {
|
|
36
|
+
this._label = label;
|
|
37
|
+
}
|
|
38
|
+
public get label(): string | null {
|
|
39
|
+
return this._label;
|
|
40
|
+
}
|
|
41
|
+
public get properties(): Map<string, Expression> {
|
|
42
|
+
return this._properties;
|
|
43
|
+
}
|
|
44
|
+
public setProperty(key: string, value: Expression): void {
|
|
45
|
+
this._properties.set(key, value);
|
|
46
|
+
}
|
|
47
|
+
public getProperty(key: string): Expression | null {
|
|
48
|
+
return this._properties.get(key) || null;
|
|
49
|
+
}
|
|
50
|
+
public setValue(value: NodeRecord): void {
|
|
51
|
+
this._value = value;
|
|
52
|
+
}
|
|
53
|
+
public value(): NodeRecord | null {
|
|
54
|
+
return this._value;
|
|
55
|
+
}
|
|
56
|
+
public set outgoing(relationship: Relationship | null) {
|
|
57
|
+
this._outgoing = relationship;
|
|
58
|
+
}
|
|
59
|
+
public get outgoing(): Relationship | null {
|
|
60
|
+
return this._outgoing;
|
|
61
|
+
}
|
|
62
|
+
public set incoming(relationship: Relationship | null) {
|
|
63
|
+
this._incoming = relationship;
|
|
64
|
+
}
|
|
65
|
+
public get incoming(): Relationship | null {
|
|
66
|
+
return this._incoming;
|
|
67
|
+
}
|
|
68
|
+
public setData(data: NodeData | null): void {
|
|
69
|
+
this._data = data;
|
|
70
|
+
}
|
|
71
|
+
public async next(): Promise<void> {
|
|
72
|
+
this._data?.reset();
|
|
73
|
+
while (this._data?.next()) {
|
|
74
|
+
this.setValue(this._data?.current()!);
|
|
75
|
+
await this._outgoing?.find(this._value!.id);
|
|
76
|
+
await this.runTodoNext();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
public async find(id: string, hop: number = 0): Promise<void> {
|
|
80
|
+
this._data?.reset();
|
|
81
|
+
while (this._data?.find(id, hop)) {
|
|
82
|
+
this.setValue(this._data?.current(hop) as NodeRecord);
|
|
83
|
+
this._incoming?.setEndNode(this);
|
|
84
|
+
await this._outgoing?.find(this._value!.id, hop);
|
|
85
|
+
await this.runTodoNext();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// For setting a function to be called after each 'next' and 'find' operation
|
|
89
|
+
public set todoNext(func: (() => Promise<void>) | null) {
|
|
90
|
+
this._todoNext = func;
|
|
91
|
+
}
|
|
92
|
+
public async runTodoNext(): Promise<void> {
|
|
93
|
+
if (this._todoNext) {
|
|
94
|
+
await this._todoNext();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default Node;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Data from "./data";
|
|
2
|
+
|
|
3
|
+
export type NodeRecord = { id: string } & Record<string, any>;
|
|
4
|
+
|
|
5
|
+
class NodeData extends Data {
|
|
6
|
+
constructor(records: NodeRecord[] = []) {
|
|
7
|
+
super(records);
|
|
8
|
+
super._buildIndex("id");
|
|
9
|
+
}
|
|
10
|
+
public find(id: string, hop: number = 0): boolean {
|
|
11
|
+
return super._find(id, hop);
|
|
12
|
+
}
|
|
13
|
+
public current(hop: number = 0): NodeRecord | null {
|
|
14
|
+
return super.current(hop) as NodeRecord | null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default NodeData;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Node from "./node";
|
|
2
|
+
|
|
3
|
+
class NodeReference extends Node {
|
|
4
|
+
private _reference: Node | null = null;
|
|
5
|
+
constructor(base: Node, reference: Node) {
|
|
6
|
+
super();
|
|
7
|
+
this._identifier = base.identifier;
|
|
8
|
+
this._label = base.label;
|
|
9
|
+
this._properties = base.properties;
|
|
10
|
+
this._outgoing = base.outgoing;
|
|
11
|
+
this._incoming = base.incoming;
|
|
12
|
+
this._reference = reference;
|
|
13
|
+
}
|
|
14
|
+
public get reference(): Node | null {
|
|
15
|
+
return this._reference;
|
|
16
|
+
}
|
|
17
|
+
public async next(): Promise<void> {
|
|
18
|
+
this.setValue(this._reference!.value()!);
|
|
19
|
+
await this._outgoing?.find(this._value!.id);
|
|
20
|
+
await this.runTodoNext();
|
|
21
|
+
}
|
|
22
|
+
public async find(id: string, hop: number = 0): Promise<void> {
|
|
23
|
+
const referenced = this._reference?.value();
|
|
24
|
+
if (id !== referenced?.id) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.setValue(referenced!);
|
|
28
|
+
await this._outgoing?.find(this._value!.id, hop);
|
|
29
|
+
await this.runTodoNext();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default NodeReference;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
2
|
+
import Database from "./database";
|
|
3
|
+
import Node from "./node";
|
|
4
|
+
import NodeData from "./node_data";
|
|
5
|
+
import NodeReference from "./node_reference";
|
|
6
|
+
import Relationship from "./relationship";
|
|
7
|
+
import RelationshipData from "./relationship_data";
|
|
8
|
+
import RelationshipReference from "./relationship_reference";
|
|
9
|
+
|
|
10
|
+
class Pattern extends ASTNode {
|
|
11
|
+
private _identifier: string | null = null;
|
|
12
|
+
protected _chain: (Node | Relationship)[] = [];
|
|
13
|
+
public set identifier(id: string | null) {
|
|
14
|
+
this._identifier = id;
|
|
15
|
+
}
|
|
16
|
+
public get identifier(): string | null {
|
|
17
|
+
return this._identifier;
|
|
18
|
+
}
|
|
19
|
+
public addElement(element: Relationship | Node): void {
|
|
20
|
+
if (
|
|
21
|
+
this._chain.length > 0 &&
|
|
22
|
+
this._chain[this._chain.length - 1].constructor === element.constructor
|
|
23
|
+
) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Cannot add two consecutive elements of the same type to the graph pattern"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
if (this._chain.length > 0) {
|
|
29
|
+
const last = this._chain[this._chain.length - 1];
|
|
30
|
+
if (last instanceof Node && element instanceof Relationship) {
|
|
31
|
+
last.outgoing = element as Relationship;
|
|
32
|
+
element.source = last as Node;
|
|
33
|
+
}
|
|
34
|
+
if (last instanceof Relationship && element instanceof Node) {
|
|
35
|
+
last.target = element as Node;
|
|
36
|
+
element.incoming = last as Relationship;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this._chain.push(element);
|
|
40
|
+
}
|
|
41
|
+
public get chain(): (Node | Relationship)[] {
|
|
42
|
+
return this._chain;
|
|
43
|
+
}
|
|
44
|
+
public get startNode(): Node {
|
|
45
|
+
if (this._chain.length === 0) {
|
|
46
|
+
throw new Error("Pattern is empty");
|
|
47
|
+
}
|
|
48
|
+
const first = this._chain[0];
|
|
49
|
+
if (first instanceof Node) {
|
|
50
|
+
return first;
|
|
51
|
+
}
|
|
52
|
+
throw new Error("Pattern does not start with a node");
|
|
53
|
+
}
|
|
54
|
+
public get endNode(): Node {
|
|
55
|
+
if (this._chain.length === 0) {
|
|
56
|
+
throw new Error("Pattern is empty");
|
|
57
|
+
}
|
|
58
|
+
const last = this._chain[this._chain.length - 1];
|
|
59
|
+
if (last instanceof Node) {
|
|
60
|
+
return last;
|
|
61
|
+
}
|
|
62
|
+
throw new Error("Pattern does not end with a node");
|
|
63
|
+
}
|
|
64
|
+
public value(): any {
|
|
65
|
+
return Array.from(this.values());
|
|
66
|
+
}
|
|
67
|
+
public *values(): Generator<any> {
|
|
68
|
+
for (const element of this._chain) {
|
|
69
|
+
if (element instanceof Node) {
|
|
70
|
+
yield element.value();
|
|
71
|
+
} else if (element instanceof Relationship) {
|
|
72
|
+
let i = 0;
|
|
73
|
+
for (const match of element.matches) {
|
|
74
|
+
yield match;
|
|
75
|
+
if (i < element.matches.length - 1) {
|
|
76
|
+
yield match.endNode;
|
|
77
|
+
}
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
public async fetchData(): Promise<void> {
|
|
84
|
+
const db: Database = Database.getInstance();
|
|
85
|
+
for (const element of this._chain) {
|
|
86
|
+
if (
|
|
87
|
+
element.constructor === NodeReference ||
|
|
88
|
+
element.constructor === RelationshipReference
|
|
89
|
+
) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const data = await db.getData(element);
|
|
93
|
+
if (element.constructor === Node) {
|
|
94
|
+
element.setData(data as NodeData);
|
|
95
|
+
} else if (element.constructor === Relationship) {
|
|
96
|
+
element.setData(data as RelationshipData);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export default Pattern;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Node from "./node";
|
|
2
|
+
import NodeReference from "./node_reference";
|
|
3
|
+
import Pattern from "./pattern";
|
|
4
|
+
import Relationship from "./relationship";
|
|
5
|
+
|
|
6
|
+
class PatternExpression extends Pattern {
|
|
7
|
+
private _fetched: boolean = false;
|
|
8
|
+
private _evaluation: boolean = false;
|
|
9
|
+
public set identifier(id: string | null) {
|
|
10
|
+
throw new Error("Cannot set identifier on PatternExpression");
|
|
11
|
+
}
|
|
12
|
+
public addElement(element: Relationship | Node): void {
|
|
13
|
+
if (this._chain.length == 0 && !(element instanceof NodeReference)) {
|
|
14
|
+
throw new Error("PatternExpression must start with a NodeReference");
|
|
15
|
+
}
|
|
16
|
+
super.addElement(element);
|
|
17
|
+
}
|
|
18
|
+
public async evaluate(): Promise<void> {
|
|
19
|
+
this._evaluation = false;
|
|
20
|
+
this.endNode.todoNext = async () => {
|
|
21
|
+
this._evaluation = true;
|
|
22
|
+
};
|
|
23
|
+
await this.startNode.next();
|
|
24
|
+
}
|
|
25
|
+
public value(): boolean {
|
|
26
|
+
return this._evaluation;
|
|
27
|
+
}
|
|
28
|
+
public async fetchData(): Promise<void> {
|
|
29
|
+
if (this._fetched) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
await super.fetchData();
|
|
33
|
+
this._fetched = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default PatternExpression;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Pattern from "./pattern";
|
|
2
|
+
|
|
3
|
+
class Patterns {
|
|
4
|
+
private _patterns: Pattern[] = [];
|
|
5
|
+
constructor(patterns: Pattern[] = []) {
|
|
6
|
+
this._patterns = patterns;
|
|
7
|
+
}
|
|
8
|
+
public get patterns(): Pattern[] {
|
|
9
|
+
return this._patterns;
|
|
10
|
+
}
|
|
11
|
+
public async initialize(): Promise<void> {
|
|
12
|
+
let previous: Pattern | null = null;
|
|
13
|
+
for (const pattern of this._patterns) {
|
|
14
|
+
await pattern.fetchData(); // Ensure data is loaded
|
|
15
|
+
if (previous !== null) {
|
|
16
|
+
// Chain the patterns together
|
|
17
|
+
previous.endNode.todoNext = async () => {
|
|
18
|
+
await pattern.startNode.next();
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
previous = pattern;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
public set toDoNext(func: () => Promise<void>) {
|
|
25
|
+
if (this._patterns.length > 0) {
|
|
26
|
+
this._patterns[this._patterns.length - 1].endNode.todoNext = func;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
public async traverse(): Promise<void> {
|
|
30
|
+
if (this._patterns.length > 0) {
|
|
31
|
+
await this._patterns[0].startNode.next();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Patterns;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Runner from "../compute/runner";
|
|
2
|
+
import ASTNode from "../parsing/ast_node";
|
|
3
|
+
import Node from "./node";
|
|
4
|
+
|
|
5
|
+
class PhysicalNode extends Node {
|
|
6
|
+
private _statement: ASTNode | null = null;
|
|
7
|
+
public set statement(statement: ASTNode | null) {
|
|
8
|
+
this._statement = statement;
|
|
9
|
+
}
|
|
10
|
+
public get statement(): ASTNode | null {
|
|
11
|
+
return this._statement;
|
|
12
|
+
}
|
|
13
|
+
public async data(): Promise<Record<string, any>[]> {
|
|
14
|
+
if (this._statement === null) {
|
|
15
|
+
throw new Error("Statement is null");
|
|
16
|
+
}
|
|
17
|
+
const runner = new Runner(null, this._statement);
|
|
18
|
+
await runner.run();
|
|
19
|
+
return runner.results;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default PhysicalNode;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Runner from "../compute/runner";
|
|
2
|
+
import ASTNode from "../parsing/ast_node";
|
|
3
|
+
import Relationship from "./relationship";
|
|
4
|
+
|
|
5
|
+
class PhysicalRelationship extends Relationship {
|
|
6
|
+
private _statement: ASTNode | null = null;
|
|
7
|
+
public set statement(statement: ASTNode | null) {
|
|
8
|
+
this._statement = statement;
|
|
9
|
+
}
|
|
10
|
+
public get statement(): ASTNode | null {
|
|
11
|
+
return this._statement;
|
|
12
|
+
}
|
|
13
|
+
public async data(): Promise<Record<string, any>[]> {
|
|
14
|
+
if (this._statement === null) {
|
|
15
|
+
throw new Error("Statement is null");
|
|
16
|
+
}
|
|
17
|
+
const runner = new Runner(null, this._statement);
|
|
18
|
+
await runner.run();
|
|
19
|
+
return runner.results;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default PhysicalRelationship;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
2
|
+
import Expression from "../parsing/expressions/expression";
|
|
3
|
+
import Hops from "./hops";
|
|
4
|
+
import Node from "./node";
|
|
5
|
+
import RelationshipData, { RelationshipRecord } from "./relationship_data";
|
|
6
|
+
import RelationshipMatchCollector, {
|
|
7
|
+
RelationshipMatchRecord,
|
|
8
|
+
} from "./relationship_match_collector";
|
|
9
|
+
|
|
10
|
+
class Relationship extends ASTNode {
|
|
11
|
+
protected _identifier: string | null = null;
|
|
12
|
+
protected _type: string | null = null;
|
|
13
|
+
protected _properties: Map<string, Expression> = new Map();
|
|
14
|
+
protected _hops: Hops = new Hops();
|
|
15
|
+
|
|
16
|
+
protected _value: RelationshipMatchRecord | RelationshipMatchRecord[] | null = null;
|
|
17
|
+
protected _matches: RelationshipMatchCollector = new RelationshipMatchCollector();
|
|
18
|
+
|
|
19
|
+
protected _source: Node | null = null;
|
|
20
|
+
protected _target: Node | null = null;
|
|
21
|
+
|
|
22
|
+
private _data: RelationshipData | null = null;
|
|
23
|
+
|
|
24
|
+
constructor(identifier: string | null = null, type: string | null = null) {
|
|
25
|
+
super();
|
|
26
|
+
this._identifier = identifier;
|
|
27
|
+
this._type = type;
|
|
28
|
+
}
|
|
29
|
+
public set identifier(identifier: string) {
|
|
30
|
+
this._identifier = identifier;
|
|
31
|
+
}
|
|
32
|
+
public get identifier(): string | null {
|
|
33
|
+
return this._identifier;
|
|
34
|
+
}
|
|
35
|
+
public set type(type: string) {
|
|
36
|
+
this._type = type;
|
|
37
|
+
}
|
|
38
|
+
public get type(): string | null {
|
|
39
|
+
return this._type;
|
|
40
|
+
}
|
|
41
|
+
public get properties(): Record<string, any> {
|
|
42
|
+
return this._data?.properties() || {};
|
|
43
|
+
}
|
|
44
|
+
public setProperty(key: string, value: Expression): void {
|
|
45
|
+
this._properties.set(key, value);
|
|
46
|
+
}
|
|
47
|
+
public getProperty(key: string): Expression | null {
|
|
48
|
+
return this._properties.get(key) || null;
|
|
49
|
+
}
|
|
50
|
+
public set hops(hops: Hops) {
|
|
51
|
+
this._hops = hops;
|
|
52
|
+
}
|
|
53
|
+
public get hops(): Hops | null {
|
|
54
|
+
return this._hops;
|
|
55
|
+
}
|
|
56
|
+
public setValue(relationship: Relationship): void {
|
|
57
|
+
const match: RelationshipMatchRecord = this._matches.push(relationship);
|
|
58
|
+
this._value = this._matches.value();
|
|
59
|
+
}
|
|
60
|
+
public set source(node: Node | null) {
|
|
61
|
+
this._source = node;
|
|
62
|
+
}
|
|
63
|
+
public get source(): Node | null {
|
|
64
|
+
return this._source;
|
|
65
|
+
}
|
|
66
|
+
public set target(node: Node | null) {
|
|
67
|
+
this._target = node;
|
|
68
|
+
}
|
|
69
|
+
public get target(): Node | null {
|
|
70
|
+
return this._target;
|
|
71
|
+
}
|
|
72
|
+
public value(): RelationshipMatchRecord | RelationshipMatchRecord[] | null {
|
|
73
|
+
return this._value;
|
|
74
|
+
}
|
|
75
|
+
public get matches(): RelationshipMatchRecord[] {
|
|
76
|
+
return this._matches.matches;
|
|
77
|
+
}
|
|
78
|
+
public setData(data: RelationshipData | null): void {
|
|
79
|
+
this._data = data;
|
|
80
|
+
}
|
|
81
|
+
public getData(): RelationshipData | null {
|
|
82
|
+
return this._data;
|
|
83
|
+
}
|
|
84
|
+
public setEndNode(node: Node): void {
|
|
85
|
+
this._matches.endNode = node;
|
|
86
|
+
}
|
|
87
|
+
public async find(left_id: string, hop: number = 0): Promise<void> {
|
|
88
|
+
// Save original source node
|
|
89
|
+
const original = this._source;
|
|
90
|
+
if (hop > 0) {
|
|
91
|
+
// For hops greater than 0, the source becomes the target of the previous hop
|
|
92
|
+
this._source = this._target;
|
|
93
|
+
}
|
|
94
|
+
if (hop === 0) {
|
|
95
|
+
this._data?.reset();
|
|
96
|
+
}
|
|
97
|
+
while (this._data?.find(left_id, hop)) {
|
|
98
|
+
const data: RelationshipRecord = this._data?.current(hop) as RelationshipRecord;
|
|
99
|
+
if (hop >= this.hops!.min) {
|
|
100
|
+
this.setValue(this);
|
|
101
|
+
await this._target?.find(data.right_id, hop);
|
|
102
|
+
if (this._matches.isCircular()) {
|
|
103
|
+
throw new Error("Circular relationship detected");
|
|
104
|
+
}
|
|
105
|
+
if (hop + 1 < this.hops!.max) {
|
|
106
|
+
await this.find(data.right_id, hop + 1);
|
|
107
|
+
}
|
|
108
|
+
this._matches.pop();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Restore original source node
|
|
112
|
+
this._source = original;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export default Relationship;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Data from "./data";
|
|
2
|
+
|
|
3
|
+
export type RelationshipRecord = { left_id: string; right_id: string } & Record<string, any>;
|
|
4
|
+
|
|
5
|
+
class RelationshipData extends Data {
|
|
6
|
+
constructor(records: RelationshipRecord[] = []) {
|
|
7
|
+
super(records);
|
|
8
|
+
super._buildIndex("left_id");
|
|
9
|
+
}
|
|
10
|
+
public find(left_id: string, hop: number = 0): boolean {
|
|
11
|
+
return super._find(left_id, hop);
|
|
12
|
+
}
|
|
13
|
+
/*
|
|
14
|
+
** Get the properties of the current relationship record
|
|
15
|
+
'' excluding the left_id and right_id fields
|
|
16
|
+
*/
|
|
17
|
+
public properties(): Record<string, any> | null {
|
|
18
|
+
const current = this.current();
|
|
19
|
+
if (current) {
|
|
20
|
+
const { left_id, right_id, ...props } = current;
|
|
21
|
+
return props;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default RelationshipData;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Relationship from "./relationship";
|
|
2
|
+
|
|
3
|
+
export type RelationshipMatchRecord = {
|
|
4
|
+
type: string;
|
|
5
|
+
startNode: Record<string, any>;
|
|
6
|
+
endNode: Record<string, any> | null;
|
|
7
|
+
properties: Record<string, any>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
class RelationshipMatchCollector {
|
|
11
|
+
private _matches: RelationshipMatchRecord[] = [];
|
|
12
|
+
private _nodeIds: Array<string> = [];
|
|
13
|
+
|
|
14
|
+
public push(relationship: Relationship): RelationshipMatchRecord {
|
|
15
|
+
const match: RelationshipMatchRecord = {
|
|
16
|
+
type: relationship.type!,
|
|
17
|
+
startNode: relationship.source?.value() || {},
|
|
18
|
+
endNode: null,
|
|
19
|
+
properties: relationship.properties,
|
|
20
|
+
};
|
|
21
|
+
this._matches.push(match);
|
|
22
|
+
this._nodeIds.push(match.startNode.id);
|
|
23
|
+
return match;
|
|
24
|
+
}
|
|
25
|
+
public set endNode(node: any) {
|
|
26
|
+
if (this._matches.length > 0) {
|
|
27
|
+
this._matches[this._matches.length - 1].endNode = node.value();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
public pop(): RelationshipMatchRecord | undefined {
|
|
31
|
+
this._nodeIds.pop();
|
|
32
|
+
return this._matches.pop();
|
|
33
|
+
}
|
|
34
|
+
public value(): RelationshipMatchRecord | RelationshipMatchRecord[] | null {
|
|
35
|
+
if (this._matches.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
} else if (this._matches.length === 1) {
|
|
38
|
+
const _match = this._matches[0];
|
|
39
|
+
return _match;
|
|
40
|
+
} else {
|
|
41
|
+
const _matches = this._matches;
|
|
42
|
+
return _matches;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
public get matches(): RelationshipMatchRecord[] {
|
|
46
|
+
return this._matches;
|
|
47
|
+
}
|
|
48
|
+
/*
|
|
49
|
+
** Checks if the collected relationships form a circular pattern
|
|
50
|
+
** meaning the same node id occur more than 2 times in the collected matches
|
|
51
|
+
*/
|
|
52
|
+
public isCircular(): boolean {
|
|
53
|
+
const seen = new Set(this._nodeIds);
|
|
54
|
+
return seen.size < this._nodeIds.length;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default RelationshipMatchCollector;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Relationship from "./relationship";
|
|
2
|
+
import { RelationshipRecord } from "./relationship_data";
|
|
3
|
+
|
|
4
|
+
class RelationshipReference extends Relationship {
|
|
5
|
+
private _reference: Relationship | null = null;
|
|
6
|
+
constructor(base: Relationship, reference: Relationship) {
|
|
7
|
+
super();
|
|
8
|
+
this._identifier = base.identifier;
|
|
9
|
+
this._type = base.type;
|
|
10
|
+
this._hops = base.hops!;
|
|
11
|
+
this._source = base.source;
|
|
12
|
+
this._target = base.target;
|
|
13
|
+
this._reference = reference;
|
|
14
|
+
}
|
|
15
|
+
public async find(left_id: string, hop: number = 0): Promise<void> {
|
|
16
|
+
this.setValue(this._reference!);
|
|
17
|
+
const data: RelationshipRecord = this._reference!.getData()?.current(
|
|
18
|
+
hop
|
|
19
|
+
) as RelationshipRecord;
|
|
20
|
+
await this._target?.find(data.right_id, hop);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default RelationshipReference;
|