Skip to content

Commit 149f383

Browse files
authored
Merge pull request #71 from wgevaert/5.0.0-typing-and-consistency
minor improvements to 5.0.0 typing and consistency
2 parents 2446bd2 + 7c80129 commit 149f383

40 files changed

+89
-69
lines changed

src/Expressions/Literals/Float_.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public function getValue(): float
4848
*/
4949
public function toQuery(): string
5050
{
51-
return (string)$this->value;
51+
$value = (string) $this->value;
52+
if (
53+
ctype_digit($value)
54+
|| ($value[0] === '-' && ctype_digit(substr($value,1)) )
55+
) {
56+
$value .= '.0';
57+
}
58+
return $value;
5259
}
5360
}

src/Expressions/Literals/Integer.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use WikibaseSolutions\CypherDSL\Traits\TypeTraits\PropertyTypeTraits\IntegerTypeTrait;
1313
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\IntegerType;
14+
use TypeError;
1415

1516
/**
1617
* Represents an integer literal.
@@ -20,25 +21,40 @@ final class Integer implements IntegerType
2021
use IntegerTypeTrait;
2122

2223
/**
23-
* @var int The value
24+
* @var string The value
2425
*/
25-
private int $value;
26+
private string $value;
2627

2728
/**
28-
* @param int $value The value
29+
* @param int|string $value The value
2930
* @internal This function is not covered by the backwards compatibility guarantee of php-cypher-dsl
3031
*/
31-
public function __construct(int $value)
32+
public function __construct($value)
3233
{
33-
$this->value = $value;
34+
if (!is_int($value) && !is_string($value)) {
35+
throw new TypeError('An integer should be given as a string or integer, '.gettype($value).' received.');
36+
}
37+
$parsedValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
38+
39+
if (false === $parsedValue) {
40+
throw new TypeError(
41+
'A non-integer string has been provided: "'.$value.'".'
42+
);
43+
} elseif (is_string($value) && $parsedValue !== $value) {
44+
throw new TypeError(
45+
'A non-integer string has been provided: "'.$value.'", should be something like "'.$parsedValue.'".'
46+
);
47+
}
48+
49+
$this->value = $parsedValue;
3450
}
3551

3652
/**
37-
* Returns the integer value.
53+
* Returns a string representation of the integer value.
3854
*
39-
* @return int
55+
* @return string
4056
*/
41-
public function getValue(): int
57+
public function getValue(): string
4258
{
4359
return $this->value;
4460
}
@@ -48,6 +64,6 @@ public function getValue(): int
4864
*/
4965
public function toQuery(): string
5066
{
51-
return (string)$this->value;
67+
return $this->value;
5268
}
5369
}

src/Expressions/Literals/Literal.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ public static function literal($literal)
6969
return array_is_list($literal) ? self::list($literal) : self::map($literal);
7070
}
7171

72+
if (is_object($literal) && method_exists($literal, '__toString')) {
73+
return self::string($literal->__toString());
74+
}
75+
7276
throw new InvalidArgumentException(
73-
"The literal type " . is_object($literal) ? get_class($literal) : gettype($literal) . " is not supported by Cypher"
77+
"The literal type " . get_debug_type($literal) . " is not supported by Cypher"
7478
);
7579
}
7680

@@ -153,8 +157,11 @@ public static function float(float $value): Float_
153157
* @param array $value
154158
* @return List_
155159
*/
156-
public static function list(array $value): List_
160+
public static function list(iterable $value): List_
157161
{
162+
if (is_object($value)) {
163+
$value = iterator_to_array($value);
164+
}
158165
return new List_(array_map([self::class, 'toAnyType'], $value));
159166
}
160167

src/Expressions/Literals/Map.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ final class Map implements MapType
4343
*/
4444
public function __construct(array $elements = [])
4545
{
46-
self::assertClassArray('properties', AnyType::class, $elements);
46+
self::assertClassArray('elements', AnyType::class, $elements);
4747
$this->elements = $elements;
4848
}
4949

