Skip to content

Commit 53bb866

Browse files
committed
big refactor in http formatter
1 parent fcd2297 commit 53bb866

14 files changed

+685
-633
lines changed

src/Contracts/FormatterInterface.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Laudis\Neo4j\Types\CypherList;
2020
use Psr\Http\Message\RequestInterface;
2121
use Psr\Http\Message\ResponseInterface;
22+
use stdClass;
2223

2324
/**
2425
* A formatter (aka Hydrator) is reponsible for formatting the incoming results of the driver.
@@ -82,14 +83,14 @@ public function formatBoltResult(array $meta, array $results, ConnectionInterfac
8283
/**
8384
* Formats the results of the HTTP protocol to the unified format.
8485
*
85-
* @param CypherResponseSet $body
86+
* @param stdClass $body
8687
* @param iterable<Statement> $statements
8788
*
8889
* @throws JsonException
8990
*
9091
* @return CypherList<ResultFormat>
9192
*/
92-
public function formatHttpResult(ResponseInterface $response, array $body, ConnectionInterface $connection, float $resultsAvailableAfter, float $resultsConsumedAfter, iterable $statements): CypherList;
93+
public function formatHttpResult(ResponseInterface $response, stdClass $body, ConnectionInterface $connection, float $resultsAvailableAfter, float $resultsConsumedAfter, iterable $statements): CypherList;
9394

9495
/**
9596
* Decorates a request to make make sure it requests the correct format.

src/Formatter/BasicFormatter.php

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

1414
namespace Laudis\Neo4j\Formatter;
1515

16+
use stdClass;
1617
use function array_slice;
1718
use Bolt\structures\Path;
1819
use function count;
@@ -74,36 +75,35 @@ public function formatBoltResult(array $meta, array $results, ?ConnectionInterfa
7475
return new CypherList($tbr);
7576
}
7677

77-
public function formatHttpResult(ResponseInterface $response, array $body, ?ConnectionInterface $connection = null, ?float $resultsAvailableAfter = null, ?float $resultsConsumedAfter = null, ?iterable $statements = null): CypherList
78+
public function formatHttpResult(ResponseInterface $response, stdClass $body, ?ConnectionInterface $connection = null, ?float $resultsAvailableAfter = null, ?float $resultsConsumedAfter = null, ?iterable $statements = null): CypherList
7879
{
7980
/** @var list<CypherList<CypherMap<scalar|array|null>>> */
8081
$tbr = [];
8182

82-
foreach ($body['results'] as $results) {
83+
foreach ($body->results as $results) {
8384
$tbr[] = $this->buildResult($results);
8485
}
8586

8687
return new CypherList($tbr);
8788
}
8889

