flowquery 1.0.30 → 1.0.32
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/dist/flowquery.min.js +1 -1
- package/dist/graph/node_reference.d.ts +3 -2
- package/dist/graph/node_reference.d.ts.map +1 -1
- package/dist/graph/node_reference.js.map +1 -1
- package/dist/graph/relationship.d.ts +2 -1
- package/dist/graph/relationship.d.ts.map +1 -1
- package/dist/graph/relationship.js +15 -15
- package/dist/graph/relationship.js.map +1 -1
- package/dist/graph/relationship_data.d.ts +1 -2
- package/dist/graph/relationship_data.d.ts.map +1 -1
- package/dist/graph/relationship_data.js +2 -5
- package/dist/graph/relationship_data.js.map +1 -1
- package/dist/graph/relationship_match_collector.d.ts +2 -2
- package/dist/graph/relationship_match_collector.d.ts.map +1 -1
- package/dist/graph/relationship_match_collector.js +6 -7
- package/dist/graph/relationship_match_collector.js.map +1 -1
- package/dist/parsing/operations/group_by.d.ts.map +1 -1
- package/dist/parsing/operations/group_by.js +8 -4
- package/dist/parsing/operations/group_by.js.map +1 -1
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +2 -1
- package/dist/parsing/parser.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/graph/node_reference.py +5 -4
- package/flowquery-py/src/graph/relationship.py +20 -22
- package/flowquery-py/src/graph/relationship_data.py +4 -7
- package/flowquery-py/src/graph/relationship_match_collector.py +5 -7
- package/flowquery-py/src/parsing/operations/group_by.py +16 -2
- package/flowquery-py/src/parsing/parser.py +1 -1
- package/flowquery-py/tests/compute/test_runner.py +61 -5
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/graph/node_reference.ts +4 -3
- package/src/graph/relationship.ts +15 -15
- package/src/graph/relationship_data.ts +2 -5
- package/src/graph/relationship_match_collector.ts +6 -7
- package/src/parsing/operations/group_by.ts +27 -19
- package/src/parsing/parser.ts +4 -1
- package/tests/compute/runner.test.ts +123 -4
- package/tests/parsing/parser.test.ts +2 -2
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import ASTNode from "../parsing/ast_node";
|
|
1
2
|
import Node from "./node";
|
|
2
3
|
|
|
3
4
|
class NodeReference extends Node {
|
|
4
|
-
private _reference:
|
|
5
|
-
constructor(base: Node, reference:
|
|
5
|
+
private _reference: ASTNode | null = null;
|
|
6
|
+
constructor(base: Node, reference: ASTNode) {
|
|
6
7
|
super();
|
|
7
8
|
this._identifier = base.identifier;
|
|
8
9
|
this._label = base.label;
|
|
@@ -11,7 +12,7 @@ class NodeReference extends Node {
|
|
|
11
12
|
this._incoming = base.incoming;
|
|
12
13
|
this._reference = reference;
|
|
13
14
|
}
|
|
14
|
-
public get reference():
|
|
15
|
+
public get reference(): ASTNode | null {
|
|
15
16
|
return this._reference;
|
|
16
17
|
}
|
|
17
18
|
public async next(): Promise<void> {
|
|
@@ -71,8 +71,8 @@ class Relationship extends ASTNode {
|
|
|
71
71
|
public get hops(): Hops | null {
|
|
72
72
|
return this._hops;
|
|
73
73
|
}
|
|
74
|
-
public setValue(relationship: Relationship): void {
|
|
75
|
-
const match: RelationshipMatchRecord = this._matches.push(relationship);
|
|
74
|
+
public setValue(relationship: Relationship, traversalId: string = ""): void {
|
|
75
|
+
const match: RelationshipMatchRecord = this._matches.push(relationship, traversalId);
|
|
76
76
|
this._value = this._matches.value();
|
|
77
77
|
}
|
|
78
78
|
public set source(node: Node | null) {
|
|
@@ -108,10 +108,12 @@ class Relationship extends ASTNode {
|
|
|
108
108
|
public setEndNode(node: Node): void {
|
|
109
109
|
this._matches.endNode = node;
|
|
110
110
|
}
|
|
111
|
+
public _left_id_or_right_id(): string {
|
|
112
|
+
return this._direction === "left" ? "left_id" : "right_id";
|
|
113
|
+
}
|
|
111
114
|
public async find(left_id: string, hop: number = 0): Promise<void> {
|
|
112
115
|
// Save original source node
|
|
113
116
|
const original = this._source;
|
|
114
|
-
const isLeft = this._direction === "left";
|
|
115
117
|
if (hop > 0) {
|
|
116
118
|
// For hops greater than 0, the source becomes the target of the previous hop
|
|
117
119
|
this._source = this._target;
|
|
@@ -127,28 +129,26 @@ class Relationship extends ASTNode {
|
|
|
127
129
|
await this._target.find(left_id, hop);
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
|
-
|
|
131
|
-
? (id: string, h: number) => this._data!.findReverse(id, h)
|
|
132
|
-
: (id: string, h: number) => this._data!.find(id, h);
|
|
133
|
-
const followId = isLeft ? "left_id" : "right_id";
|
|
134
|
-
while (findMatch(left_id, hop)) {
|
|
132
|
+
while (this._data!.find(left_id, hop, this._direction)) {
|
|
135
133
|
const data: RelationshipRecord = this._data?.current(hop) as RelationshipRecord;
|
|
134
|
+
const id = data[this._left_id_or_right_id()];
|
|
136
135
|
if (hop + 1 >= this.hops!.min) {
|
|
137
|
-
this.setValue(this);
|
|
136
|
+
this.setValue(this, left_id);
|
|
138
137
|
if (!this._matchesProperties(hop)) {
|
|
139
138
|
continue;
|
|
140
139
|
}
|
|
141
|
-
await this._target?.find(
|
|
142
|
-
if (this._matches.isCircular()) {
|
|
143
|
-
throw new Error("Circular relationship detected");
|
|
144
|
-
}
|
|
140
|
+
await this._target?.find(id, hop);
|
|
145
141
|
if (hop + 1 < this.hops!.max) {
|
|
146
|
-
|
|
142
|
+
if (this._matches.isCircular(id)) {
|
|
143
|
+
this._matches.pop();
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
await this.find(id, hop + 1);
|
|
147
147
|
}
|
|
148
148
|
this._matches.pop();
|
|
149
149
|
} else {
|
|
150
150
|
// Below minimum hops: traverse the edge without yielding a match
|
|
151
|
-
await this.find(
|
|
151
|
+
await this.find(id, hop + 1);
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
// Restore original source node
|
|
@@ -8,11 +8,8 @@ class RelationshipData extends Data {
|
|
|
8
8
|
super._buildIndex("left_id");
|
|
9
9
|
super._buildIndex("right_id");
|
|
10
10
|
}
|
|
11
|
-
public find(
|
|
12
|
-
return super._find(
|
|
13
|
-
}
|
|
14
|
-
public findReverse(right_id: string, hop: number = 0): boolean {
|
|
15
|
-
return super._find(right_id, hop, "right_id");
|
|
11
|
+
public find(id: string, hop: number = 0, direction: "left" | "right" = "right"): boolean {
|
|
12
|
+
return super._find(id, hop, direction === "left" ? "right_id" : "left_id");
|
|
16
13
|
}
|
|
17
14
|
/*
|
|
18
15
|
** Get the properties of the current relationship record
|
|
@@ -11,7 +11,7 @@ class RelationshipMatchCollector {
|
|
|
11
11
|
private _matches: RelationshipMatchRecord[] = [];
|
|
12
12
|
private _nodeIds: Array<string> = [];
|
|
13
13
|
|
|
14
|
-
public push(relationship: Relationship): RelationshipMatchRecord {
|
|
14
|
+
public push(relationship: Relationship, traversalId: string): RelationshipMatchRecord {
|
|
15
15
|
const match: RelationshipMatchRecord = {
|
|
16
16
|
type: relationship.type!,
|
|
17
17
|
startNode: relationship.source?.value() || {},
|
|
@@ -19,7 +19,7 @@ class RelationshipMatchCollector {
|
|
|
19
19
|
properties: relationship.getData()?.properties() as Record<string, any>,
|
|
20
20
|
};
|
|
21
21
|
this._matches.push(match);
|
|
22
|
-
this._nodeIds.push(
|
|
22
|
+
this._nodeIds.push(traversalId);
|
|
23
23
|
return match;
|
|
24
24
|
}
|
|
25
25
|
public set endNode(node: any) {
|
|
@@ -46,12 +46,11 @@ class RelationshipMatchCollector {
|
|
|
46
46
|
return this._matches;
|
|
47
47
|
}
|
|
48
48
|
/*
|
|
49
|
-
** Checks if the
|
|
50
|
-
**
|
|
49
|
+
** Checks if traversing to the given node id would form a cycle
|
|
50
|
+
** in the current traversal path
|
|
51
51
|
*/
|
|
52
|
-
public isCircular(): boolean {
|
|
53
|
-
|
|
54
|
-
return seen.size < this._nodeIds.length;
|
|
52
|
+
public isCircular(nextId: string): boolean {
|
|
53
|
+
return this._nodeIds.includes(nextId);
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
|
|
@@ -50,10 +50,10 @@ class GroupBy extends Projection {
|
|
|
50
50
|
}
|
|
51
51
|
private map() {
|
|
52
52
|
let node: Node = this.current;
|
|
53
|
-
for(const mapper of this.mappers) {
|
|
53
|
+
for (const mapper of this.mappers) {
|
|
54
54
|
const value: any = mapper.value();
|
|
55
55
|
let child: Node | undefined = node.children.get(value);
|
|
56
|
-
if(child === undefined) {
|
|
56
|
+
if (child === undefined) {
|
|
57
57
|
child = new Node(value);
|
|
58
58
|
node.children.set(value, child);
|
|
59
59
|
}
|
|
@@ -62,8 +62,8 @@ class GroupBy extends Projection {
|
|
|
62
62
|
this.current = node;
|
|
63
63
|
}
|
|
64
64
|
private reduce() {
|
|
65
|
-
if(this.current.elements === null) {
|
|
66
|
-
this.current.elements = this.reducers.map(reducer => reducer.element());
|
|
65
|
+
if (this.current.elements === null) {
|
|
66
|
+
this.current.elements = this.reducers.map((reducer) => reducer.element());
|
|
67
67
|
}
|
|
68
68
|
const elements: AggregationElement[] = this.current.elements;
|
|
69
69
|
this.reducers.forEach((reducer, index) => {
|
|
@@ -71,29 +71,37 @@ class GroupBy extends Projection {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
private get mappers(): Expression[] {
|
|
74
|
-
if(this._mappers === null) {
|
|
74
|
+
if (this._mappers === null) {
|
|
75
75
|
this._mappers = [...this._generate_mappers()];
|
|
76
76
|
}
|
|
77
77
|
return this._mappers;
|
|
78
78
|
}
|
|
79
79
|
private *_generate_mappers(): Generator<Expression> {
|
|
80
|
-
for(const [expression, _] of this.expressions()) {
|
|
81
|
-
if(expression.mappable()) {
|
|
80
|
+
for (const [expression, _] of this.expressions()) {
|
|
81
|
+
if (expression.mappable()) {
|
|
82
82
|
yield expression;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
private get reducers(): AggregateFunction[] {
|
|
87
|
-
if(this._reducers === null) {
|
|
88
|
-
this._reducers = this.children
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
if (this._reducers === null) {
|
|
88
|
+
this._reducers = this.children
|
|
89
|
+
.map((child) => {
|
|
90
|
+
return (child as Expression).reducers();
|
|
91
|
+
})
|
|
92
|
+
.flat();
|
|
91
93
|
}
|
|
92
94
|
return this._reducers;
|
|
93
95
|
}
|
|
94
|
-
public *generate_results(
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
public *generate_results(
|
|
97
|
+
mapperIndex: number = 0,
|
|
98
|
+
node: Node = this.root
|
|
99
|
+
): Generator<Record<string, any>> {
|
|
100
|
+
if (mapperIndex === 0 && node.children.size === 0 && this.mappers.length > 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (node.children.size > 0) {
|
|
104
|
+
for (const child of node.children.values()) {
|
|
97
105
|
this.mappers[mapperIndex].overridden = child.value;
|
|
98
106
|
yield* this.generate_results(mapperIndex + 1, child);
|
|
99
107
|
}
|
|
@@ -102,10 +110,10 @@ class GroupBy extends Projection {
|
|
|
102
110
|
this.reducers[reducerIndex].overridden = element.value;
|
|
103
111
|
});
|
|
104
112
|
const record: Record<string, any> = {};
|
|
105
|
-
for(const [expression, alias] of this.expressions()) {
|
|
113
|
+
for (const [expression, alias] of this.expressions()) {
|
|
106
114
|
record[alias] = expression.value();
|
|
107
115
|
}
|
|
108
|
-
if(this.where) {
|
|
116
|
+
if (this.where) {
|
|
109
117
|
yield record;
|
|
110
118
|
}
|
|
111
119
|
}
|
|
@@ -114,11 +122,11 @@ class GroupBy extends Projection {
|
|
|
114
122
|
this._where = where;
|
|
115
123
|
}
|
|
116
124
|
public get where(): boolean {
|
|
117
|
-
if(this._where === null) {
|
|
125
|
+
if (this._where === null) {
|
|
118
126
|
return true;
|
|
119
127
|
}
|
|
120
128
|
return this._where.value();
|
|
121
129
|
}
|
|
122
|
-
}
|
|
130
|
+
}
|
|
123
131
|
|
|
124
|
-
export default GroupBy;
|
|
132
|
+
export default GroupBy;
|
package/src/parsing/parser.ts
CHANGED
|
@@ -467,7 +467,10 @@ class Parser extends BaseParser {
|
|
|
467
467
|
reference = inner;
|
|
468
468
|
}
|
|
469
469
|
}
|
|
470
|
-
if (
|
|
470
|
+
if (
|
|
471
|
+
reference === undefined ||
|
|
472
|
+
(!(reference instanceof Node) && !(reference instanceof Unwind))
|
|
473
|
+
) {
|
|
471
474
|
throw new Error(`Undefined node reference: ${identifier}`);
|
|
472
475
|
}
|
|
473
476
|
node = new NodeReference(node, reference);
|
|
@@ -334,6 +334,20 @@ test("Test aggregated with and return", async () => {
|
|
|
334
334
|
expect(results[1]).toEqual({ i: 2, sum: 12 });
|
|
335
335
|
});
|
|
336
336
|
|
|
337
|
+
test("Test aggregated with on empty result set", async () => {
|
|
338
|
+
const runner = new Runner(
|
|
339
|
+
`
|
|
340
|
+
unwind [] as i
|
|
341
|
+
unwind [1, 2] as j
|
|
342
|
+
with i, count(j) as cnt
|
|
343
|
+
return i, cnt
|
|
344
|
+
`
|
|
345
|
+
);
|
|
346
|
+
await runner.run();
|
|
347
|
+
const results = runner.results;
|
|
348
|
+
expect(results.length).toBe(0);
|
|
349
|
+
});
|
|
350
|
+
|
|
337
351
|
test("Test aggregated with using collect and return", async () => {
|
|
338
352
|
const runner = new Runner(
|
|
339
353
|
`
|
|
@@ -1138,7 +1152,7 @@ test("Test circular graph pattern", async () => {
|
|
|
1138
1152
|
expect(results[0].pattern[4].id).toBe(1);
|
|
1139
1153
|
});
|
|
1140
1154
|
|
|
1141
|
-
test("Test circular graph pattern with variable length should
|
|
1155
|
+
test("Test circular graph pattern with variable length should not revisit nodes", async () => {
|
|
1142
1156
|
await new Runner(`
|
|
1143
1157
|
CREATE VIRTUAL (:Person) AS {
|
|
1144
1158
|
unwind [
|
|
@@ -1161,9 +1175,10 @@ test("Test circular graph pattern with variable length should throw error", asyn
|
|
|
1161
1175
|
MATCH p=(:Person)-[:KNOWS*]-(:Person)
|
|
1162
1176
|
RETURN p AS pattern
|
|
1163
1177
|
`);
|
|
1164
|
-
await
|
|
1165
|
-
|
|
1166
|
-
|
|
1178
|
+
await match.run();
|
|
1179
|
+
const results = match.results;
|
|
1180
|
+
// Circular graph 1↔2: cycles are skipped, only acyclic paths are returned
|
|
1181
|
+
expect(results.length).toBe(6);
|
|
1167
1182
|
});
|
|
1168
1183
|
|
|
1169
1184
|
test("Test multi-hop match with min hops constraint *1..", async () => {
|
|
@@ -2064,3 +2079,107 @@ test("Test WHERE with CONTAINS combined with AND", async () => {
|
|
|
2064
2079
|
expect(results.length).toBe(1);
|
|
2065
2080
|
expect(results[0].fruit).toBe("pineapple");
|
|
2066
2081
|
});
|
|
2082
|
+
|
|
2083
|
+
test("Test collected nodes and re-matching", async () => {
|
|
2084
|
+
await new Runner(`
|
|
2085
|
+
CREATE VIRTUAL (:Person) AS {
|
|
2086
|
+
unwind [
|
|
2087
|
+
{id: 1, name: 'Person 1'},
|
|
2088
|
+
{id: 2, name: 'Person 2'},
|
|
2089
|
+
{id: 3, name: 'Person 3'},
|
|
2090
|
+
{id: 4, name: 'Person 4'}
|
|
2091
|
+
] as record
|
|
2092
|
+
RETURN record.id as id, record.name as name
|
|
2093
|
+
}
|
|
2094
|
+
`).run();
|
|
2095
|
+
await new Runner(`
|
|
2096
|
+
CREATE VIRTUAL (:Person)-[:KNOWS]-(:Person) AS {
|
|
2097
|
+
unwind [
|
|
2098
|
+
{left_id: 1, right_id: 2},
|
|
2099
|
+
{left_id: 2, right_id: 3},
|
|
2100
|
+
{left_id: 3, right_id: 4}
|
|
2101
|
+
] as record
|
|
2102
|
+
RETURN record.left_id as left_id, record.right_id as right_id
|
|
2103
|
+
}
|
|
2104
|
+
`).run();
|
|
2105
|
+
const match = new Runner(`
|
|
2106
|
+
MATCH (a:Person)-[:KNOWS*0..3]->(b:Person)
|
|
2107
|
+
WITH collect(a) AS persons, b
|
|
2108
|
+
UNWIND persons AS p
|
|
2109
|
+
match (p)-[:KNOWS]->(:Person)
|
|
2110
|
+
return p.name AS name
|
|
2111
|
+
`);
|
|
2112
|
+
await match.run();
|
|
2113
|
+
const results = match.results;
|
|
2114
|
+
expect(results.length).toBe(9);
|
|
2115
|
+
const names = results.map((r: any) => r.name);
|
|
2116
|
+
expect(names).toContain("Person 1");
|
|
2117
|
+
expect(names).toContain("Person 2");
|
|
2118
|
+
expect(names).toContain("Person 3");
|
|
2119
|
+
});
|
|
2120
|
+
|
|
2121
|
+
test("Test collected patterns and unwind", async () => {
|
|
2122
|
+
await new Runner(`
|
|
2123
|
+
CREATE VIRTUAL (:Person) AS {
|
|
2124
|
+
unwind [
|
|
2125
|
+
{id: 1, name: 'Person 1'},
|
|
2126
|
+
{id: 2, name: 'Person 2'},
|
|
2127
|
+
{id: 3, name: 'Person 3'},
|
|
2128
|
+
{id: 4, name: 'Person 4'}
|
|
2129
|
+
] as record
|
|
2130
|
+
RETURN record.id as id, record.name as name
|
|
2131
|
+
}
|
|
2132
|
+
`).run();
|
|
2133
|
+
await new Runner(`
|
|
2134
|
+
CREATE VIRTUAL (:Person)-[:KNOWS]-(:Person) AS {
|
|
2135
|
+
unwind [
|
|
2136
|
+
{left_id: 1, right_id: 2},
|
|
2137
|
+
{left_id: 2, right_id: 3},
|
|
2138
|
+
{left_id: 3, right_id: 4}
|
|
2139
|
+
] as record
|
|
2140
|
+
RETURN record.left_id as left_id, record.right_id as right_id
|
|
2141
|
+
}
|
|
2142
|
+
`).run();
|
|
2143
|
+
const match = new Runner(`
|
|
2144
|
+
MATCH p=(a:Person)-[:KNOWS*0..3]->(b:Person)
|
|
2145
|
+
WITH collect(p) AS patterns
|
|
2146
|
+
UNWIND patterns AS pattern
|
|
2147
|
+
RETURN pattern
|
|
2148
|
+
`);
|
|
2149
|
+
await match.run();
|
|
2150
|
+
const results = match.results;
|
|
2151
|
+
expect(results.length).toBe(10);
|
|
2152
|
+
// Index 0: Person 1 zero-hop - pattern = [node1] (single node)
|
|
2153
|
+
expect(results[0].pattern.length).toBe(1);
|
|
2154
|
+
expect(results[0].pattern[0].id).toBe(1);
|
|
2155
|
+
|
|
2156
|
+
// Index 1: Person 1 -> Person 2 (1-hop)
|
|
2157
|
+
expect(results[1].pattern.length).toBe(3);
|
|
2158
|
+
|
|
2159
|
+
// Index 2: Person 1 -> Person 2 -> Person 3 (2-hop)
|
|
2160
|
+
expect(results[2].pattern.length).toBe(5);
|
|
2161
|
+
|
|
2162
|
+
// Index 3: Person 1 -> Person 2 -> Person 3 -> Person 4 (3-hop)
|
|
2163
|
+
expect(results[3].pattern.length).toBe(7);
|
|
2164
|
+
|
|
2165
|
+
// Index 4: Person 2 zero-hop - pattern = [node2]
|
|
2166
|
+
expect(results[4].pattern.length).toBe(1);
|
|
2167
|
+
expect(results[4].pattern[0].id).toBe(2);
|
|
2168
|
+
|
|
2169
|
+
// Index 5: Person 2 -> Person 3 (1-hop)
|
|
2170
|
+
expect(results[5].pattern.length).toBe(3);
|
|
2171
|
+
|
|
2172
|
+
// Index 6: Person 2 -> Person 3 -> Person 4 (2-hop)
|
|
2173
|
+
expect(results[6].pattern.length).toBe(5);
|
|
2174
|
+
|
|
2175
|
+
// Index 7: Person 3 zero-hop - pattern = [node3]
|
|
2176
|
+
expect(results[7].pattern.length).toBe(1);
|
|
2177
|
+
expect(results[7].pattern[0].id).toBe(3);
|
|
2178
|
+
|
|
2179
|
+
// Index 8: Person 3 -> Person 4 (1-hop)
|
|
2180
|
+
expect(results[8].pattern.length).toBe(3);
|
|
2181
|
+
|
|
2182
|
+
// Index 9: Person 4 zero-hop - pattern = [node4]
|
|
2183
|
+
expect(results[9].pattern.length).toBe(1);
|
|
2184
|
+
expect(results[9].pattern[0].id).toBe(4);
|
|
2185
|
+
});
|
|
@@ -839,7 +839,7 @@ test("Parse statement with graph pattern in where clause", () => {
|
|
|
839
839
|
const source = pattern.chain[0] as NodeReference;
|
|
840
840
|
const relationship = pattern.chain[1] as Relationship;
|
|
841
841
|
const target = pattern.chain[2] as Node;
|
|
842
|
-
expect(source.reference?.identifier).toBe("a");
|
|
842
|
+
expect((source.reference as Node)?.identifier).toBe("a");
|
|
843
843
|
expect(relationship.type).toBe("KNOWS");
|
|
844
844
|
expect(target.label).toBe("Person");
|
|
845
845
|
});
|
|
@@ -909,7 +909,7 @@ test("Test node reference with label creates NodeReference instead of new node",
|
|
|
909
909
|
expect(firstNode.identifier).toBe("n");
|
|
910
910
|
expect(firstNode.label).toBe("Person");
|
|
911
911
|
expect(secondNode).toBeInstanceOf(NodeReference);
|
|
912
|
-
expect(secondNode.reference
|
|
912
|
+
expect((secondNode.reference! as Node).identifier).toBe("n");
|
|
913
913
|
expect(secondNode.label).toBe("Person");
|
|
914
914
|
});
|
|
915
915
|
|