Skip to content

Commit 97698eb

Browse files
committed
Adding support for UNION queries
1 parent b9e4815 commit 97698eb

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

src/SQLParser/Query/StatementFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ public static function toObject(array $desc)
8787
}
8888

8989
return $select;
90+
} elseif (isset($desc['UNION'])) {
91+
$selects = array_map([self::class, 'toObject'], $desc['UNION']);
92+
93+
return new Union($selects);
9094
} else {
9195
throw new \BadMethodCallException('Unknown query');
9296
}

src/SQLParser/Query/Union.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
namespace SQLParser\Query;
4+
5+
use Doctrine\DBAL\Connection;
6+
use Mouf\MoufInstanceDescriptor;
7+
use SQLParser\Node\NodeFactory;
8+
use Mouf\MoufManager;
9+
use SQLParser\Node\NodeInterface;
10+
use SQLParser\Node\Traverser\NodeTraverser;
11+
use SQLParser\Node\Traverser\VisitorInterface;
12+
13+
/**
14+
* This class represents a <code>UNION</code> query. You can use it to generate a SQL query statement
15+
* using the <code>toSql</code> method.
16+
* You can use the <code>QueryResult</code> class if you want to run the query directly.
17+
*
18+
* @author David Négrier <[email protected]>
19+
*/
20+
class Union implements StatementInterface, NodeInterface
21+
{
22+
/**
23+
* @var array|Select[]
24+
*/
25+
private $selects;
26+
27+
/**
28+
* Union constructor.
29+
* @param Select[] $selects
30+
*/
31+
public function __construct(array $selects)
32+
{
33+
$this->selects = $selects;
34+
}
35+
36+
/**
37+
* @param MoufManager $moufManager
38+
*
39+
* @return MoufInstanceDescriptor
40+
*/
41+
public function toInstanceDescriptor(MoufManager $moufManager)
42+
{
43+
$instanceDescriptor = $moufManager->createInstance(get_called_class());
44+
$instanceDescriptor->getProperty('selects')->setValue(NodeFactory::nodeToInstanceDescriptor($this->selects, $moufManager));
45+
46+
return $instanceDescriptor;
47+
}
48+
49+
/**
50+
* Configure the $instanceDescriptor describing this object (it must already exist as a Mouf instance).
51+
*
52+
* @param MoufManager $moufManager
53+
*
54+
* @return MoufInstanceDescriptor
55+
*/
56+
public function overwriteInstanceDescriptor($name, MoufManager $moufManager)
57+
{
58+
//$name = $moufManager->findInstanceName($this);
59+
$instanceDescriptor = $moufManager->getInstanceDescriptor($name);
60+
$instanceDescriptor->getProperty('selects')->setValue(NodeFactory::nodeToInstanceDescriptor($this->selects, $moufManager));
61+
62+
return $instanceDescriptor;
63+
}
64+
65+
/**
66+
* Renders the object as a SQL string.
67+
*
68+
* @param array $parameters
69+
* @param Connection $dbConnection
70+
* @param int|number $indent
71+
* @param int $conditionsMode
72+
*
73+
* @return string
74+
*/
75+
public function toSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY)
76+
{
77+
$selectsSql = array_map(function(Select $select) use ($parameters, $dbConnection, $indent, $conditionsMode) {
78+
return $select->toSql($parameters, $dbConnection, $indent, $conditionsMode);
79+
}, $this->selects);
80+
81+
$sql = implode(' UNION ', $selectsSql);
82+
83+
return $sql;
84+
}
85+
86+
/**
87+
* Walks the tree of nodes, calling the visitor passed in parameter.
88+
*
89+
* @param VisitorInterface $visitor
90+
*/
91+
public function walk(VisitorInterface $visitor)
92+
{
93+
$node = $this;
94+
$result = $visitor->enterNode($node);
95+
if ($result instanceof NodeInterface) {
96+
$node = $result;
97+
}
98+
if ($result !== NodeTraverser::DONT_TRAVERSE_CHILDREN) {
99+
$this->walkChildren($this->columns, $visitor);
100+
$this->walkChildren($this->from, $visitor);
101+
$this->walkChildren($this->where, $visitor);
102+
$this->walkChildren($this->group, $visitor);
103+
$this->walkChildren($this->having, $visitor);
104+
$this->walkChildren($this->order, $visitor);
105+
}
106+
107+
return $visitor->leaveNode($node);
108+
}
109+
110+
private function walkChildren(&$children, VisitorInterface $visitor)
111+
{
112+
if ($children) {
113+
if (is_array($children)) {
114+
foreach ($children as $key => $operand) {
115+
if ($operand) {
116+
$result2 = $operand->walk($visitor);
117+
if ($result2 === NodeTraverser::REMOVE_NODE) {
118+
unset($children[$key]);
119+
} elseif ($result2 instanceof NodeInterface) {
120+
$children[$key] = $result2;
121+
}
122+
}
123+
}
124+
} else {
125+
$result2 = $children->walk($visitor);
126+
if ($result2 === NodeTraverser::REMOVE_NODE) {
127+
$children = null;
128+
} elseif ($result2 instanceof NodeInterface) {
129+
$children = $result2;
130+
}
131+
}
132+
}
133+
}
134+
}

tests/Mouf/Database/MagicQueryTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ public function testStandardSelect()
158158

159159
$sql = 'SELECT COUNT(DISTINCT a, b) FROM users';
160160
$this->assertEquals('SELECT COUNT(DISTINCT a, b) FROM users', self::simplifySql($magicQuery->build($sql)));
161+
162+
$sql = 'SELECT a FROM users UNION SELECT a FROM users';
163+
$this->assertEquals('SELECT a FROM users UNION SELECT a FROM users', self::simplifySql($magicQuery->build($sql)));
161164
}
162165

163166
/**

0 commit comments

Comments
 (0)