8990
/**
90-
* @psalm-param CypherResponse $result
91-
*
9291
* @return CypherList<CypherMap<scalar|array|null>>
9392
*/
94-
private function buildResult(array $result): CypherList
93+
private function buildResult(stdClass $result): CypherList
9594
{
9695
/** @var list<CypherMap<scalar|array|null>> */
9796
$tbr = [];
9897

99-
$columns = $result['columns'];
100-
foreach ($result['data'] as $dataRow) {
101-
$row = $dataRow['row'];
98+
$columns = (array) $result->columns;
99+
foreach ($result->data as $dataRow) {
100+
$row = $dataRow->row;
102101
/** @var array<string, scalar|array|null> $map */
103102
$map = [];
104103
$vector = $row;
105104
foreach ($columns as $index => $key) {
106-
$map[$key] = $vector[$index];
105+
// Make sure it are all arrays now
106+
$map[$key] = json_decode(json_encode($vector[$index], JSON_THROW_ON_ERROR), true, 512, JSON_THROW_ON_ERROR);
107107
}
108108
$tbr[] = new CypherMap($map);
109109
}

src/Formatter/OGMFormatter.php

Lines changed: 9 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,16 @@
1515

1616
use function array_slice;
1717
use function count;
18-
use Exception;
19-
use function is_array;
20-
use function is_string;
2118
use Laudis\Neo4j\Contracts\ConnectionInterface;
2219
use Laudis\Neo4j\Contracts\FormatterInterface;
2320
use Laudis\Neo4j\Databags\Statement;
2421
use Laudis\Neo4j\Formatter\Specialised\BoltOGMTranslator;
25-
use Laudis\Neo4j\Formatter\Specialised\HttpOGMArrayTranslator;
26-
use Laudis\Neo4j\Formatter\Specialised\HttpOGMStringTranslator;
22+
use Laudis\Neo4j\Formatter\Specialised\HttpOGMTranslator;
2723
use Laudis\Neo4j\Types\CypherList;
2824
use Laudis\Neo4j\Types\CypherMap;
2925
use Psr\Http\Message\RequestInterface;
3026
use Psr\Http\Message\ResponseInterface;
27+
use stdClass;
3128

3229
/**
3330
* Formats the result in a basic OGM (Object Graph Mapping) format by mapping al cypher types to types found in the \Laudis\Neo4j\Types namespace.
@@ -38,13 +35,6 @@
3835
*
3936
* @psalm-type OGMResults = CypherList<CypherMap<OGMTypes>>
4037
*
41-
* @psalm-import-type NodeArray from \Laudis\Neo4j\Formatter\Specialised\HttpOGMArrayTranslator
42-
* @psalm-import-type MetaArray from \Laudis\Neo4j\Formatter\Specialised\HttpOGMArrayTranslator
43-
* @psalm-import-type RelationshipArray from \Laudis\Neo4j\Formatter\Specialised\HttpOGMArrayTranslator
44-
*
45-
* @psalm-type CypherResultDataRow = list<array{row: list<scalar|array|null>, meta: MetaArray, graph: array{nodes: list<NodeArray>, relationships: list<RelationshipArray>}}>
46-
* @psalm-type CypherResult = array{columns: list<string>, data: CypherResultDataRow}
47-
*
4838
* @psalm-import-type BoltMeta from \Laudis\Neo4j\Contracts\FormatterInterface
4939
*
5040
* @implements FormatterInterface<CypherList<CypherMap<OGMTypes>>>
@@ -54,14 +44,12 @@
5444
final class OGMFormatter implements FormatterInterface
5545
{
5646
private BoltOGMTranslator $boltTranslator;
57-
private HttpOGMArrayTranslator $arrayTranslator;
58-
private HttpOGMStringTranslator $stringTranslator;
47+
private HttpOGMTranslator $httpTranslator;
5948

60-
public function __construct(BoltOGMTranslator $boltTranslator, HttpOGMArrayTranslator $arrayTranslator, HttpOGMStringTranslator $stringTranslator)
49+
public function __construct(BoltOGMTranslator $boltTranslator, HttpOGMTranslator $httpTranslator)
6150
{
6251
$this->boltTranslator = $boltTranslator;
63-
$this->arrayTranslator = $arrayTranslator;
64-
$this->stringTranslator = $stringTranslator;
52+
$this->httpTranslator = $httpTranslator;
6553
}
6654

6755
/**
@@ -71,11 +59,7 @@ public function __construct(BoltOGMTranslator $boltTranslator, HttpOGMArrayTrans
7159
*/
7260
public static function create(): OGMFormatter
7361
{
74-
return new self(
75-
new BoltOGMTranslator(),
76-
new HttpOGMArrayTranslator(),
77-
new HttpOGMStringTranslator()
78-
);
62+
return new self(new BoltOGMTranslator(), new HttpOGMTranslator());
7963
}
8064

8165
/**
@@ -98,61 +82,13 @@ public function formatBoltResult(array $meta, array $results, ConnectionInterfac
9882
return new CypherList($tbr);
9983
}
10084

101-
public function formatHttpResult(ResponseInterface $response, array $body, ConnectionInterface $connection, float $resultsAvailableAfter, float $resultsConsumedAfter, iterable $statements): CypherList
85+
public function formatHttpResult(ResponseInterface $response, stdClass $body, ConnectionInterface $connection, float $resultsAvailableAfter, float $resultsConsumedAfter, iterable $statements): CypherList
10286
{
10387
/** @var list<CypherList<CypherMap<OGMTypes>>> $tbr */
10488
$tbr = [];
10589

106-
foreach ($body['results'] as $results) {
107-
/** @var CypherResult $results */
108-
$tbr[] = $this->buildResult($results);
109-
}
110-
111-
return new CypherList($tbr);
112-
}
113-
114-
/**
115-
* @param CypherResult $result
116-
*
117-
* @throws Exception
118-
*
119-
* @return CypherList<CypherMap<OGMTypes>>
120-
*/
121-
private function buildResult(array $result): CypherList
122-
{
123-
/** @var list<CypherMap<OGMTypes>> $tbr */
124-
$tbr = [];
125-
126-
$columns = $result['columns'];
127-
foreach ($result['data'] as $data) {
128-
$meta = $data['meta'];
129-
$nodes = $data['graph']['nodes'];
130-
$relationship = $data['graph']['relationships'];
131-
$metaIndex = 0;
132-
$relationshipIndex = 0;
133-
$nodeIndex = 0;
134-
135-
/** @var array<string, OGMTypes> $record */
136-
$record = [];
137-
foreach ($data['row'] as $i => $value) {
138-
if (is_array($value)) {
139-
$translation = $this->arrayTranslator->translate($meta, $relationship, $metaIndex, $relationshipIndex, $nodeIndex, $nodes, $value);
140-
141-
$relationshipIndex += $translation[1];
142-
$metaIndex += $translation[0];
143-
$nodeIndex += $translation[2];
144-
$record[$columns[$i]] = $translation[3];
145-
} elseif (is_string($value)) {
146-
[$metaIncrement, $translation] = $this->stringTranslator->translate($metaIndex, $meta, $value);
147-
$metaIndex += $metaIncrement;
148-
$record[$columns[$i]] = $translation;
149-
} else {
150-
$record[$columns[$i]] = $value;
151-
++$metaIndex;
152-
}
153-
}
154-
155-
$tbr[] = new CypherMap($record);
90+
foreach ($body->results as $results) {
91+
$tbr[] = $this->httpTranslator->translateResult($results);
15692
}
15793

15894
return new CypherList($tbr);
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Laudis Neo4j package.
5+
*
6+
* (c) Laudis technologies <http://laudis.tech>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Laudis\Neo4j\Formatter\Specialised;
13+
14+
use function is_array;
15+
use stdClass;
16+
17+
/**
18+
* @psalm-type RelationshipArray = array{id: string, type: string, startNode: string, endNode: string, properties: array<string, scalar|null|array<array-key, scalar|null|array>>}
19+
* @psalm-type NodeArray = array{id: string, labels: list<string>, properties: array<string, scalar|null|array}
20+
* @psalm-type Meta = array{id?: int, type: string, deleted?: bool}
21+
* @psalm-type MetaArray = list<Meta|null|list<array{id: int, type: string, deleted: bool}>>
22+
* @psalm-type CypherResultDataRow = array{row: list<scalar|array|null>, meta: MetaArray, graph: array{nodes: list<NodeArray>, relationships: list<RelationshipArray>}}
23+
*
24+
* @psalm-immutable
25+
*/
26+
final class HttpMetaInfo
27+
{
28+
/** @var list<stdClass|list> */
29+
private array $meta;
30+
/** @var list<stdClass> */
31+
private array $nodes;
32+
/** @var list<stdClass> */
33+
private array $relationships;
34+
private int $currentMeta;
35+
36+
/**
37+
* @param list<stdClass> $relationships
38+
* @param list<stdClass> $meta
39+
* @param list<stdClass> $nodes
40+
*/
41+
public function __construct(
42+
array $meta,
43+
array $nodes,
44+
array $relationships,
45+
int $currentMeta = 0
46+
) {
47+
$this->meta = $meta;
48+
$this->nodes = $nodes;
49+
$this->relationships = $relationships;
50+
$this->currentMeta = $currentMeta;
51+
}
52+
53+
/**
54+
* @pure
55+
*/
56+
public static function createFromData(stdClass $data): self
57+
{
58+
/** @var stdClass */
59+
$graph = $data->graph;
60+
61+
return new self($data->meta, $graph->nodes, $graph->relationships);
62+
}
63+
64+
/**
65+
* @return stdClass|list|null
66+
*/
67+
public function currentMeta()
68+
{
69+
return $this->meta[$this->currentMeta] ?? null;
70+
}
71+
72+
public function currentNode(): ?stdClass
73+
{
74+
$meta = $this->currentMeta();
75+
if ($meta === null || is_array($meta)) {
76+
return null;
77+
}
78+
79+
foreach ($this->nodes as $node) {
80+
if ((int) $node->id === $meta->id) {
81+
return $node;
82+
}
83+
}
84+
85+
return null;
86+
}
87+
88+
public function getCurrentRelationship(): ?stdClass
89+
{
90+
$meta = $this->currentMeta();
91+
if ($meta === null || is_array($meta)) {
92+
return null;
93+
}
94+
95+
foreach ($this->relationships as $relationship) {
96+
if ((int) $relationship->id === $meta->id) {
97+
return $relationship;
98+
}
99+
}
100+
101+
return null;
102+
}
103+
104+
public function getCurrentType(): ?string
105+
{
106+
$currentMeta = $this->currentMeta();
107+
if (is_array($currentMeta)) {
108+
return 'path';
109+
}
110+
111+
if ($currentMeta === null) {
112+
return null;
113+
}
114+
115+
return $currentMeta->type;
116+
}
117+
118+
public function withNestedMeta(): self
119+
{
120+
$tbr = clone $this;
121+
122+
$tbr->meta = (array) $this->currentMeta();
123+
$tbr->currentMeta = 0;
124+
125+
return $tbr;
126+
}
127+
128+
public function incrementMeta(): self
129+
{
130+
$tbr = clone $this;
131+
++$tbr->currentMeta;
132+
133+
return $tbr;
134+
}
135+
}

0 commit comments

Comments
 (0)