Skip to content

Commit 987d776

Browse files
committed
fixed psalm typing issues
1 parent e4ea336 commit 987d776

File tree

4 files changed

+125
-99
lines changed

4 files changed

+125
-99
lines changed

src/Formatter/Specialised/JoltHttpOGMTranslator.php

Lines changed: 97 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
/*
46
* This file is part of the Laudis Neo4j package.
57
*
@@ -11,18 +13,19 @@
1113

1214
namespace Laudis\Neo4j\Formatter\Specialised;
1315

16+
use Closure;
1417
use Laudis\Neo4j\Contracts\ConnectionInterface;
1518
use Laudis\Neo4j\Contracts\PointInterface;
1619
use Laudis\Neo4j\Formatter\OGMFormatter;
1720
use Laudis\Neo4j\Http\HttpHelper;
18-
use Laudis\Neo4j\Types\AbstractPropertyObject;
1921
use Laudis\Neo4j\Types\Cartesian3DPoint;
2022
use Laudis\Neo4j\Types\CartesianPoint;
2123
use Laudis\Neo4j\Types\CypherList;
2224
use Laudis\Neo4j\Types\CypherMap;
2325
use Laudis\Neo4j\Types\Node;
2426
use Laudis\Neo4j\Types\Path;
2527
use Laudis\Neo4j\Types\Relationship;
28+
use Laudis\Neo4j\Types\UnboundRelationship;
2629
use Laudis\Neo4j\Types\WGS843DPoint;
2730
use Laudis\Neo4j\Types\WGS84Point;
2831
use Psr\Http\Message\RequestInterface;
@@ -38,27 +41,26 @@
3841
*/
3942
final class JoltHttpOGMTranslator
4043
{
44+
/** @var array<string, pure-callable(mixed):OGMTypes> */
4145
private array $rawToTypes;
4246

4347
public function __construct()
4448
{
49+
/** @psalm-suppress InvalidPropertyAssignmentValue */
4550
$this->rawToTypes = [
4651
'?' => static fn (string $value): bool => strtolower($value) === 'true',
4752
'Z' => static fn (string $value): int => (int) $value,
4853
'R' => static fn (string $value): float => (float) $value,
4954
'U' => static fn (string $value): string => $value,
50-
'T' => fn (string $value): AbstractPropertyObject => $this->translateDateTime($value),
51-
'@' => fn (string $value): PointInterface => $this->translatePoint($value),
52-
'#' => static function (string $value) {
53-
// TODO
54-
throw new UnexpectedValueException('Binary data has not been implemented');
55-
},
56-
'[]' => fn (array $value): CypherList => $this->translateList($value),
57-
'{}' => fn (stdClass $value): CypherMap => $this->translateMap($value),
58-
'()' => fn (array $value): Node => new Node($value[0], new CypherList($value[1]), $this->translateMap($value[2])),
59-
'->' => fn (array $value): Relationship => new Relationship($value[0], $value[1], $value[3], $value[2], $this->translateMap($value[4])),
60-
'<-' => fn (array $value): Relationship => new Relationship($value[0], $value[3], $value[1], $value[2], $this->translateMap($value[4])),
61-
'..' => fn (array $value): Path => $this->translatePath($value),
55+
'T' => Closure::fromCallable([$this, 'translateDateTime']),
56+
'@' => Closure::fromCallable([$this, 'translatePoint']),
57+
'#' => Closure::fromCallable([$this, 'translateBinary']),
58+
'[]' => Closure::fromCallable([$this, 'translateList']),
59+
'{}' => Closure::fromCallable([$this, 'translateMap']),
60+
'()' => Closure::fromCallable([$this, 'translateNode']),
61+
'->' => Closure::fromCallable([$this, 'translateRightRelationship']),
62+
'<-' => Closure::fromCallable([$this, 'translateLeftRelationship']),
63+
'..' => Closure::fromCallable([$this, 'translatePath']),
6264
];
6365
}
6466

@@ -74,10 +76,15 @@ public function formatHttpResult(
7476
iterable $statements
7577
): CypherList {
7678
$allResults = [];
77-
// TODO: Lazy evaluation.
79+
/** @var stdClass $result */
7880
foreach ($body->results as $result) {
79-
$fields = $result->header->fields;
81+
/** @var stdClass $header */
82+
$header = $result->header;
83+
/** @var list<string> $fields */
84+
$fields = $header->fields;
8085
$rows = [];
86+
87+
/** @var list<stdClass> $data */
8188
foreach ($result->data as $data) {
8289
$row = [];
8390
foreach ($data as $key => $value) {
@@ -91,20 +98,27 @@ public function formatHttpResult(
9198
return new CypherList($allResults);
9299
}
93100

101+
/**
102+
* @return OGMTypes
103+
*/
94104
private function translateJoltType(?stdClass $value)
95105
{
96106
if (is_null($value)) {
97107
return null;
98108
}
99109

100-
[$key, $value] = HttpHelper::splitJoltSingleton($value);
110+
/** @var mixed $input */
111+
[$key, $input] = HttpHelper::splitJoltSingleton($value);
101112
if (!isset($this->rawToTypes[$key])) {
102113
throw new UnexpectedValueException('Unexpected Jolt key: '.$key);
103114
}
104115

105-
return $this->rawToTypes[$key]($value);
116+
return $this->rawToTypes[$key]($input);
106117
}
107118

119+
/**
120+
* @return OGMTypes
121+
*/
108122
private function translateDateTime(string $datetime)
109123
{
110124
// TODO; They're in ISO format so shouldn't be too hard
@@ -125,28 +139,28 @@ private function translatePoint(string $value): PointInterface
125139

126140
if ($srid === CartesianPoint::SRID) {
127141
return new CartesianPoint(
128-
$coordinates[0],
129-
$coordinates[1],
142+
(float) $coordinates[0],
143+
(float) $coordinates[1],
130144
);
131145
}
132146
if ($srid === Cartesian3DPoint::SRID) {
133147
return new Cartesian3DPoint(
134-
$coordinates[0],
135-
$coordinates[1],
136-
$coordinates[2],
148+
(float) $coordinates[0],
149+
(float) $coordinates[1],
150+
(float) $coordinates[2],
137151
);
138152
}
139153
if ($srid === WGS84Point::SRID) {
140154
return new WGS84Point(
141-
$coordinates[0],
142-
$coordinates[1],
155+
(float) $coordinates[0],
156+
(float) $coordinates[1],
143157
);
144158
}
145159
if ($srid === WGS843DPoint::SRID) {
146160
return new WGS843DPoint(
147-
$coordinates[0],
148-
$coordinates[1],
149-
$coordinates[2],
161+
(float) $coordinates[0],
162+
(float) $coordinates[1],
163+
(float) $coordinates[2],
150164
);
151165
}
152166
throw new UnexpectedValueException('A point with srid '.$srid.' has been returned, which has not been implemented.');
@@ -159,33 +173,40 @@ private function getSRID(string $value): int
159173
throw new UnexpectedValueException('Unexpected SRID string: '.$value);
160174
}
161175

176+
/** @var array{0: string, 1: string} $matches */
162177
return (int) $matches[1];
163178
}
164179

180+
/**
181+
* @return array{0: string, 1: string, 2: string} $coordinates
182+
*/
165183
private function getCoordinates(string $value): array
166184
{
167185
$matches = [];
168-
if (!preg_match('/^POINT ?(Z?) ?\(([0-9\. ]+)\)$/', $value, $matches)) {
186+
if (!preg_match('/^POINT ?(Z?) ?\(([0-9. ]+)\)$/', $value, $matches)) {
169187
throw new UnexpectedValueException('Unexpected point coordinates string: '.$value);
170188
}
189+
/** @var array{0: string, 1: string, 2: string} $matches */
171190
$coordinates = explode(' ', $matches[2]);
172-
if ($matches[1] === 'Z') {
173-
if (count($coordinates) !== 3) {
174-
throw new UnexpectedValueException('Expected 3 coordinates in string: '.$value);
175-
}
176-
} else {
177-
if (count($coordinates) !== 2) {
178-
throw new UnexpectedValueException('Expected 2 coordinates in string: '.$value);
179-
}
191+
if ($matches[1] === 'Z' && count($coordinates) !== 3) {
192+
throw new UnexpectedValueException('Expected 3 coordinates in string: '.$value);
193+
}
194+
195+
if (count($coordinates) !== 2) {
196+
throw new UnexpectedValueException('Expected 2 coordinates in string: '.$value);
180197
}
181198

182199
return $coordinates;
183200
}
184201

202+
/**
203+
* @return CypherMap<OGMTypes>
204+
*/
185205
private function translateMap(stdClass $value): CypherMap
186206
{
187207
return new CypherMap(
188208
function () use ($value) {
209+
/** @var stdClass|null $element */
189210
foreach ((array) $value as $key => $element) {
190211
yield $key => $this->translateJoltType($element);
191212
}
@@ -197,25 +218,33 @@ private function translateList(array $value): CypherList
197218
{
198219
return new CypherList(
199220
function () use ($value) {
221+
/** @var stdClass|null $element */
200222
foreach ($value as $element) {
201223
yield $this->translateJoltType($element);
202224
}
203225
}
204226
);
205227
}
206228

207-
private function translatePath(array $value)
229+
/**
230+
* @param list<stdClass> $value
231+
*/
232+
private function translatePath(array $value): Path
208233
{
209234
$nodes = [];
235+
/** @var list<UnboundRelationship> $relations */
210236
$relations = [];
211237
$ids = [];
212-
foreach ($value as $i => $nodeOrRelation) {
238+
foreach ($value as $nodeOrRelation) {
239+
/** @var Node|Relationship $nodeOrRelation */
213240
$nodeOrRelation = $this->translateJoltType($nodeOrRelation);
214-
if ($i % 2) {
241+
242+
if ($nodeOrRelation instanceof Relationship) {
215243
$relations[] = $nodeOrRelation;
216244
} else {
217245
$nodes[] = $nodeOrRelation;
218246
}
247+
219248
$ids[] = $nodeOrRelation->getId();
220249
}
221250

@@ -238,4 +267,33 @@ public function statementConfigOverride(): array
238267
{
239268
return [];
240269
}
270+
271+
/**
272+
* @param array{0: int, 1: list<string>, 2: stdClass} $value
273+
*/
274+
private function translateNode(array $value): Node
275+
{
276+
return new Node($value[0], new CypherList($value[1]), $this->translateMap($value[2]));
277+
}
278+
279+
/**
280+
* @param array{0:int, 1: int, 2: string, 3:int, 4: stdClass} $value
281+
*/
282+
private function translateRightRelationship(array $value): Relationship
283+
{
284+
return new Relationship($value[0], $value[1], $value[3], $value[2], $this->translateMap($value[4]));
285+
}
286+
287+
/**
288+
* @param array{0:int, 1: int, 2: string, 3:int, 4: stdClass} $value
289+
*/
290+
private function translateLeftRelationship(array $value): Relationship
291+
{
292+
return new Relationship($value[0], $value[3], $value[1], $value[2], $this->translateMap($value[4]));
293+
}
294+
295+
private function translateBinary(): Closure
296+
{
297+
throw new UnexpectedValueException('Binary data has not been implemented');
298+
}
241299
}

src/Http/HttpHelper.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ public static function getJoltBody(string $contents): stdClass
169169
}
170170

171171
/**
172+
* @pure
173+
*
172174
* @return array{0: string, 1: mixed}
173175
*/
174176
public static function splitJoltSingleton(stdClass $joltSingleton): array

src/Types/Relationship.php

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,49 +13,27 @@
1313

1414
namespace Laudis\Neo4j\Types;
1515

16-
use Laudis\Neo4j\Exception\PropertyDoesNotExistException;
17-
use function sprintf;
18-
1916
/**
2017
* A Relationship class representing a Relationship in cypher.
2118
*
2219
* @psalm-import-type OGMTypes from \Laudis\Neo4j\Formatter\OGMFormatter
2320
*
2421
* @psalm-immutable
25-
*
26-
* @extends AbstractPropertyObject<OGMTypes, int|string|CypherMap<OGMTypes>>
2722
*/
28-
final class Relationship extends AbstractPropertyObject
23+
final class Relationship extends UnboundRelationship
2924
{
30-
private int $id;
31-
3225
private int $startNodeId;
3326

3427
private int $endNodeId;
3528

36-
private string $type;
37-
38-
/** @var CypherMap<OGMTypes> */
39-
private CypherMap $properties;
40-
4129
/**
4230
* @param CypherMap<OGMTypes> $properties
4331
*/
4432
public function __construct(int $id, int $startNodeId, int $endNodeId, string $type, CypherMap $properties)
4533
{
46-
$this->id = $id;
34+
parent::__construct($id, $type, $properties);
4735
$this->startNodeId = $startNodeId;
4836
$this->endNodeId = $endNodeId;
49-
$this->type = $type;
50-
$this->properties = $properties;
51-
}
52-
53-
/**
54-
* Returns the id of the relationship.
55-
*/
56-
public function getId(): int
57-
{
58-
return $this->id;
5937
}
6038

6139
/**
@@ -74,20 +52,6 @@ public function getEndNodeId(): int
7452
return $this->endNodeId;
7553
}
7654

77-
/**
78-
* Returns the type of the relationship.
79-
*/
80-
public function getType(): string
81-
{
82-
return $this->type;
83-
}
84-
85-
public function getProperties(): CypherMap
86-
{
87-
/** @psalm-suppress InvalidReturnStatement false positive with type alias. */
88-
return $this->properties;
89-
}
90-
9155
/**
9256
* @psalm-suppress ImplementedReturnTypeMismatch False positive.
9357
*
@@ -101,28 +65,11 @@ public function getProperties(): CypherMap
10165
*/
10266
public function toArray(): array
10367
{
104-
return [
105-
'id' => $this->getId(),
106-
'type' => $this->getType(),
107-
'startNodeId' => $this->getStartNodeId(),
108-
'endNodeId' => $this->getEndNodeId(),
109-
'properties' => $this->getProperties(),
110-
];
111-
}
68+
$tbr = parent::toArray();
11269

113-
/**
114-
* Gets the property of the relationship by key.
115-
*
116-
* @return OGMTypes
117-
*/
118-
public function getProperty(string $key)
119-
{
120-
/** @psalm-suppress ImpureMethodCall */
121-
if (!$this->properties->hasKey($key)) {
122-
throw new PropertyDoesNotExistException(sprintf('Property "%s" does not exist on relationship', $key));
123-
}
70+
$tbr['startNodeId'] = $this->getStartNodeId();
71+
$tbr['endNodeId'] = $this->getStartNodeId();
12472

125-
/** @psalm-suppress ImpureMethodCall */
126-
return $this->properties->get($key);
73+
return $tbr;
12774
}
12875
}

0 commit comments

Comments
 (0)