From b67e13302cdaa20f0a2f2d9bb986b2cfa0cfc0da Mon Sep 17 00:00:00 2001 From: Jose Lorenzo Rodriguez Date: Mon, 21 Oct 2013 21:27:12 +0200 Subject: [PATCH] Implementing Query::append(), which will be useful for setting extra options in certain queries, specifically for returning inserted values in postgresql --- Cake/Database/Query.php | 36 +++++++++++++++++++---- Cake/Test/TestCase/Database/QueryTest.php | 19 ++++++++++++ 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Cake/Database/Query.php b/Cake/Database/Query.php index 56fa294d8ab..52f0a2a85ee 100644 --- a/Cake/Database/Query.php +++ b/Cake/Database/Query.php @@ -72,7 +72,8 @@ class Query implements ExpressionInterface, IteratorAggregate { 'order' => null, 'limit' => null, 'offset' => null, - 'union' => [] + 'union' => [], + 'append' => null ]; /** @@ -91,6 +92,7 @@ class Query implements ExpressionInterface, IteratorAggregate { 'order' => ' %s', 'limit' => ' LIMIT %s', 'offset' => ' OFFSET %s', + 'append' => ' %s' ]; /** @@ -280,7 +282,10 @@ public function traverse(callable $visitor) { * @return void */ protected function _traverseSelect(callable $visitor) { - $parts = ['select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', 'offset', 'union']; + $parts = [ + 'select', 'from', 'join', 'where', 'group', 'having', 'order', 'limit', + 'offset', 'union', 'append' + ]; foreach ($parts as $name) { $visitor($this->_parts[$name], $name); } @@ -293,7 +298,7 @@ protected function _traverseSelect(callable $visitor) { * @return void */ protected function _traverseDelete(callable $visitor) { - $parts = ['delete', 'from', 'where']; + $parts = ['delete', 'from', 'where', 'append']; foreach ($parts as $name) { $visitor($this->_parts[$name], $name); } @@ -306,7 +311,7 @@ protected function _traverseDelete(callable $visitor) { * @return void */ protected function _traverseUpdate(callable $visitor) { - $parts = ['update', 'set', 'where']; + $parts = ['update', 'set', 'where', 'append']; foreach ($parts as $name) { $visitor($this->_parts[$name], $name); } @@ -319,7 +324,7 @@ protected function _traverseUpdate(callable $visitor) { * @return void */ protected function _traverseInsert(callable $visitor) { - $parts = ['insert', 'values']; + $parts = ['insert', 'values', 'append']; foreach ($parts as $name) { $visitor($this->_parts[$name], $name); } @@ -1319,6 +1324,27 @@ public function delete($table = null) { return $this; } +/** + * A string or expression that will be appended to the generated query + * + * ### Examples: + * {{{ + * $query->select('id')->where(['author_id' => 1])->append('FOR UPDATE'); + * $query + * ->insert('articles', ['title']) + * ->values(['author_id' => 1]) + * ->append('RETURNING id'); + * }}} + * + * @params string|QueryExpression the expression to be appended + * @return Query + */ + public function append($expression = null) { + $this->_dirty(); + $this->_parts['append'] = $expression; + return $this; + } + /** * Returns the type of this query (select, insert, update, delete) * diff --git a/Cake/Test/TestCase/Database/QueryTest.php b/Cake/Test/TestCase/Database/QueryTest.php index e22928d9877..c92232c17e4 100644 --- a/Cake/Test/TestCase/Database/QueryTest.php +++ b/Cake/Test/TestCase/Database/QueryTest.php @@ -1937,6 +1937,25 @@ public function testBind() { $this->assertEquals($expected, $results->fetchAll('assoc')); } +/** + * Test that append() will actually append a string to a select query + * + * @return void + */ + public function testAppendSelect() { + $query = new Query($this->connection); + $sql = $query + ->select(['id', 'title']) + ->from('articles') + ->where(['id' => 1]) + ->append('FOR UPDATE') + ->sql(); + $this->assertContains('SELECT', $sql); + $this->assertContains('FROM', $sql); + $this->assertContains('WHERE', $sql); + $this->assertEquals('FOR UPDATE', substr($sql, -10)); + } + /** * Assertion for comparing a table's contents with what is in it. *