Skip to content

Commit f7167c8

Browse files
author
Wout Gevaert
committed
Merge branch 'main' into bugfix-assignment-as-outer-pattern
2 parents f15c024 + 0ca5ff1 commit f7167c8

File tree

8 files changed

+179
-36
lines changed

8 files changed

+179
-36
lines changed

src/Patterns/Path.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ public function named($variable): self
182182
*/
183183
public function withMinHops(int $minHops): self
184184
{
185-
if ($minHops < 1) {
186-
throw new DomainException("minHops cannot be less than 1");
185+
if ($minHops < 0) {
186+
throw new DomainException("minHops cannot be less than 0");
187187
}
188188

189189
if (isset($this->maxHops) && $minHops > $this->maxHops) {

src/Regex.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* Cypher DSL
5+
* Copyright (C) 2021 Wikibase Solutions
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation; either version 2
10+
* of the License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20+
*/
21+
22+
namespace WikibaseSolutions\CypherDSL;
23+
24+
use WikibaseSolutions\CypherDSL\Traits\BooleanTypeTrait;
25+
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\BooleanType;
26+
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\StringType;
27+
28+
/**
29+
* Represents the application of the regex operator.
30+
*
31+
* @see https://neo4j.com/docs/cypher-manual/current/syntax/operators/#query-operators-string
32+
*/
33+
class Regex extends BinaryOperator implements BooleanType
34+
{
35+
use BooleanTypeTrait;
36+
37+
/**
38+
* @inheritDoc
39+
*/
40+
public function __construct(StringType $left, StringType $right)
41+
{
42+
parent::__construct($left, $right);
43+
}
44+
45+
/**
46+
* @inheritDoc
47+
*/
48+
protected function getOperator(): string
49+
{
50+
return "=~";
51+
}
52+
}

src/Traits/ErrorTrait.php

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,34 @@
2121

2222
namespace WikibaseSolutions\CypherDSL\Traits;
2323

24-
use TypeError;
2524
use ReflectionClass;
25+
use TypeError;
2626

2727
/**
2828
* Convenience trait including simple assertions and error reporting functions
2929
*/
30-
trait ErrorTrait {
30+
trait ErrorTrait
31+
{
3132

3233
/**
3334
* Asserts that $userInput is an instance of one of the provided $classNames (polyfill for php 8.0 Union types)
3435
*
35-
* @param string $varName The name of the userinput variable, to be used in the error message.
36-
* @param string|string[] $classNames The classnames that should be tested against
37-
* @param mixed $userInput The input that should be tested
36+
* @param string $varName The name of the userinput variable, to be used in the error message.
37+
* @param string|string[] $classNames The classnames that should be tested against
38+
* @param mixed $userInput The input that should be tested
3839
* @throws TypeError
3940
*/
40-
private function assertClass(string $varName, $classNames, $userInput) : void {
41+
private function assertClass(string $varName, $classNames, $userInput): void
42+
{
4143
if (!is_array($classNames)) {
4244
$classNames = [$classNames];
4345
}
46+
4447
foreach ($classNames as $class) {
4548
if ($userInput instanceof $class)
4649
return;
4750
}
51+
4852
throw new TypeError(
4953
$this->getTypeErrorText(
5054
$varName,
@@ -57,38 +61,41 @@ private function assertClass(string $varName, $classNames, $userInput) : void {
5761
/**
5862
* Give a nice error message about $userInput not being an object with one of the $classNames types.
5963
*
60-
* @param string $varname The name of the variable to be used in the message (without trailing '$')
61-
* @param array $classNames The classnames that should be mentioned in the message
62-
* @param mixed $userInput The input that has been given.
64+
* @param string $varName The name of the variable to be used in the message (without trailing '$')
65+
* @param array $classNames The class names that should be mentioned in the message
66+
* @param mixed $userInput The input that has been given
67+
* @return string
6368
*/
64-
private function getTypeErrorText(
65-
string $varName,
66-
array $classNames,
67-
$userInput
68-
) : string {
69-
return
70-
"\$$varName should be a " .
71-
implode(' or ', $classNames) . " object, " .
72-
$this->getUserInputInfo($userInput) . " given.";
69+
private function getTypeErrorText(string $varName, array $classNames, $userInput): string
70+
{
71+
return sprintf(
72+
'$%s should be a %s object, %s given.',
73+
$varName,
74+
implode(' or ', $classNames),
75+
$this->getUserInputInfo($userInput)
76+
);
7377
}
7478

7579
/**
7680
* Simple function to determine what $userInput is.
7781
*
7882
* @param mixed $userInput
79-
* @return string A description of $userInput.
83+
* @return string A description of $userInput
8084
*/
81-
private function getUserInputInfo($userInput) : string {
82-
$info = gettype( $userInput );
83-
if ( $info === 'object' ) {
85+
private function getUserInputInfo($userInput): string
86+
{
87+
$info = gettype($userInput);
88+
89+
if ($info === 'object') {
8490
if ((new ReflectionClass($userInput))->isAnonymous()) {
8591
$info = 'anonymous class instance';
8692
} else {
87-
$info = get_class( $userInput );
93+
$info = get_class($userInput);
8894
}
8995
} elseif (is_scalar($userInput)) {
90-
$info .= ' "' . (string) $userInput . '"';
96+
$info .= ' "' . (string)$userInput . '"';
9197
}
98+
9299
return $info;
93100
}
94101
}

src/Traits/StringTypeTrait.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
use WikibaseSolutions\CypherDSL\Contains;
2525
use WikibaseSolutions\CypherDSL\EndsWith;
26+
use WikibaseSolutions\CypherDSL\Regex;
2627
use WikibaseSolutions\CypherDSL\StartsWith;
2728
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\StringType;
2829

@@ -65,4 +66,15 @@ public function startsWith(StringType $right): StartsWith
6566
{
6667
return new StartsWith($this, $right);
6768
}
69+
70+
/**
71+
* Perform a regex comparison with the given expression.
72+
*
73+
* @param StringType $right
74+
* @return Regex
75+
*/
76+
public function regex(StringType $right): Regex
77+
{
78+
return new Regex($this, $right);
79+
}
6880
}

src/Types/PropertyTypes/StringType.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
use WikibaseSolutions\CypherDSL\Contains;
2525
use WikibaseSolutions\CypherDSL\EndsWith;
26+
use WikibaseSolutions\CypherDSL\Regex;
2627
use WikibaseSolutions\CypherDSL\StartsWith;
2728

2829
/**
@@ -53,4 +54,12 @@ public function endsWith(StringType $right): EndsWith;
5354
* @return StartsWith
5455
*/
5556
public function startsWith(StringType $right): StartsWith;
57+
58+
/**
59+
* Perform a regex comparison with the given expression.
60+
*
61+
* @param StringType $right
62+
* @return Regex
63+
*/
64+
public function regex(StringType $right): Regex;
5665
}

tests/Unit/Patterns/RelationshipTest.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -378,15 +378,6 @@ public function testMinHopsGreaterThanMaxHops()
378378
$r->withMinHops(100);
379379
}
380380

381-
public function testMinHopsLessThanOne()
382-
{
383-
$r = new Path($this->a, $this->b, Path::DIR_RIGHT);
384-
385-
$this->expectException(DomainException::class);
386-
387-
$r->withMinHops(0);
388-
}
389-
390381
public function testMinHopsLessThanZero()
391382
{
392383
$r = new Path($this->a, $this->b, Path::DIR_RIGHT);
@@ -558,4 +549,4 @@ public function provideWithMultipleTypesData(): array
558549
['a', ['a', 'b'], [], Path::DIR_LEFT, "(a)<-[a:a|b {}]-(b)"]
559550
];
560551
}
561-
}
552+
}

tests/Unit/RegexTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* Cypher DSL
5+
* Copyright (C) 2021 Wikibase Solutions
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation; either version 2
10+
* of the License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20+
*/
21+
22+
namespace WikibaseSolutions\CypherDSL\Tests\Unit;
23+
24+
use PHPUnit\Framework\TestCase;
25+
use TypeError;
26+
use WikibaseSolutions\CypherDSL\Contains;
27+
use WikibaseSolutions\CypherDSL\Regex;
28+
use WikibaseSolutions\CypherDSL\Types\AnyType;
29+
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\StringType;
30+
31+
/**
32+
* @covers \WikibaseSolutions\CypherDSL\Regex
33+
*/
34+
class RegexTest extends TestCase
35+
{
36+
use TestHelper;
37+
38+
public function testToQuery()
39+
{
40+
$regex = new Regex($this->getQueryConvertableMock(StringType::class, "a"), $this->getQueryConvertableMock(StringType::class, "b"));
41+
42+
$this->assertSame("(a =~ b)", $regex->toQuery());
43+
}
44+
45+
public function testCannotBeNested()
46+
{
47+
$regex = new Regex($this->getQueryConvertableMock(StringType::class, "a"), $this->getQueryConvertableMock(StringType::class, "b"));
48+
49+
$this->expectException(TypeError::class);
50+
51+
$regex = new Regex($regex, $regex);
52+
53+
$regex->toQuery();
54+
}
55+
56+
public function testDoesNotAcceptAnyTypeAsOperands()
57+
{
58+
$this->expectException(TypeError::class);
59+
60+
$regex = new Regex($this->getQueryConvertableMock(AnyType::class, "a"), $this->getQueryConvertableMock(AnyType::class, "b"));
61+
62+
$regex->toQuery();
63+
}
64+
}

tests/Unit/Traits/StringTypeTraitTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use PHPUnit\Framework\TestCase;
2626
use WikibaseSolutions\CypherDSL\Contains;
2727
use WikibaseSolutions\CypherDSL\EndsWith;
28+
use WikibaseSolutions\CypherDSL\Regex;
2829
use WikibaseSolutions\CypherDSL\StartsWith;
2930
use WikibaseSolutions\CypherDSL\Tests\Unit\TestHelper;
3031
use WikibaseSolutions\CypherDSL\Types\PropertyTypes\StringType;
@@ -72,4 +73,11 @@ public function testStartsWith()
7273

7374
$this->assertInstanceOf(StartsWith::class, $startsWith);
7475
}
76+
77+
public function testRegex()
78+
{
79+
$regex = $this->a->regex($this->b);
80+
81+
$this->assertInstanceOf(Regex::class, $regex);
82+
}
7583
}

0 commit comments

Comments
 (0)