Unverified Commit 22854d27 authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #3833 from BenMorel/sql-part-from

Introduce From class in QueryBuilder
parents 61693e19 b916de26
# Upgrade to 3.0 # Upgrade to 3.0
## BC BREAK: `QueryBuilder::insert()`, `update()` and `delete()` signatures changed
These methods now require the `$table` parameter, and do not support aliases anymore.
## BC BREAK: `OCI8Statement::convertPositionalToNamedPlaceholders()` is removed. ## BC BREAK: `OCI8Statement::convertPositionalToNamedPlaceholders()` is removed.
The `OCI8Statement::convertPositionalToNamedPlaceholders()` method has been extracted to an internal utility class. The `OCI8Statement::convertPositionalToNamedPlaceholders()` method has been extracted to an internal utility class.
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Query;
/**
* @internal
*/
final class From
{
/** @var string */
public $table;
/** @var string|null */
public $alias;
public function __construct(string $table, ?string $alias = null)
{
$this->table = $table;
$this->alias = $alias;
}
}
...@@ -62,6 +62,7 @@ class QueryBuilder ...@@ -62,6 +62,7 @@ class QueryBuilder
'select' => [], 'select' => [],
'distinct' => false, 'distinct' => false,
'from' => [], 'from' => [],
'table' => null,
'join' => [], 'join' => [],
'set' => [], 'set' => [],
'where' => null, 'where' => null,
...@@ -421,7 +422,7 @@ class QueryBuilder ...@@ -421,7 +422,7 @@ class QueryBuilder
$this->state = self::STATE_DIRTY; $this->state = self::STATE_DIRTY;
if ($append) { if ($append) {
if ($sqlPartName === 'orderBy' || $sqlPartName === 'groupBy' || $sqlPartName === 'select' || $sqlPartName === 'set') { if ($sqlPartName === 'orderBy' || $sqlPartName === 'groupBy' || $sqlPartName === 'select' || $sqlPartName === 'set' || $sqlPartName === 'from') {
foreach ($sqlPart as $part) { foreach ($sqlPart as $part) {
$this->sqlParts[$sqlPartName][] = $part; $this->sqlParts[$sqlPartName][] = $part;
} }
...@@ -528,23 +529,15 @@ class QueryBuilder ...@@ -528,23 +529,15 @@ class QueryBuilder
* ->setParameter(':user_id', 1); * ->setParameter(':user_id', 1);
* </code> * </code>
* *
* @param string $delete The table whose rows are subject to the deletion. * @param string $table The table whose rows are subject to the deletion.
* @param string $alias The table alias used in the constructed query.
* *
* @return $this This QueryBuilder instance. * @return $this This QueryBuilder instance.
*/ */
public function delete(?string $delete = null, ?string $alias = null) : self public function delete(string $table) : self
{ {
$this->type = self::DELETE; $this->type = self::DELETE;
if (! $delete) { return $this->add('table', $table);
return $this;
}
return $this->add('from', [
'table' => $delete,
'alias' => $alias,
]);
} }
/** /**
...@@ -558,23 +551,15 @@ class QueryBuilder ...@@ -558,23 +551,15 @@ class QueryBuilder
* ->where('c.id = ?'); * ->where('c.id = ?');
* </code> * </code>
* *
* @param string $update The table whose rows are subject to the update. * @param string $table The table whose rows are subject to the update.
* @param string $alias The table alias used in the constructed query.
* *
* @return $this This QueryBuilder instance. * @return $this This QueryBuilder instance.
*/ */
public function update(?string $update = null, ?string $alias = null) : self public function update(string $table) : self
{ {
$this->type = self::UPDATE; $this->type = self::UPDATE;
if (! $update) { return $this->add('table', $table);
return $this;
}
return $this->add('from', [
'table' => $update,
'alias' => $alias,
]);
} }
/** /**
...@@ -592,19 +577,15 @@ class QueryBuilder ...@@ -592,19 +577,15 @@ class QueryBuilder
* ); * );
* </code> * </code>
* *
* @param string $insert The table into which the rows should be inserted. * @param string $table The table into which the rows should be inserted.
* *
* @return $this This QueryBuilder instance. * @return $this This QueryBuilder instance.
*/ */
public function insert(?string $insert = null) : self public function insert(string $table) : self
{ {
$this->type = self::INSERT; $this->type = self::INSERT;
if (! $insert) { return $this->add('table', $table);
return $this;
}
return $this->add('from', ['table' => $insert]);
} }
/** /**
...@@ -624,10 +605,7 @@ class QueryBuilder ...@@ -624,10 +605,7 @@ class QueryBuilder
*/ */
public function from(string $from, ?string $alias = null) public function from(string $from, ?string $alias = null)
{ {
return $this->add('from', [ return $this->add('from', new From($from, $alias), true);
'table' => $from,
'alias' => $alias,
], true);
} }
/** /**
...@@ -1125,17 +1103,14 @@ class QueryBuilder ...@@ -1125,17 +1103,14 @@ class QueryBuilder
$knownAliases = []; $knownAliases = [];
// Loop through all FROM clauses // Loop through all FROM clauses
/** @var From $from */
foreach ($this->sqlParts['from'] as $from) { foreach ($this->sqlParts['from'] as $from) {
if ($from['alias'] === null || $from['alias'] === $from['table']) { if ($from->alias === null || $from->alias === $from->table) {
$tableSql = $from['table']; $tableSql = $from->table;
$tableReference = $from->table;
/** @var string $tableReference */
$tableReference = $from['table'];
} else { } else {
$tableSql = $from['table'] . ' ' . $from['alias']; $tableSql = $from->table . ' ' . $from->alias;
$tableReference = $from->alias;
/** @var string $tableReference */
$tableReference = $from['alias'];
} }
$knownAliases[$tableReference] = true; $knownAliases[$tableReference] = true;
...@@ -1172,7 +1147,7 @@ class QueryBuilder ...@@ -1172,7 +1147,7 @@ class QueryBuilder
*/ */
private function getSQLForInsert() : string private function getSQLForInsert() : string
{ {
return 'INSERT INTO ' . $this->sqlParts['from']['table'] . return 'INSERT INTO ' . $this->sqlParts['table'] .
' (' . implode(', ', array_keys($this->sqlParts['values'])) . ')' . ' (' . implode(', ', array_keys($this->sqlParts['values'])) . ')' .
' VALUES(' . implode(', ', $this->sqlParts['values']) . ')'; ' VALUES(' . implode(', ', $this->sqlParts['values']) . ')';
} }
...@@ -1182,15 +1157,7 @@ class QueryBuilder ...@@ -1182,15 +1157,7 @@ class QueryBuilder
*/ */
private function getSQLForUpdate() : string private function getSQLForUpdate() : string
{ {
$from = $this->sqlParts['from']; return 'UPDATE ' . $this->sqlParts['table']
if ($from['alias'] === null || $from['alias'] === $from['table']) {
$table = $from['table'];
} else {
$table = $from['table'] . ' ' . $from['alias'];
}
return 'UPDATE ' . $table
. ' SET ' . implode(', ', $this->sqlParts['set']) . ' SET ' . implode(', ', $this->sqlParts['set'])
. ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '');
} }
...@@ -1200,15 +1167,7 @@ class QueryBuilder ...@@ -1200,15 +1167,7 @@ class QueryBuilder
*/ */
private function getSQLForDelete() : string private function getSQLForDelete() : string
{ {
$from = $this->sqlParts['from']; return 'DELETE FROM ' . $this->sqlParts['table'] . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '');
if ($from['alias'] === null || $from['alias'] === $from['table']) {
$table = $from['table'];
} else {
$table = $from['table'] . ' ' . $from['alias'];
}
return 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '');
} }
/** /**
......
...@@ -404,65 +404,27 @@ class QueryBuilderTest extends DbalTestCase ...@@ -404,65 +404,27 @@ class QueryBuilderTest extends DbalTestCase
} }
public function testUpdate() : void public function testUpdate() : void
{
$qb = new QueryBuilder($this->conn);
$qb->update('users', 'u')
->set('u.foo', '?')
->set('u.bar', '?');
self::assertEquals(QueryBuilder::UPDATE, $qb->getType());
self::assertEquals('UPDATE users u SET u.foo = ?, u.bar = ?', (string) $qb);
}
public function testUpdateWithoutAlias() : void
{ {
$qb = new QueryBuilder($this->conn); $qb = new QueryBuilder($this->conn);
$qb->update('users') $qb->update('users')
->set('foo', '?') ->set('foo', '?')
->set('bar', '?'); ->set('bar', '?');
self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); self::assertEquals(QueryBuilder::UPDATE, $qb->getType());
}
public function testUpdateWithMatchingAlias() : void
{
$qb = new QueryBuilder($this->conn);
$qb->update('users', 'users')
->set('foo', '?')
->set('bar', '?');
self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb);
} }
public function testUpdateWhere() : void public function testUpdateWhere() : void
{ {
$qb = new QueryBuilder($this->conn); $qb = new QueryBuilder($this->conn);
$qb->update('users', 'u') $qb->update('users')
->set('u.foo', '?') ->set('foo', '?')
->where('u.foo = ?'); ->where('foo = ?');
self::assertEquals('UPDATE users u SET u.foo = ? WHERE u.foo = ?', (string) $qb);
}
public function testEmptyUpdate() : void
{
$qb = new QueryBuilder($this->conn);
$qb2 = $qb->update();
self::assertEquals(QueryBuilder::UPDATE, $qb->getType()); self::assertEquals('UPDATE users SET foo = ? WHERE foo = ?', (string) $qb);
self::assertSame($qb2, $qb);
} }
public function testDelete() : void public function testDelete() : void
{
$qb = new QueryBuilder($this->conn);
$qb->delete('users', 'u');
self::assertEquals(QueryBuilder::DELETE, $qb->getType());
self::assertEquals('DELETE FROM users u', (string) $qb);
}
public function testDeleteWithoutAlias() : void
{ {
$qb = new QueryBuilder($this->conn); $qb = new QueryBuilder($this->conn);
$qb->delete('users'); $qb->delete('users');
...@@ -471,31 +433,13 @@ class QueryBuilderTest extends DbalTestCase ...@@ -471,31 +433,13 @@ class QueryBuilderTest extends DbalTestCase
self::assertEquals('DELETE FROM users', (string) $qb); self::assertEquals('DELETE FROM users', (string) $qb);
} }
public function testDeleteWithMatchingAlias() : void
{
$qb = new QueryBuilder($this->conn);
$qb->delete('users', 'users');
self::assertEquals(QueryBuilder::DELETE, $qb->getType());
self::assertEquals('DELETE FROM users', (string) $qb);
}
public function testDeleteWhere() : void public function testDeleteWhere() : void
{ {
$qb = new QueryBuilder($this->conn); $qb = new QueryBuilder($this->conn);
$qb->delete('users', 'u') $qb->delete('users')
->where('u.foo = ?'); ->where('u.foo = ?');
self::assertEquals('DELETE FROM users u WHERE u.foo = ?', (string) $qb); self::assertEquals('DELETE FROM users WHERE u.foo = ?', (string) $qb);
}
public function testEmptyDelete() : void
{
$qb = new QueryBuilder($this->conn);
$qb2 = $qb->delete();
self::assertEquals(QueryBuilder::DELETE, $qb->getType());
self::assertSame($qb2, $qb);
} }
public function testInsertValues() : void public function testInsertValues() : void
...@@ -559,15 +503,6 @@ class QueryBuilderTest extends DbalTestCase ...@@ -559,15 +503,6 @@ class QueryBuilderTest extends DbalTestCase
self::assertEquals('INSERT INTO users (foo, bar) VALUES(?, ?)', (string) $qb); self::assertEquals('INSERT INTO users (foo, bar) VALUES(?, ?)', (string) $qb);
} }
public function testEmptyInsert() : void
{
$qb = new QueryBuilder($this->conn);
$qb2 = $qb->insert();
self::assertEquals(QueryBuilder::INSERT, $qb->getType());
self::assertSame($qb2, $qb);
}
public function testGetConnection() : void public function testGetConnection() : void
{ {
$qb = new QueryBuilder($this->conn); $qb = new QueryBuilder($this->conn);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment