From ad1f159cc7a772647170f43ff880cae8dae34055 Mon Sep 17 00:00:00 2001 From: Marijn van Wezel Date: Fri, 6 Feb 2026 19:16:03 +0100 Subject: [PATCH 1/3] Add support for shortestPath and allShortestPaths constructs --- CHANGELOG.md | 1 + src/Patterns/AllShortestPaths.php | 52 ++++++++++++++++++++ src/Patterns/ShortestPath.php | 52 ++++++++++++++++++++ src/Query.php | 28 +++++++++++ src/functions.php | 27 ++++++++++ tests/unit/FunctionsTest.php | 20 ++++++++ tests/unit/Patterns/AllShortestPathsTest.php | 45 +++++++++++++++++ tests/unit/Patterns/ShortestPathTest.php | 45 +++++++++++++++++ 8 files changed, 270 insertions(+) create mode 100644 src/Patterns/AllShortestPaths.php create mode 100644 src/Patterns/ShortestPath.php create mode 100644 tests/unit/Patterns/AllShortestPathsTest.php create mode 100644 tests/unit/Patterns/ShortestPathTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a7a73e..a83cf3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog], and this project adheres to ### Added - Added support for operator chaining (e.g. `a > b > c`). +- Added support for `shortestPath` and `allShortestPaths` pattern constructs. ### Changed diff --git a/src/Patterns/AllShortestPaths.php b/src/Patterns/AllShortestPaths.php new file mode 100644 index 0000000..36c85fe --- /dev/null +++ b/src/Patterns/AllShortestPaths.php @@ -0,0 +1,52 @@ +pattern = $pattern; + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("allShortestPaths(%s)", $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Patterns/ShortestPath.php b/src/Patterns/ShortestPath.php new file mode 100644 index 0000000..6aed9c2 --- /dev/null +++ b/src/Patterns/ShortestPath.php @@ -0,0 +1,52 @@ +pattern = $pattern; + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("shortestPath(%s)", $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Query.php b/src/Query.php index 03f11a3..9a97967 100644 --- a/src/Query.php +++ b/src/Query.php @@ -43,11 +43,13 @@ use WikibaseSolutions\CypherDSL\Expressions\Property; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; use WikibaseSolutions\CypherDSL\Patterns\CompletePattern; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Pattern; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; use WikibaseSolutions\CypherDSL\Syntax\Alias; use WikibaseSolutions\CypherDSL\Syntax\PropertyReplacement; use WikibaseSolutions\CypherDSL\Types\AnyType; @@ -138,6 +140,32 @@ public static function relationshipFrom(): Relationship return new Relationship(Direction::LEFT); } + + + /** + * Creates a shortestPath pattern. + * + * @param CompletePattern $pattern The pattern to find the shortest path for + * + * @see https://neo4j.com/docs/cypher-manual/current/clauses/shortestpath/ Corresponding documentation on Neo4j.com + */ + public static function shortestPath(CompletePattern $pattern): ShortestPath + { + return new ShortestPath($pattern); + } + + /** + * Creates an allShortestPaths pattern. + * + * @param CompletePattern $pattern The pattern to find all shortest paths for + * + * @see https://neo4j.com/docs/cypher-manual/current/clauses/allshortestpaths/ Corresponding documentation on Neo4j.com + */ + public static function allShortestPaths(CompletePattern $pattern): AllShortestPaths + { + return new AllShortestPaths($pattern); + } + /** * Creates a new variable with the given name, or generates a new variable with a random unique name. * diff --git a/src/functions.php b/src/functions.php index 2b99586..a57dbb6 100644 --- a/src/functions.php +++ b/src/functions.php @@ -21,9 +21,12 @@ use WikibaseSolutions\CypherDSL\Expressions\Procedures\Procedure; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\CompletePattern; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; /** * Creates a new Cypher query. @@ -99,6 +102,30 @@ function relationshipFrom(): Relationship return Query::relationshipFrom(); } +/** + * Creates a shortestPath pattern. + * + * @param CompletePattern $pattern The pattern to find the shortest path for + * + * @see Query::shortestPath() + */ +function shortestPath(CompletePattern $pattern): ShortestPath +{ + return Query::shortestPath($pattern); +} + +/** + * Creates an allShortestPaths pattern. + * + * @param CompletePattern $pattern The pattern to find all shortest paths for + * + * @see Query::allShortestPaths() + */ +function allShortestPaths(CompletePattern $pattern): AllShortestPaths +{ + return Query::allShortestPaths($pattern); +} + /** * Creates a new variable with the given name, or generates a new variable with a random unique name. * diff --git a/tests/unit/FunctionsTest.php b/tests/unit/FunctionsTest.php index d0ea56f..4e76495 100644 --- a/tests/unit/FunctionsTest.php +++ b/tests/unit/FunctionsTest.php @@ -22,6 +22,7 @@ use WikibaseSolutions\CypherDSL\Expressions\Procedures\Procedure; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use function WikibaseSolutions\CypherDSL\allShortestPaths; use function WikibaseSolutions\CypherDSL\float; use function WikibaseSolutions\CypherDSL\function_; use function WikibaseSolutions\CypherDSL\integer; @@ -36,6 +37,7 @@ use function WikibaseSolutions\CypherDSL\query; use function WikibaseSolutions\CypherDSL\raw; use function WikibaseSolutions\CypherDSL\relationship; +use function WikibaseSolutions\CypherDSL\shortestPath; use function WikibaseSolutions\CypherDSL\string; use function WikibaseSolutions\CypherDSL\variable; @@ -247,4 +249,22 @@ public function testRawOnlyAcceptsString(): void // @phpstan-ignore-next-line raw([]); } + + public function testShortestPath(): void + { + $path = node()->relationshipTo(node()); + $shortestPath = shortestPath($path); + + $this->assertInstanceOf(\WikibaseSolutions\CypherDSL\Patterns\ShortestPath::class, $shortestPath); + $this->assertSame('shortestPath(()-->())', $shortestPath->toQuery()); + } + + public function testAllShortestPaths(): void + { + $path = node()->relationshipTo(node()); + $allShortestPaths = allShortestPaths($path); + + $this->assertInstanceOf(\WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths::class, $allShortestPaths); + $this->assertSame('allShortestPaths(()-->())', $allShortestPaths->toQuery()); + } } diff --git a/tests/unit/Patterns/AllShortestPathsTest.php b/tests/unit/Patterns/AllShortestPathsTest.php new file mode 100644 index 0000000..8022771 --- /dev/null +++ b/tests/unit/Patterns/AllShortestPathsTest.php @@ -0,0 +1,45 @@ +relationshipTo(Query::node()); + $allShortestPaths = new AllShortestPaths($path); + + $this->assertEquals('allShortestPaths(()-->())', $allShortestPaths->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $allShortestPaths = new AllShortestPaths($path); + $allShortestPaths->withVariable('p'); + + $this->assertEquals('p = allShortestPaths(()-->())', $allShortestPaths->toQuery()); + } + + public function testToQueryWithInnerVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $path->withVariable('q'); + $allShortestPaths = new AllShortestPaths($path); + + $this->assertEquals('allShortestPaths(q = ()-->())', $allShortestPaths->toQuery()); + } +} diff --git a/tests/unit/Patterns/ShortestPathTest.php b/tests/unit/Patterns/ShortestPathTest.php new file mode 100644 index 0000000..4596be1 --- /dev/null +++ b/tests/unit/Patterns/ShortestPathTest.php @@ -0,0 +1,45 @@ +relationshipTo(Query::node()); + $shortestPath = new ShortestPath($path); + + $this->assertEquals('shortestPath(()-->())', $shortestPath->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestPath = new ShortestPath($path); + $shortestPath->withVariable('p'); + + $this->assertEquals('p = shortestPath(()-->())', $shortestPath->toQuery()); + } + + public function testToQueryWithInnerVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $path->withVariable('q'); + $shortestPath = new ShortestPath($path); + + $this->assertEquals('shortestPath(q = ()-->())', $shortestPath->toQuery()); + } +} From 0c624166cbac6fd2ab0be95fd227812fba2891ce Mon Sep 17 00:00:00 2001 From: Marijn van Wezel Date: Fri, 6 Feb 2026 19:52:53 +0100 Subject: [PATCH 2/3] Add support for shortest paths using new syntax --- CHANGELOG.md | 1 + src/Patterns/AllShortest.php | 52 ++++++++++++++ src/Patterns/AnyPath.php | 52 ++++++++++++++ src/Patterns/Shortest.php | 62 +++++++++++++++++ src/Patterns/ShortestGroups.php | 62 +++++++++++++++++ src/Query.php | 54 +++++++++++++++ src/functions.php | 55 +++++++++++++++ tests/unit/FunctionsTest.php | 68 +++++++++++++++++- tests/unit/Patterns/AllShortestTest.php | 36 ++++++++++ tests/unit/Patterns/AnyPathTest.php | 36 ++++++++++ tests/unit/Patterns/ShortestGroupsTest.php | 45 ++++++++++++ tests/unit/Patterns/ShortestTest.php | 53 ++++++++++++++ tests/unit/QueryTest.php | 80 +++++++++++++++++++++- 13 files changed, 653 insertions(+), 3 deletions(-) create mode 100644 src/Patterns/AllShortest.php create mode 100644 src/Patterns/AnyPath.php create mode 100644 src/Patterns/Shortest.php create mode 100644 src/Patterns/ShortestGroups.php create mode 100644 tests/unit/Patterns/AllShortestTest.php create mode 100644 tests/unit/Patterns/AnyPathTest.php create mode 100644 tests/unit/Patterns/ShortestGroupsTest.php create mode 100644 tests/unit/Patterns/ShortestTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a83cf3d..6585898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog], and this project adheres to - Added support for operator chaining (e.g. `a > b > c`). - Added support for `shortestPath` and `allShortestPaths` pattern constructs. +- Added support for shortest path constructs (`SHORTEST k`, `ALL SHORTEST`, `SHORTEST k GROUPS`, and `ANY`). ### Changed diff --git a/src/Patterns/AllShortest.php b/src/Patterns/AllShortest.php new file mode 100644 index 0000000..3bba2ca --- /dev/null +++ b/src/Patterns/AllShortest.php @@ -0,0 +1,52 @@ +pattern = $pattern; + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("ALL SHORTEST (%s)", $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Patterns/AnyPath.php b/src/Patterns/AnyPath.php new file mode 100644 index 0000000..6f8b18f --- /dev/null +++ b/src/Patterns/AnyPath.php @@ -0,0 +1,52 @@ +pattern = $pattern; + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("ANY (%s)", $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Patterns/Shortest.php b/src/Patterns/Shortest.php new file mode 100644 index 0000000..530272d --- /dev/null +++ b/src/Patterns/Shortest.php @@ -0,0 +1,62 @@ +pattern = $pattern; + $this->k = CastUtils::toIntegerType($k); + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("SHORTEST %s (%s)", $this->k->toQuery(), $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Patterns/ShortestGroups.php b/src/Patterns/ShortestGroups.php new file mode 100644 index 0000000..a3499df --- /dev/null +++ b/src/Patterns/ShortestGroups.php @@ -0,0 +1,62 @@ +pattern = $pattern; + $this->k = CastUtils::toIntegerType($k); + } + + /** + * @inheritDoc + */ + public function toQuery(): string + { + $cql = ''; + + if (isset($this->variable)) { + $cql = $this->variable->toQuery() . ' = '; + } + + $cql .= sprintf("SHORTEST %s GROUPS (%s)", $this->k->toQuery(), $this->pattern->toQuery()); + + return $cql; + } +} diff --git a/src/Query.php b/src/Query.php index 9a97967..1123975 100644 --- a/src/Query.php +++ b/src/Query.php @@ -43,12 +43,16 @@ use WikibaseSolutions\CypherDSL\Expressions\Property; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortest; use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\AnyPath; use WikibaseSolutions\CypherDSL\Patterns\CompletePattern; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Pattern; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\Shortest; +use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; use WikibaseSolutions\CypherDSL\Syntax\Alias; use WikibaseSolutions\CypherDSL\Syntax\PropertyReplacement; @@ -166,6 +170,56 @@ public static function allShortestPaths(CompletePattern $pattern): AllShortestPa return new AllShortestPaths($pattern); } + /** + * Creates a SHORTEST k construct. + * + * @param CompletePattern $pattern The pattern to find the shortest path for + * @param int|IntegerType $k The number of paths to match + * + * @see https://neo4j.com/docs/cypher-manual/current/patterns/shortest-paths/ Corresponding documentation on Neo4j.com + */ + public static function shortest(CompletePattern $pattern, int|IntegerType $k = 1): Shortest + { + return new Shortest($pattern, $k); + } + + /** + * Creates an ALL SHORTEST construct. + * + * @param CompletePattern $pattern The pattern to find all shortest paths for + * + * @see https://neo4j.com/docs/cypher-manual/current/patterns/shortest-paths/ Corresponding documentation on Neo4j.com + */ + public static function allShortest(CompletePattern $pattern): AllShortest + { + return new AllShortest($pattern); + } + + /** + * Creates a SHORTEST k GROUPS construct. + * + * @param CompletePattern $pattern The pattern to find the shortest groups for + * @param int|IntegerType $k The number of groups to match + * + * @see https://neo4j.com/docs/cypher-manual/current/patterns/shortest-paths/ Corresponding documentation on Neo4j.com + */ + public static function shortestGroups(CompletePattern $pattern, int|IntegerType $k): ShortestGroups + { + return new ShortestGroups($pattern, $k); + } + + /** + * Creates an ANY construct. + * + * @param CompletePattern $pattern The pattern to find any path for + * + * @see https://neo4j.com/docs/cypher-manual/current/patterns/shortest-paths/ Corresponding documentation on Neo4j.com + */ + public static function anyPath(CompletePattern $pattern): AnyPath + { + return new AnyPath($pattern); + } + /** * Creates a new variable with the given name, or generates a new variable with a random unique name. * diff --git a/src/functions.php b/src/functions.php index a57dbb6..bd01182 100644 --- a/src/functions.php +++ b/src/functions.php @@ -21,12 +21,17 @@ use WikibaseSolutions\CypherDSL\Expressions\Procedures\Procedure; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortest; use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\AnyPath; use WikibaseSolutions\CypherDSL\Patterns\CompletePattern; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\Shortest; +use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; +use WikibaseSolutions\CypherDSL\Types\PropertyTypes\IntegerType; /** * Creates a new Cypher query. @@ -126,6 +131,56 @@ function allShortestPaths(CompletePattern $pattern): AllShortestPaths return Query::allShortestPaths($pattern); } +/** + * Creates the SHORTEST k construct. + * + * @param CompletePattern $pattern The pattern to find the shortest path for + * @param int|IntegerType $k The number of paths to match + * + * @see Query::shortest() + */ +function shortest(CompletePattern $pattern, int|IntegerType $k = 1): Shortest +{ + return Query::shortest($pattern, $k); +} + +/** + * Creates the ALL SHORTEST construct. + * + * @param CompletePattern $pattern The pattern to find all shortest paths for + * + * @see Query::allShortest() + */ +function allShortest(CompletePattern $pattern): AllShortest +{ + return Query::allShortest($pattern); +} + +/** + * Creates the SHORTEST k GROUPS construct. + * + * @param CompletePattern $pattern The pattern to find the shortest groups for + * @param int|IntegerType $k The number of groups to match + * + * @see Query::shortestGroups() + */ +function shortestGroups(CompletePattern $pattern, int|IntegerType $k): ShortestGroups +{ + return Query::shortestGroups($pattern, $k); +} + +/** + * Creates the ANY construct. + * + * @param CompletePattern $pattern The pattern to find any path for + * + * @see Query::anyPath() + */ +function anyPath(CompletePattern $pattern): AnyPath +{ + return Query::anyPath($pattern); +} + /** * Creates a new variable with the given name, or generates a new variable with a random unique name. * diff --git a/tests/unit/FunctionsTest.php b/tests/unit/FunctionsTest.php index 4e76495..fd2b517 100644 --- a/tests/unit/FunctionsTest.php +++ b/tests/unit/FunctionsTest.php @@ -22,7 +22,15 @@ use WikibaseSolutions\CypherDSL\Expressions\Procedures\Procedure; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortest; +use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\AnyPath; +use WikibaseSolutions\CypherDSL\Patterns\Shortest; +use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; +use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; +use function WikibaseSolutions\CypherDSL\allShortest; use function WikibaseSolutions\CypherDSL\allShortestPaths; +use function WikibaseSolutions\CypherDSL\anyPath; use function WikibaseSolutions\CypherDSL\float; use function WikibaseSolutions\CypherDSL\function_; use function WikibaseSolutions\CypherDSL\integer; @@ -37,6 +45,8 @@ use function WikibaseSolutions\CypherDSL\query; use function WikibaseSolutions\CypherDSL\raw; use function WikibaseSolutions\CypherDSL\relationship; +use function WikibaseSolutions\CypherDSL\shortest; +use function WikibaseSolutions\CypherDSL\shortestGroups; use function WikibaseSolutions\CypherDSL\shortestPath; use function WikibaseSolutions\CypherDSL\string; use function WikibaseSolutions\CypherDSL\variable; @@ -255,7 +265,7 @@ public function testShortestPath(): void $path = node()->relationshipTo(node()); $shortestPath = shortestPath($path); - $this->assertInstanceOf(\WikibaseSolutions\CypherDSL\Patterns\ShortestPath::class, $shortestPath); + $this->assertInstanceOf(ShortestPath::class, $shortestPath); $this->assertSame('shortestPath(()-->())', $shortestPath->toQuery()); } @@ -264,7 +274,61 @@ public function testAllShortestPaths(): void $path = node()->relationshipTo(node()); $allShortestPaths = allShortestPaths($path); - $this->assertInstanceOf(\WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths::class, $allShortestPaths); + $this->assertInstanceOf(AllShortestPaths::class, $allShortestPaths); $this->assertSame('allShortestPaths(()-->())', $allShortestPaths->toQuery()); } + + public function testShortest(): void + { + $path = node()->relationshipTo(node()); + $shortest = shortest($path, 2); + + $this->assertInstanceOf(Shortest::class, $shortest); + $this->assertSame('SHORTEST 2 (()-->())', $shortest->toQuery()); + } + + public function testShortestIntegerType(): void + { + $path = node()->relationshipTo(node()); + $shortest = shortest($path, new Integer(2)); + + $this->assertInstanceOf(Shortest::class, $shortest); + $this->assertSame('SHORTEST 2 (()-->())', $shortest->toQuery()); + } + + public function testAllShortest(): void + { + $path = node()->relationshipTo(node()); + $allShortest = allShortest($path); + + $this->assertInstanceOf(AllShortest::class, $allShortest); + $this->assertSame('ALL SHORTEST (()-->())', $allShortest->toQuery()); + } + + public function testShortestGroups(): void + { + $path = node()->relationshipTo(node()); + $shortestGroups = shortestGroups($path, 3); + + $this->assertInstanceOf(ShortestGroups::class, $shortestGroups); + $this->assertSame('SHORTEST 3 GROUPS (()-->())', $shortestGroups->toQuery()); + } + + public function testShortestGroupsIntegerType(): void + { + $path = node()->relationshipTo(node()); + $shortestGroups = shortestGroups($path, new Integer(3)); + + $this->assertInstanceOf(ShortestGroups::class, $shortestGroups); + $this->assertSame('SHORTEST 3 GROUPS (()-->())', $shortestGroups->toQuery()); + } + + public function testAnyPath(): void + { + $path = node()->relationshipTo(node()); + $anyPath = anyPath($path); + + $this->assertInstanceOf(AnyPath::class, $anyPath); + $this->assertSame('ANY (()-->())', $anyPath->toQuery()); + } } diff --git a/tests/unit/Patterns/AllShortestTest.php b/tests/unit/Patterns/AllShortestTest.php new file mode 100644 index 0000000..733b1df --- /dev/null +++ b/tests/unit/Patterns/AllShortestTest.php @@ -0,0 +1,36 @@ +relationshipTo(Query::node()); + $allShortest = new AllShortest($path); + + $this->assertEquals('ALL SHORTEST (()-->())', $allShortest->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $allShortest = new AllShortest($path); + $allShortest->withVariable('p'); + + $this->assertEquals('p = ALL SHORTEST (()-->())', $allShortest->toQuery()); + } +} diff --git a/tests/unit/Patterns/AnyPathTest.php b/tests/unit/Patterns/AnyPathTest.php new file mode 100644 index 0000000..486db39 --- /dev/null +++ b/tests/unit/Patterns/AnyPathTest.php @@ -0,0 +1,36 @@ +relationshipTo(Query::node()); + $anyPath = new AnyPath($path); + + $this->assertEquals('ANY (()-->())', $anyPath->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $anyPath = new AnyPath($path); + $anyPath->withVariable('p'); + + $this->assertEquals('p = ANY (()-->())', $anyPath->toQuery()); + } +} diff --git a/tests/unit/Patterns/ShortestGroupsTest.php b/tests/unit/Patterns/ShortestGroupsTest.php new file mode 100644 index 0000000..f45c315 --- /dev/null +++ b/tests/unit/Patterns/ShortestGroupsTest.php @@ -0,0 +1,45 @@ +relationshipTo(Query::node()); + $shortestGroups = new ShortestGroups($path, 2); + + $this->assertEquals('SHORTEST 2 GROUPS (()-->())', $shortestGroups->toQuery()); + } + + public function testToQueryWithIntegerClass(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestGroups = new ShortestGroups($path, Query::integer(5)); + + $this->assertEquals('SHORTEST 5 GROUPS (()-->())', $shortestGroups->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestGroups = new ShortestGroups($path, 10); + $shortestGroups->withVariable('p'); + + $this->assertEquals('p = SHORTEST 10 GROUPS (()-->())', $shortestGroups->toQuery()); + } +} diff --git a/tests/unit/Patterns/ShortestTest.php b/tests/unit/Patterns/ShortestTest.php new file mode 100644 index 0000000..cb72071 --- /dev/null +++ b/tests/unit/Patterns/ShortestTest.php @@ -0,0 +1,53 @@ +relationshipTo(Query::node()); + $shortest = new Shortest($path, 1); + + $this->assertEquals('SHORTEST 1 (()-->())', $shortest->toQuery()); + } + + public function testToQueryWithVariable(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortest = new Shortest($path, 5); + $shortest->withVariable('p'); + + $this->assertEquals('p = SHORTEST 5 (()-->())', $shortest->toQuery()); + } + + public function testToQueryWithParameter(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortest = new Shortest($path, Query::parameter('k')); + + $this->assertEquals('SHORTEST $k (()-->())', $shortest->toQuery()); + } + + public function testToQueryWithIntegerClass(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortest = new Shortest($path, Query::integer(10)); + + $this->assertEquals('SHORTEST 10 (()-->())', $shortest->toQuery()); + } +} diff --git a/tests/unit/QueryTest.php b/tests/unit/QueryTest.php index 785b9fb..7ae64e8 100644 --- a/tests/unit/QueryTest.php +++ b/tests/unit/QueryTest.php @@ -16,6 +16,7 @@ use WikibaseSolutions\CypherDSL\Clauses\RawClause; use WikibaseSolutions\CypherDSL\Clauses\WhereClause; use WikibaseSolutions\CypherDSL\Clauses\WithClause; +use WikibaseSolutions\CypherDSL\Expressions\Exists; use WikibaseSolutions\CypherDSL\Expressions\Label; use WikibaseSolutions\CypherDSL\Expressions\Literals\Boolean; use WikibaseSolutions\CypherDSL\Expressions\Literals\Float_; @@ -30,16 +31,22 @@ use WikibaseSolutions\CypherDSL\Expressions\Property; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; +use WikibaseSolutions\CypherDSL\Patterns\AllShortest; +use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\AnyPath; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Path; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\Shortest; +use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; +use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; use WikibaseSolutions\CypherDSL\Query; use WikibaseSolutions\CypherDSL\Types\AnyType; use WikibaseSolutions\CypherDSL\Types\PropertyTypes\PropertyType; /** - * This class only tests methods of the query class that do not add a neq clause. Use a separate class for testing + * This class only tests methods of the query class that do not add a new clause. Use a separate class for testing * functions that add new clauses to the query. * * @covers \WikibaseSolutions\CypherDSL\Query @@ -196,6 +203,77 @@ public function testToString(): void $this->assertSame('SKIP 10', (string) $query); } + public function testShortestPath(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestPath = Query::shortestPath($path); + + $this->assertInstanceOf(ShortestPath::class, $shortestPath); + } + + public function testAllShortestPaths(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $allShortestPaths = Query::allShortestPaths($path); + + $this->assertInstanceOf(AllShortestPaths::class, $allShortestPaths); + } + + public function testShortest(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortest = Query::shortest($path, 2); + + $this->assertInstanceOf(Shortest::class, $shortest); + } + + public function testShortestWithIntegerClass(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortest = Query::shortest($path, Query::integer(2)); + + $this->assertInstanceOf(Shortest::class, $shortest); + } + + public function testAllShortest(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $allShortest = Query::allShortest($path); + + $this->assertInstanceOf(AllShortest::class, $allShortest); + } + + public function testShortestGroups(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestGroups = Query::shortestGroups($path, 3); + + $this->assertInstanceOf(ShortestGroups::class, $shortestGroups); + } + + public function testShortestGroupsWithIntegerClass(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $shortestGroups = Query::shortestGroups($path, Query::integer(3)); + + $this->assertInstanceOf(ShortestGroups::class, $shortestGroups); + } + + public function testAnyPath(): void + { + $path = Query::node()->relationshipTo(Query::node()); + $anyPath = Query::anyPath($path); + + $this->assertInstanceOf(AnyPath::class, $anyPath); + } + + public function testExists(): void + { + $exists = Query::exists(Query::node()); + + $this->assertInstanceOf(Exists::class, $exists); + } + public function testListOfLiterals(): void { $list = Query::list(["hello", "world", 1.0, 1, 2, 3, true]); From 1d666890795c9fc1b5502dd0c2c78a3376f7f6f1 Mon Sep 17 00:00:00 2001 From: Marijn van Wezel Date: Fri, 6 Feb 2026 19:53:53 +0100 Subject: [PATCH 3/3] Linting --- src/Patterns/Shortest.php | 1 - src/Patterns/ShortestGroups.php | 1 - src/Query.php | 2 -- tests/unit/FunctionsTest.php | 18 +++++++++--------- tests/unit/Patterns/ShortestGroupsTest.php | 1 - tests/unit/Patterns/ShortestTest.php | 1 - 6 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Patterns/Shortest.php b/src/Patterns/Shortest.php index 530272d..6d0d9ac 100644 --- a/src/Patterns/Shortest.php +++ b/src/Patterns/Shortest.php @@ -10,7 +10,6 @@ namespace WikibaseSolutions\CypherDSL\Patterns; -use WikibaseSolutions\CypherDSL\QueryConvertible; use WikibaseSolutions\CypherDSL\Traits\PatternTraits\PatternTrait; use WikibaseSolutions\CypherDSL\Types\PropertyTypes\IntegerType; use WikibaseSolutions\CypherDSL\Utils\CastUtils; diff --git a/src/Patterns/ShortestGroups.php b/src/Patterns/ShortestGroups.php index a3499df..8ccbb38 100644 --- a/src/Patterns/ShortestGroups.php +++ b/src/Patterns/ShortestGroups.php @@ -10,7 +10,6 @@ namespace WikibaseSolutions\CypherDSL\Patterns; -use WikibaseSolutions\CypherDSL\QueryConvertible; use WikibaseSolutions\CypherDSL\Traits\PatternTraits\PatternTrait; use WikibaseSolutions\CypherDSL\Types\PropertyTypes\IntegerType; use WikibaseSolutions\CypherDSL\Utils\CastUtils; diff --git a/src/Query.php b/src/Query.php index 1123975..9a5b493 100644 --- a/src/Query.php +++ b/src/Query.php @@ -144,8 +144,6 @@ public static function relationshipFrom(): Relationship return new Relationship(Direction::LEFT); } - - /** * Creates a shortestPath pattern. * diff --git a/tests/unit/FunctionsTest.php b/tests/unit/FunctionsTest.php index fd2b517..008c040 100644 --- a/tests/unit/FunctionsTest.php +++ b/tests/unit/FunctionsTest.php @@ -12,6 +12,9 @@ use PHPUnit\Framework\TestCase; use TypeError; +use function WikibaseSolutions\CypherDSL\allShortest; +use function WikibaseSolutions\CypherDSL\allShortestPaths; +use function WikibaseSolutions\CypherDSL\anyPath; use WikibaseSolutions\CypherDSL\Expressions\Literals\Boolean; use WikibaseSolutions\CypherDSL\Expressions\Literals\Float_; use WikibaseSolutions\CypherDSL\Expressions\Literals\Integer; @@ -22,15 +25,6 @@ use WikibaseSolutions\CypherDSL\Expressions\Procedures\Procedure; use WikibaseSolutions\CypherDSL\Expressions\RawExpression; use WikibaseSolutions\CypherDSL\Expressions\Variable; -use WikibaseSolutions\CypherDSL\Patterns\AllShortest; -use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; -use WikibaseSolutions\CypherDSL\Patterns\AnyPath; -use WikibaseSolutions\CypherDSL\Patterns\Shortest; -use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; -use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; -use function WikibaseSolutions\CypherDSL\allShortest; -use function WikibaseSolutions\CypherDSL\allShortestPaths; -use function WikibaseSolutions\CypherDSL\anyPath; use function WikibaseSolutions\CypherDSL\float; use function WikibaseSolutions\CypherDSL\function_; use function WikibaseSolutions\CypherDSL\integer; @@ -38,9 +32,15 @@ use function WikibaseSolutions\CypherDSL\literal; use function WikibaseSolutions\CypherDSL\map; use function WikibaseSolutions\CypherDSL\node; +use WikibaseSolutions\CypherDSL\Patterns\AllShortest; +use WikibaseSolutions\CypherDSL\Patterns\AllShortestPaths; +use WikibaseSolutions\CypherDSL\Patterns\AnyPath; use WikibaseSolutions\CypherDSL\Patterns\Direction; use WikibaseSolutions\CypherDSL\Patterns\Node; use WikibaseSolutions\CypherDSL\Patterns\Relationship; +use WikibaseSolutions\CypherDSL\Patterns\Shortest; +use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; +use WikibaseSolutions\CypherDSL\Patterns\ShortestPath; use WikibaseSolutions\CypherDSL\Query; use function WikibaseSolutions\CypherDSL\query; use function WikibaseSolutions\CypherDSL\raw; diff --git a/tests/unit/Patterns/ShortestGroupsTest.php b/tests/unit/Patterns/ShortestGroupsTest.php index f45c315..a668d1c 100644 --- a/tests/unit/Patterns/ShortestGroupsTest.php +++ b/tests/unit/Patterns/ShortestGroupsTest.php @@ -12,7 +12,6 @@ namespace WikibaseSolutions\CypherDSL\Tests\Unit\Patterns; use PHPUnit\Framework\TestCase; -use WikibaseSolutions\CypherDSL\Expressions\Literals\Integer; use WikibaseSolutions\CypherDSL\Patterns\ShortestGroups; use WikibaseSolutions\CypherDSL\Query; diff --git a/tests/unit/Patterns/ShortestTest.php b/tests/unit/Patterns/ShortestTest.php index cb72071..bd1729e 100644 --- a/tests/unit/Patterns/ShortestTest.php +++ b/tests/unit/Patterns/ShortestTest.php @@ -12,7 +12,6 @@ namespace WikibaseSolutions\CypherDSL\Tests\Unit\Patterns; use PHPUnit\Framework\TestCase; -use WikibaseSolutions\CypherDSL\Expressions\Literals\Integer; use WikibaseSolutions\CypherDSL\Patterns\Shortest; use WikibaseSolutions\CypherDSL\Query;