flowquery 1.0.26 → 1.0.27
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/parsing/expressions/reference.d.ts +1 -0
- package/dist/parsing/expressions/reference.d.ts.map +1 -1
- package/dist/parsing/expressions/reference.js +3 -0
- package/dist/parsing/expressions/reference.js.map +1 -1
- package/dist/parsing/parser.d.ts.map +1 -1
- package/dist/parsing/parser.js +18 -4
- 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/parsing/parser.py +13 -0
- package/flowquery-py/tests/compute/test_runner.py +41 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/parsing/expressions/reference.ts +8 -5
- package/src/parsing/parser.ts +18 -4
- package/tests/compute/runner.test.ts +46 -0
package/package.json
CHANGED
|
@@ -3,9 +3,9 @@ import Identifier from "./identifier";
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Represents a reference to a previously defined variable or expression.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* References point to values defined earlier in the query (e.g., in WITH or LOAD statements).
|
|
8
|
-
*
|
|
8
|
+
*
|
|
9
9
|
* @example
|
|
10
10
|
* ```typescript
|
|
11
11
|
* const ref = new Reference("myVar", previousNode);
|
|
@@ -14,10 +14,10 @@ import Identifier from "./identifier";
|
|
|
14
14
|
*/
|
|
15
15
|
class Reference extends Identifier {
|
|
16
16
|
private _referred: ASTNode | undefined = undefined;
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
/**
|
|
19
19
|
* Creates a new Reference to a variable.
|
|
20
|
-
*
|
|
20
|
+
*
|
|
21
21
|
* @param value - The identifier name
|
|
22
22
|
* @param referred - The node this reference points to (optional)
|
|
23
23
|
*/
|
|
@@ -25,6 +25,9 @@ class Reference extends Identifier {
|
|
|
25
25
|
super(value);
|
|
26
26
|
this._referred = referred;
|
|
27
27
|
}
|
|
28
|
+
public get referred(): ASTNode | undefined {
|
|
29
|
+
return this._referred;
|
|
30
|
+
}
|
|
28
31
|
public set referred(node: ASTNode) {
|
|
29
32
|
this._referred = node;
|
|
30
33
|
}
|
|
@@ -39,4 +42,4 @@ class Reference extends Identifier {
|
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
export default Reference;
|
|
45
|
+
export default Reference;
|
package/src/parsing/parser.ts
CHANGED
|
@@ -438,8 +438,15 @@ class Parser extends BaseParser {
|
|
|
438
438
|
node.identifier = identifier;
|
|
439
439
|
this.variables.set(identifier, node);
|
|
440
440
|
} else if (identifier !== null) {
|
|
441
|
-
|
|
442
|
-
|
|
441
|
+
let reference = this.variables.get(identifier);
|
|
442
|
+
// Resolve through Expression -> Reference -> Node (e.g., after WITH)
|
|
443
|
+
if (reference instanceof Expression && reference.firstChild() instanceof Reference) {
|
|
444
|
+
const inner = (reference.firstChild() as Reference).referred;
|
|
445
|
+
if (inner instanceof Node) {
|
|
446
|
+
reference = inner;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (reference === undefined || !(reference instanceof Node)) {
|
|
443
450
|
throw new Error(`Undefined node reference: ${identifier}`);
|
|
444
451
|
}
|
|
445
452
|
node = new NodeReference(node, reference);
|
|
@@ -629,8 +636,15 @@ class Parser extends BaseParser {
|
|
|
629
636
|
relationship.identifier = variable;
|
|
630
637
|
this.variables.set(variable, relationship);
|
|
631
638
|
} else if (variable !== null) {
|
|
632
|
-
|
|
633
|
-
|
|
639
|
+
let reference = this.variables.get(variable);
|
|
640
|
+
// Resolve through Expression -> Reference -> Relationship (e.g., after WITH)
|
|
641
|
+
if (reference instanceof Expression && reference.firstChild() instanceof Reference) {
|
|
642
|
+
const inner = (reference.firstChild() as Reference).referred;
|
|
643
|
+
if (inner instanceof Relationship) {
|
|
644
|
+
reference = inner;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (reference === undefined || !(reference instanceof Relationship)) {
|
|
634
648
|
throw new Error(`Undefined relationship reference: ${variable}`);
|
|
635
649
|
}
|
|
636
650
|
relationship = new RelationshipReference(relationship, reference);
|
|
@@ -1556,3 +1556,49 @@ test("Test reserved keywords as relationship types and labels", async () => {
|
|
|
1556
1556
|
expect(results.length).toBe(1);
|
|
1557
1557
|
expect(results[0]).toEqual({ name1: "Node 1", name2: "Node 2" });
|
|
1558
1558
|
});
|
|
1559
|
+
|
|
1560
|
+
test("Test match with node reference passed through WITH", async () => {
|
|
1561
|
+
await new Runner(`
|
|
1562
|
+
CREATE VIRTUAL (:User) AS {
|
|
1563
|
+
UNWIND [
|
|
1564
|
+
{id: 1, name: 'Alice', mail: 'alice@test.com', jobTitle: 'CEO'},
|
|
1565
|
+
{id: 2, name: 'Bob', mail: 'bob@test.com', jobTitle: 'VP'},
|
|
1566
|
+
{id: 3, name: 'Carol', mail: 'carol@test.com', jobTitle: 'VP'},
|
|
1567
|
+
{id: 4, name: 'Dave', mail: 'dave@test.com', jobTitle: 'Engineer'}
|
|
1568
|
+
] AS record
|
|
1569
|
+
RETURN record.id AS id, record.name AS name, record.mail AS mail, record.jobTitle AS jobTitle
|
|
1570
|
+
}
|
|
1571
|
+
`).run();
|
|
1572
|
+
await new Runner(`
|
|
1573
|
+
CREATE VIRTUAL (:User)-[:MANAGES]-(:User) AS {
|
|
1574
|
+
UNWIND [
|
|
1575
|
+
{left_id: 1, right_id: 2},
|
|
1576
|
+
{left_id: 1, right_id: 3},
|
|
1577
|
+
{left_id: 2, right_id: 4}
|
|
1578
|
+
] AS record
|
|
1579
|
+
RETURN record.left_id AS left_id, record.right_id AS right_id
|
|
1580
|
+
}
|
|
1581
|
+
`).run();
|
|
1582
|
+
// Equivalent to:
|
|
1583
|
+
// MATCH (ceo:User)-[:MANAGES]->(dr1:User)
|
|
1584
|
+
// WHERE ceo.jobTitle = 'CEO'
|
|
1585
|
+
// WITH ceo, dr1
|
|
1586
|
+
// MATCH (ceo)-[:MANAGES]->(dr2:User)
|
|
1587
|
+
// WHERE dr1.mail <> dr2.mail
|
|
1588
|
+
// RETURN ceo, dr1, dr2
|
|
1589
|
+
const match = new Runner(`
|
|
1590
|
+
MATCH (ceo:User)-[:MANAGES]->(dr1:User)
|
|
1591
|
+
WHERE ceo.jobTitle = 'CEO'
|
|
1592
|
+
WITH ceo, dr1
|
|
1593
|
+
MATCH (ceo)-[:MANAGES]->(dr2:User)
|
|
1594
|
+
WHERE dr1.mail <> dr2.mail
|
|
1595
|
+
RETURN ceo.name AS ceo, dr1.name AS dr1, dr2.name AS dr2
|
|
1596
|
+
`);
|
|
1597
|
+
await match.run();
|
|
1598
|
+
const results = match.results;
|
|
1599
|
+
// CEO (Alice) manages Bob and Carol. All distinct pairs:
|
|
1600
|
+
// (Alice, Bob, Carol) and (Alice, Carol, Bob)
|
|
1601
|
+
expect(results.length).toBe(2);
|
|
1602
|
+
expect(results[0]).toEqual({ ceo: "Alice", dr1: "Bob", dr2: "Carol" });
|
|
1603
|
+
expect(results[1]).toEqual({ ceo: "Alice", dr1: "Carol", dr2: "Bob" });
|
|
1604
|
+
});
|