Skip to content

Commit 44ba318

Browse files
authored
Merge pull request #59 from moufmouf/not_in_issue
NOT IN parameters are not adding parenthesis automatically
2 parents bc9b2f5 + 22470bb commit 44ba318

File tree

5 files changed

+80
-50
lines changed

5 files changed

+80
-50
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,10 @@ jobs:
3535
- *composerupdate
3636
script:
3737
- *phpunit
38+
- stage: test
39+
php: 7.3
40+
env: PREFER_LOWEST=""
41+
before_script:
42+
- *composerupdate
43+
script:
44+
- *phpunit
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace SQLParser\Node;
4+
use Doctrine\DBAL\Connection;
5+
use Mouf\Database\MagicQueryException;
6+
7+
/**
8+
* This class represents an In operation in an SQL expression.
9+
*
10+
* @author David Négrier <[email protected]>
11+
*/
12+
abstract class AbstractInListOperator extends AbstractTwoOperandsOperator
13+
{
14+
protected function getSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY, bool $extrapolateParameters = true)
15+
{
16+
$rightOperand = $this->getRightOperand();
17+
18+
$rightOperand = $this->refactorParameterToExpression($rightOperand);
19+
20+
$this->setRightOperand($rightOperand);
21+
22+
$parameterNode = $this->getParameter($rightOperand);
23+
24+
if ($parameterNode !== null) {
25+
if (!isset($parameters[$parameterNode->getName()])) {
26+
throw new MagicQueryException("Missing parameter '" . $parameterNode->getName() . "' for 'IN' operand.");
27+
}
28+
if ($parameters[$parameterNode->getName()] === []) {
29+
return "FALSE";
30+
}
31+
}
32+
33+
return parent::getSql($parameters, $dbConnection, $indent, $conditionsMode, $extrapolateParameters);
34+
}
35+
36+
protected function refactorParameterToExpression(NodeInterface $rightOperand): NodeInterface
37+
{
38+
if ($rightOperand instanceof Parameter) {
39+
$expression = new Expression();
40+
$expression->setSubTree([$rightOperand]);
41+
$expression->setBrackets(true);
42+
return $expression;
43+
}
44+
return $rightOperand;
45+
}
46+
47+
protected function getParameter(NodeInterface $operand): ?Parameter
48+
{
49+
if (!$operand instanceof Expression) {
50+
return null;
51+
}
52+
$subtree = $operand->getSubTree();
53+
if (!isset($subtree[0])) {
54+
return null;
55+
}
56+
if ($subtree[0] instanceof Parameter) {
57+
return $subtree[0];
58+
}
59+
return null;
60+
}
61+
}

src/SQLParser/Node/In.php

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
* @author David Négrier <[email protected]>
1111
*/
12-
class In extends AbstractTwoOperandsOperator
12+
class In extends AbstractInListOperator
1313
{
1414
/**
1515
* Returns the symbol for this operator.
@@ -20,52 +20,4 @@ protected function getOperatorSymbol()
2020
{
2121
return 'IN';
2222
}
23-
24-
protected function getSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY, bool $extrapolateParameters = true)
25-
{
26-
$rightOperand = $this->getRightOperand();
27-
28-
$rightOperand = $this->refactorParameterToExpression($rightOperand);
29-
30-
$this->setRightOperand($rightOperand);
31-
32-
$parameterNode = $this->getParameter($rightOperand);
33-
34-
if ($parameterNode !== null) {
35-
if (!isset($parameters[$parameterNode->getName()])) {
36-
throw new MagicQueryException("Missing parameter '" . $parameterNode->getName() . "' for 'IN' operand.");
37-
}
38-
if ($parameters[$parameterNode->getName()] === []) {
39-
return "FALSE";
40-
}
41-
}
42-
43-
return parent::getSql($parameters, $dbConnection, $indent, $conditionsMode, $extrapolateParameters);
44-
}
45-
46-
protected function refactorParameterToExpression(NodeInterface $rightOperand): NodeInterface
47-
{
48-
if ($rightOperand instanceof Parameter) {
49-
$expression = new Expression();
50-
$expression->setSubTree([$rightOperand]);
51-
$expression->setBrackets(true);
52-
return $expression;
53-
}
54-
return $rightOperand;
55-
}
56-
57-
protected function getParameter(NodeInterface $operand): ?Parameter
58-
{
59-
if (!$operand instanceof Expression) {
60-
return null;
61-
}
62-
$subtree = $operand->getSubTree();
63-
if (!isset($subtree[0])) {
64-
return null;
65-
}
66-
if ($subtree[0] instanceof Parameter) {
67-
return $subtree[0];
68-
}
69-
return null;
70-
}
7123
}

src/SQLParser/Node/NotIn.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
* @author David Négrier <[email protected]>
99
*/
10-
class NotIn extends AbstractTwoOperandsOperator
10+
class NotIn extends AbstractInListOperator
1111
{
1212
/**
1313
* Returns the symbol for this operator.

tests/Mouf/Database/MagicQueryTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ public function testStandardSelect()
7878
$sql = 'SELECT * FROM users WHERE status IN :statuses';
7979
$this->assertEquals('SELECT * FROM users WHERE status IN (\'1\',\'2\')', self::simplifySql($magicQuery->build($sql, ['statuses' => [1, 2]])));
8080

81+
$sql = 'SELECT * FROM users WHERE status not in :status';
82+
$this->assertEquals("SELECT * FROM users WHERE status NOT IN ('2','4')", self::simplifySql($magicQuery->build($sql, ['status' => [2, 4]])));
83+
84+
$sql = 'SELECT * FROM users WHERE status not in (:status)';
85+
$this->assertEquals("SELECT * FROM users WHERE status NOT IN ('2','4')", self::simplifySql($magicQuery->build($sql, ['status' => [2, 4]])));
86+
8187
$sql = 'SELECT * FROM myTable where someField BETWEEN :value1 AND :value2';
8288
$this->assertEquals("SELECT * FROM myTable WHERE someField BETWEEN '2' AND '4'", self::simplifySql($magicQuery->build($sql, ['value1' => 2, 'value2' => 4])));
8389
$this->assertEquals("SELECT * FROM myTable WHERE someField >= '2'", self::simplifySql($magicQuery->build($sql, ['value1' => 2])));
@@ -433,5 +439,9 @@ public function testBuildPreparedStatement()
433439
// Let's check that MagicQuery is cleverly adding parenthesis if the user forgot those in the "IN" statement.
434440
$sql = 'SELECT id FROM users WHERE status IN :status';
435441
$this->assertEquals("SELECT id FROM users WHERE status IN (:status)", self::simplifySql($magicQuery->buildPreparedStatement($sql, ['status' => [1,2]])));
442+
443+
// Let's check that MagicQuery is cleverly adding parenthesis if the user forgot those in the "NOT IN" statement.
444+
$sql = 'SELECT id FROM users WHERE status NOT IN :status';
445+
$this->assertEquals("SELECT id FROM users WHERE status NOT IN (:status)", self::simplifySql($magicQuery->buildPreparedStatement($sql, ['status' => [1,2]])));
436446
}
437447
}

0 commit comments

Comments
 (0)