Skip to content

Commit 2c2bf77

Browse files
committed
added path formatting for http
1 parent 6bd93a2 commit 2c2bf77

File tree

4 files changed

+93
-15
lines changed

4 files changed

+93
-15
lines changed

src/Formatter/Specialised/BoltOGMTranslator.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Bolt\structures\Point3D as BoltPoint3D;
2525
use Bolt\structures\Relationship as BoltRelationship;
2626
use Bolt\structures\Time as BoltTime;
27+
use Bolt\structures\UnboundRelationship as BoltUnboundRelationship;
2728
use function call_user_func;
2829
use Laudis\Neo4j\Types\Cartesian3DPoint;
2930
use Laudis\Neo4j\Types\CartesianPoint;
@@ -38,6 +39,7 @@
3839
use Laudis\Neo4j\Types\Path;
3940
use Laudis\Neo4j\Types\Relationship;
4041
use Laudis\Neo4j\Types\Time;
42+
use Laudis\Neo4j\Types\UnboundRelationship;
4143
use UnexpectedValueException;
4244

4345
/**
@@ -65,6 +67,7 @@ public function __construct()
6567
BoltLocalDateTime::class => [$this, 'makeFromBoltLocalDateTime'],
6668
BoltLocalTime::class => [$this, 'makeFromBoltLocalTime'],
6769
BoltRelationship::class => [$this, 'makeFromBoltRelationship'],
70+
BoltUnboundRelationship::class => [$this, 'makeFromBoltUnboundRelationship'],
6871
BoltPath::class => [$this, 'makeFromBoltPath'],
6972
BoltPoint2D::class => [$this, 'makeFromBoltPoint2D'],
7073
BoltPoint3D::class => [$this, 'makeFromBoltPoint3D'],
@@ -155,6 +158,25 @@ private function makeFromBoltRelationship(BoltRelationship $rel): Relationship
155158
);
156159
}
157160

161+
private function makeFromBoltUnboundRelationship(BoltUnboundRelationship $rel): UnboundRelationship
162+
{
163+
/** @var array<string, OGMTypes> $map */
164+
$map = [];
165+
/**
166+
* @var string $key
167+
* @var mixed $property
168+
*/
169+
foreach ($rel->properties() as $key => $property) {
170+
$map[$key] = $this->mapValueToType($property);
171+
}
172+
173+
return new UnboundRelationship(
174+
$rel->id(),
175+
$rel->type(),
176+
new CypherMap($map)
177+
);
178+
}
179+
158180
private function makeFromBoltPoint2D(BoltPoint2d $x): CartesianPoint
159181
{
160182
return new CartesianPoint($x->x(), $x->y(), 'cartesian', $x->srid());
@@ -174,10 +196,10 @@ private function makeFromBoltPath(BoltPath $path): Path
174196
$nodes[] = $this->makeFromBoltNode($node);
175197
}
176198
$relationships = [];
177-
/** @var list<BoltRelationship> $rels */
199+
/** @var list<BoltUnboundRelationship> $rels */
178200
$rels = $path->rels();
179201
foreach ($rels as $rel) {
180-
$relationships[] = $this->makeFromBoltRelationship($rel);
202+
$relationships[] = $this->makeFromBoltUnboundRelationship($rel);
181203
}
182204
/** @var list<int> $ids */
183205
$ids = $path->ids();

src/Formatter/Specialised/HttpOGMArrayTranslator.php

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace Laudis\Neo4j\Formatter\Specialised;
1515

