Skip to content

Commit

Permalink
Allow using arrays in sequence operations without wrapping with Param…
Browse files Browse the repository at this point in the history
…eter; Update changelog
  • Loading branch information
roxblnfk committed Dec 4, 2023
1 parent cc23e1e commit 0abebe3
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

v2.7.0 (04.12.2023)
-------------------
- Add `varbinary` support in MySQL; optimize `size` attribute by @msmakouz (#146)
- Add the ability to use WHERE IN and WHERE NOT IN with array values
The value sequence may contain `FragmentInterface` objets by @msmakouz and @roxblnfk (#147)

v2.6.0 (02.11.2023)
-------------------
- Fix incorrect parameters processing for JOIN subqueries by @smelesh (#133)
Expand Down
6 changes: 5 additions & 1 deletion src/Driver/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,11 @@ protected function condition(QueryParameters $params, Quoter $q, array $context)

$placeholder = '?';
if ($value->isArray()) {
return $this->arrayToInOperator($params, $q, $value->getValue(), $operator === 'IN' || $operator === '=');
return $this->arrayToInOperator($params, $q, $value->getValue(), match (\strtoupper($operator)) {
'IN', '=' => true,
'NOT IN', '!=' => false,
default => throw CompilerException\UnexpectedOperatorException::sequence($operator),
});
}

if ($value->isNull()) {
Expand Down
33 changes: 33 additions & 0 deletions src/Exception/CompilerException/UnexpectedOperatorException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* This file is part of Cycle ORM package.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Cycle\Database\Exception\CompilerException;

use Cycle\Database\Exception\CompilerException;

class UnexpectedOperatorException extends CompilerException
{
/**
* Exception for the value sequence (IN or NOT IN operator).
*
* @param string $operator User-provided operator.
*/
public static function sequence(string $operator): self
{
return new self(
\sprintf(
'Unable to compile query, unexpected operator `%s` provided for a value sequence. %s',
$operator,
'Allowed operators: `IN`, `NOT IN` (or `=`, `!=` as sugar).'
)
);
}
}
15 changes: 5 additions & 10 deletions src/Query/Traits/WhereTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@

use Closure;
use Cycle\Database\Exception\BuilderException;
use Cycle\Database\Injection\FragmentInterface;
use Cycle\Database\Injection\Parameter;
use Cycle\Database\Injection\ParameterInterface;
use Cycle\Database\Injection\FragmentInterface as Fragment;
use Cycle\Database\Injection\ParameterInterface as Parameter;

trait WhereTrait
{
Expand Down Expand Up @@ -108,12 +107,8 @@ abstract protected function registerToken(
*/
protected function whereWrapper(): Closure
{
return static function ($parameter) {
\is_array($parameter) and throw new BuilderException('Arrays must be wrapped with Parameter instance.');

return !$parameter instanceof ParameterInterface && !$parameter instanceof FragmentInterface
? new Parameter($parameter)
: $parameter;
};
return static fn ($parameter) => $parameter instanceof Parameter || $parameter instanceof Fragment
? $parameter
: new \Cycle\Database\Injection\Parameter($parameter);
}
}
50 changes: 35 additions & 15 deletions tests/Database/Functional/Driver/Common/Query/SelectQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Cycle\Database\Tests\Functional\Driver\Common\Query;

use Cycle\Database\Exception\BuilderException;
use Cycle\Database\Exception\CompilerException\UnexpectedOperatorException;
use Cycle\Database\Injection\Expression;
use Cycle\Database\Injection\Fragment;
use Cycle\Database\Injection\Parameter;
Expand Down Expand Up @@ -334,12 +335,13 @@ public function testSelectWithWhereOrWhere(): void

public function testSelectInvalidArrayArgument(): void
{
$this->expectException(BuilderException::class);
$this->expectException(UnexpectedOperatorException::class);

$this->database->select()->distinct()
->from(['users'])
->where('name', 'Anton')
->orWhere('id', 'like', [1, 2, 3]);
->orWhere('id', 'like', [1, 2, 3])
->sqlStatement();
}

public function testSelectWithWhereOrWhereAndWhere(): void
Expand Down Expand Up @@ -1917,16 +1919,16 @@ public function testInOperatorWithBadArrayParameter(): void

public function testBadArrayParameterInShortWhere(): void
{
$this->expectException(BuilderException::class);
$this->expectExceptionMessage('Arrays must be wrapped with Parameter instance');
$this->expectException(UnexpectedOperatorException::class);

$this->database->select()
->from(['users'])
->where(
[
'status' => ['LIKE' => ['active', 'blocked']],
]
);
$this->database
->select()
->from(['users'])
->where(
[
'status' => ['LIKE' => ['active', 'blocked']],
]
)->sqlStatement();
}

public function testGoodArrayParameter(): void
Expand Down Expand Up @@ -2193,12 +2195,21 @@ public function testWhereInWithEqualSpecifiedOperator(): void
'uuid',
'=',
new Parameter(['12345678-1234-1234-1234-123456789012', '12345678-1234-1234-1234-123456789013'])
)->orWhere(
'uuid',
'=',
['23456789-1234-1234-1234-123456789012', '23456789-1234-1234-1234-123456789013']
);

$this->assertSameQuery('SELECT * FROM {users} WHERE {uuid} IN (?, ?)', $select);
$this->assertSameQuery('SELECT * FROM {users} WHERE {uuid} IN (?, ?) OR {uuid} IN (?, ?)', $select);

$this->assertSameParameters(
['12345678-1234-1234-1234-123456789012', '12345678-1234-1234-1234-123456789013'],
[
'12345678-1234-1234-1234-123456789012',
'12345678-1234-1234-1234-123456789013',
'23456789-1234-1234-1234-123456789012',
'23456789-1234-1234-1234-123456789013',
],
$select,
);
}
Expand All @@ -2212,12 +2223,21 @@ public function testWhereInWithNotEqualSpecifiedOperator(): void
'uuid',
'!=',
new Parameter(['12345678-1234-1234-1234-123456789012', '12345678-1234-1234-1234-123456789013'])
)->orWhere(
'uuid',
'!=',
['23456789-1234-1234-1234-123456789012', '23456789-1234-1234-1234-123456789013']
);

$this->assertSameQuery('SELECT * FROM {users} WHERE {uuid} NOT IN (?, ?)', $select);
$this->assertSameQuery('SELECT * FROM {users} WHERE {uuid} NOT IN (?, ?) OR {uuid} NOT IN (?, ?)', $select);

$this->assertSameParameters(
['12345678-1234-1234-1234-123456789012', '12345678-1234-1234-1234-123456789013'],
[
'12345678-1234-1234-1234-123456789012',
'12345678-1234-1234-1234-123456789013',
'23456789-1234-1234-1234-123456789012',
'23456789-1234-1234-1234-123456789013',
],
$select,
);
}
Expand Down

0 comments on commit 0abebe3

Please sign in to comment.