src/Expressions/Operators/ExclusiveOr.php renamed to src/Expressions/Operators/ExclusiveDisjunction.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010
namespace WikibaseSolutions\CypherDSL\Expressions\Operators;
1111

1212
/**
13-
* Represents the application of the exclusive or (XOR) operator.
13+
* Represents the application of the exclusive disjunction (XOR) operator.
1414
*
1515
* @see https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf (page 50)
1616
* @see https://neo4j.com/docs/cypher-manual/current/syntax/operators/#query-operators-boolean
1717
*/
18-
final class ExclusiveOr extends BooleanBinaryOperator
18+
final class ExclusiveDisjunction extends BooleanBinaryOperator
1919
{
2020
/**
2121
* @inheritDoc

src/Expressions/Operators/ModuloDivision.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
/**
1313
* Represents the application of the modulo division (%) operator.
14+
* This operator is sometimes simply called "modulo operator".
1415
*
1516
* @see https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf (page 48)
1617
* @see https://neo4j.com/docs/cypher-manual/current/syntax/operators/#query-operators-mathematical

src/Patterns/Relationship.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ private function relationshipDetailToString(): string
301301

302302
if (isset($this->properties)) {
303303
// Only add the properties if they're not empty
304-
if (!$this->properties instanceof Map || $this->properties->getProperties() !== []) {
304+
if (!$this->properties instanceof Map || $this->properties->getElements() !== []) {
305305
$map = $this->properties->toQuery();
306306

307307
if ($conditionInner !== "") {

src/Query.php

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
use WikibaseSolutions\CypherDSL\Patterns\Relationship;
4949
use WikibaseSolutions\CypherDSL\Syntax\Alias;
5050
use WikibaseSolutions\CypherDSL\Syntax\PropertyReplacement;
51+
use WikibaseSolutions\CypherDSL\Traits\CastTrait;
5152
use WikibaseSolutions\CypherDSL\Traits\ErrorTrait;
5253
use WikibaseSolutions\CypherDSL\Traits\EscapeTrait;
5354
use WikibaseSolutions\CypherDSL\Types\AnyType;
@@ -63,6 +64,7 @@ final class Query implements QueryConvertible
6364
{
6465
use EscapeTrait;
6566
use ErrorTrait;
67+
use CastTrait;
6668

6769
// A reference to the Literal class
6870
public const literal = Literal::class;
@@ -246,7 +248,7 @@ public static function float(float $value): Float_
246248
* @param array $value
247249
* @return List_
248250
*/
249-
public static function list(array $value): List_
251+
public static function list(iterable $value): List_
250252
{
251253
return self::literal()::list($value);
252254
}
@@ -358,7 +360,7 @@ public function call($query = null, $variables = []): self
358360
* Creates the CALL procedure clause.
359361
*
360362
* @param Procedure $procedure The procedure to call
361-
* @param string|Variable|Alias|string[]|Variable[]|Alias[] $yields The result fields that should be returned
363+
* @param string|Variable|Alias|(string|Variable|Alias)[] $yields The result fields that should be returned
362364
*
363365
* @return $this
364366
*
@@ -370,6 +372,7 @@ public function callProcedure(Procedure $procedure, $yields = []): self
370372
if (!is_array($yields)) {
371373
$yields = [$yields];
372374
}
375+
$yields = $this->makeAliasArray($yields, 'toName');
373376

374377
$callProcedureClause = new CallProcedureClause();
375378
$callProcedureClause->setProcedure($procedure);
@@ -407,7 +410,7 @@ public function match($patterns): self
407410
/**
408411
* Creates the RETURN clause.
409412
*
410-
* @param AnyType|Alias|Pattern|int|float|string|bool|array|AnyType[]|Alias[]|Pattern[]|int[]|float[]|string[]|bool[]|array[] $expressions The expressions to return
413+
* @param AnyType|Alias|Pattern|int|float|string|bool|array|(AnyType|Alias|Pattern|int|float|string|bool|array)[] $expressions The expressions to return
411414
* @param bool $distinct Whether to be a RETURN DISTINCT query
412415
*
413416
* @return $this
@@ -420,9 +423,11 @@ public function returning($expressions, bool $distinct = false): self
420423
if (!is_array($expressions)) {
421424
$expressions = [$expressions];
422425
}
426+
$expressions = $this->makeAliasArray($expressions);
423427

424428
$returnClause = new ReturnClause();
425429
$returnClause->addColumn(...$expressions);
430+
426431
$returnClause->setDistinct($distinct);
427432

428433
$this->clauses[] = $returnClause;
@@ -482,7 +487,7 @@ public function delete($structures, bool $detach = false): self
482487
/**
483488
* Creates the DETACH DELETE clause.
484489
*
485-
* @param StructuralType|Pattern|StructuralType[]|Pattern[] $variables The variables to delete, including relationships
490+
* @param StructuralType|Pattern|(StructuralType|Pattern)[] $variables The variables to delete, including nodes, relationships and paths
486491
*
487492
* @return $this
488493
* @see https://neo4j.com/docs/cypher-manual/current/clauses/delete/
@@ -688,7 +693,7 @@ public function where($expressions, string $operator = WhereClause::AND): self
688693
/**
689694
* Creates the WITH clause.
690695
*
691-
* @param AnyType|Alias|Pattern|int|float|string|bool|array|AnyType[]|Alias[]|Pattern[]|int[]|float[]|string[]|bool[]|array[] $expressions The entries to add; if the array-key is non-numerical, it is used as the alias
696+
* @param AnyType|Alias|Pattern|int|float|string|bool|array|(AnyType|Alias|Pattern|int|float|string|bool|array)[] $expressions The entries to add; if the array-key is non-numerical, it is used as the alias
692697
*
693698
* @return $this
694699
*
@@ -700,6 +705,7 @@ public function with($expressions): self
700705
if (!is_array($expressions)) {
701706
$expressions = [$expressions];
702707
}
708+
$expressions = $this->makeAliasArray($expressions);
703709

704710
$withClause = new WithClause();
705711
$withClause->addEntry(...$expressions);
@@ -813,4 +819,23 @@ public function __toString(): string
813819
{
814820
return $this->build();
815821
}
822+
823+
/**
824+
* Changes an associative array into an array of aliasses.
825+
*
826+
* @param array $array The array to change into a sequential array
827+
* @param string $castFunc Name of the (static) method to use to cast the elements of $array.
828+
* @return array A sequential array, possibly consisting of aliasses.
829+
*/
830+
private function makeAliasArray(array $array, string $castFunc = 'toAnyType'): array
831+
{
832+
if (array_is_list($array)) {
833+
return array_map([self::class, $castFunc], $array);
834+
}
835+
$newArray = [];
836+
foreach ($array as $key => $value) {
837+
$newArray []= new Alias(call_user_func([self::class, $castFunc], $value), new Variable($key));
838+
}
839+
return $newArray;
840+
}
816841
}

src/Traits/CastTrait.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,14 @@ private static function toAnyType($value): AnyType
165165
{
166166
self::assertClass('value', [AnyType::class, Pattern::class, 'int', 'float', 'string', 'bool', 'array'], $value);
167167

168-
if ($value instanceof AnyType) {
169-
return $value;
170-
}
171-
172168
if ($value instanceof Pattern) {
173169
return $value->getVariable();
174170
}
175171

172+
if ($value instanceof AnyType) {
173+
return $value;
174+
}
175+
176176
return Literal::literal($value);
177177
}
178178
}

src/Traits/EscapeTrait.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ trait EscapeTrait
4646
private static function escape(string $name): string
4747
{
4848
if ($name === "") {
49-
// Although some versions of Neo4j do not crash when the empty string is used as a name, there is no real
50-
// reason to ever use the empty string as a name
49+
// Although some versions of Neo4j do not crash when the empty string is used as a name,
50+
// there is no real reason to ever use the empty string as a name
5151
throw new InvalidArgumentException("A name cannot be the empty string");
5252
}
5353

0 commit comments

Comments
 (0)