16+
use Laudis\Neo4j\Types\Path;
17+
use Laudis\Neo4j\Types\UnboundRelationship;
1618
use function is_array;
1719
use Laudis\Neo4j\Contracts\PointInterface;
1820
use Laudis\Neo4j\Types\Cartesian3DPoint;
@@ -102,44 +104,71 @@ public function translate(array $meta, array $relationships, int $metaIndex, int
102104
$currentMeta = $meta[$metaIndex];
103105
$metaIncrease = 1;
104106
$relationshipIncrease = 0;
105-
$type = $currentMeta === null ? null : ($currentMeta['type'] ?? null);
107+
$type = $currentMeta === null ? null : ($currentMeta['type'] ?? 'path');
106108

107109
switch ($type) {
108110
case 'relationship':
109111
$tbr = $this->relationship($relationships[$relationshipIndex]);
110112
++$relationshipIncrease;
111113
break;
114+
case 'path':
115+
[$path, $relIncrease] = $this->path($currentMeta, $nodes, $relationships, $relationshipIndex);
116+
$relationshipIncrease += $relIncrease;
117+
$tbr = $path;
118+
break;
112119
case 'point':
113120
$tbr = $this->translatePoint($value);
114121
break;
115122
default:
116123
/** @var array<array-key, array|scalar|null> $value */
117124
$tbr = $this->translateContainer($value);
118-
if ($type === 'node' && $tbr instanceof CypherMap && isset($currentMeta['id'])) {
119-
$tbr = $this->translateNode($nodes, $currentMeta['id'], $tbr);
125+
if ($type === 'node' && isset($currentMeta['id'])) {
126+
$tbr = $this->translateNode($nodes, $currentMeta['id']);
120127
}
121128
break;
122129
}
123130

124131
return [$metaIncrease, $relationshipIncrease, $tbr];
125132
}
126133

134+
private function path(array $meta, array $nodes, array $relationships, int $relIndex): array
135+
{
136+
$nodesTbr = [];
137+
$ids = [];
138+
$rels = [];
139+
$relIncrease = 0;
140+
foreach ($meta as $nodeOrRel) {
141+
if ($nodeOrRel['type'] === 'relationship') {
142+
$rel = $relationships[$relIndex];
143+
++$relIndex;
144+
++$relIncrease;
145+
$rels[] = new UnboundRelationship((int) $rel['id'], $rel['type'], new CypherMap($rel['properties']));
146+
} else {
147+
$nodesTbr[] = $this->translateNode($nodes, $nodeOrRel['id']);
148+
}
149+
$ids[] = $nodeOrRel['id'];
150+
}
151+
152+
return [new Path(new CypherList($nodesTbr), new CypherList($rels), new CypherList($ids)), $relIncrease];
153+
}
154+
127155
/**
128156
* @param list<NodeArray> $nodes
129-
* @param CypherMap<OGMTypes> $tbr
130157
*/
131-
private function translateNode(array $nodes, int $id, CypherMap $tbr): Node
158+
private function translateNode(array $nodes, int $id): Node
132159
{
133160
/** @var list<string> */
134161
$labels = [];
162+
$props = [];
135163
foreach ($nodes as $node) {
136164
if ((int) $node['id'] === $id) {
137165
$labels = $node['labels'];
166+
$props = $node['properties'];
138167
break;
139168
}
140169
}
141170

142-
return new Node($id, new CypherList($labels), $tbr);
171+
return new Node($id, new CypherList($labels), new CypherMap($props));
143172
}
144173

145174
/**

src/Types/Path.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@
1818
*
1919
* @psalm-immutable
2020
*
21-
* @extends AbstractPropertyObject<CypherList<Node>|CypherList<Relationship>|CypherList<int>, CypherList<Node>|CypherList<Relationship>|CypherList<int>>
21+
* @extends AbstractPropertyObject<CypherList<Node>|CypherList<UnboundRelationship>|CypherList<int>, CypherList<Node>|CypherList<UnboundRelationship>|CypherList<int>>
2222
*/
2323
final class Path extends AbstractPropertyObject
2424
{
2525
/** @var CypherList<Node> */
2626
private CypherList $nodes;
27-
/** @var CypherList<Relationship> */
27+
/** @var CypherList<UnboundRelationship> */
2828
private CypherList $relationships;
2929
/** @var CypherList<int> */
3030
private CypherList $ids;
3131

3232
/**
33-
* @param CypherList<Node> $nodes
34-
* @param CypherList<Relationship> $relationships
35-
* @param CypherList<int> $ids
33+
* @param CypherList<Node> $nodes
34+
* @param CypherList<UnboundRelationship> $relationships
35+
* @param CypherList<int> $ids
3636
*/
3737
public function __construct(CypherList $nodes, CypherList $relationships, CypherList $ids)
3838
{
@@ -54,7 +54,7 @@ public function getNodes(): CypherList
5454
/**
5555
* Returns the relationships in the path.
5656
*
57-
* @return CypherList<Relationship>
57+
* @return CypherList<UnboundRelationship>
5858
*/
5959
public function getRelationships(): CypherList
6060
{
@@ -72,7 +72,7 @@ public function getIds(): CypherList
7272
}
7373

7474
/**
75-
* @return array{id: CypherList<int>, nodes: CypherList<Node>, relationships: CypherList<Relationship>}
75+
* @return array{id: CypherList<int>, nodes: CypherList<Node>, relationships: CypherList<UnboundRelationship>}
7676
*/
7777
public function toArray(): array
7878
{

tests/Integration/OGMFormatterIntegrationTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
use Laudis\Neo4j\Types\LocalDateTime;
3030
use Laudis\Neo4j\Types\LocalTime;
3131
use Laudis\Neo4j\Types\Node;
32+
use Laudis\Neo4j\Types\Path;
3233
use Laudis\Neo4j\Types\Relationship;
3334
use Laudis\Neo4j\Types\Time;
3435
use function range;
@@ -434,6 +435,32 @@ public function testPath(string $alias): void
434435
self::assertEquals(1, $results->count());
435436
}
436437

438+
/**
439+
* @dataProvider connectionAliases
440+
*/
441+
public function testPath2(string $alias): void
442+
{
443+
$results = $this->client->run(<<<'CYPHER'
444+
MERGE (a:Node {x:$x}) - [b:HasNode {attribute: $xy}] -> (c:Node {y:$y}) - [d:HasNode {attribute: $yz}] -> (e:Node {z:$z})
445+
RETURN (a) - [b] - (c) - [d] - (e) AS path
446+
CYPHER
447+
, ['x' => 'x', 'xy' => 'xy', 'y' => 'y', 'yz' => 'yz', 'z' => 'z'], $alias);
448+
449+
self::assertEquals(1, $results->count());
450+
$path = $results->first()->get('path');
451+
452+
self::assertInstanceOf(Path::class, $path);
453+
self::assertCount(2, $path->getRelationships());
454+
self::assertCount(3, $path->getNodes());
455+
456+
self::assertEquals(new CypherMap(['x' => 'x']), $path->getNodes()->get(0)->getProperties());
457+
self::assertEquals(new CypherMap(['y' => 'y']), $path->getNodes()->get(1)->getProperties());
458+
self::assertEquals(new CypherMap(['z' => 'z']), $path->getNodes()->get(2)->getProperties());
459+
460+
self::assertEquals(new CypherMap(['attribute' => 'xy']), $path->getRelationships()->get(0)->getProperties());
461+
self::assertEquals(new CypherMap(['attribute' => 'yz']), $path->getRelationships()->get(1)->getProperties());
462+
}
463+
437464
/**
438465
* @dataProvider connectionAliases
439466
*/

0 commit comments

Comments
 (0)