Skip to content

Can't limit delete or update in the query builder. #66

Merged
merged 2 commits into from Feb 21, 2013
View
68 system/classes/database/query/builder.php
@@ -132,6 +132,8 @@ public function limit($start, $end = null) {
$part = [$start];
if (!is_null($end)) $part[] = $end;
+ if (!isset($this->query_opts['limit'])) $this->query_opts['limit'] = [];
+
$this->query_opts['limit'] = array_merge($this->query_opts['limit'], $part);
return $this;
@@ -153,9 +155,9 @@ public function set($key, $value) {
/* Utility functions for the subclass */
- protected function extract() {
+ protected function extract_select() {
- $options = call_user_func_array([$this, 'extract_shuffle'], func_get_args());
+ $options = call_user_func_array([$this, 'extract_shuffle_select'], func_get_args());
$args = [];
$required = ['table'];
@@ -189,7 +191,67 @@ protected function extract() {
return $args;
}
- protected function extract_shuffle($table = null, $options = []) {
+ protected function extract_update() {
+
+ $args = $this->extract_shuffle([
+ 'table'
+ ], [
+ 'table',
+ 'data',
+ 'where',
+ 'conds',
+ 'limit',
+ 'order'
+ ], func_get_args());
+
+ if (isset($args['conds'])) {
+ $args['where'] = $args['conds'];
+ unset($args['conds']);
+ }
+
+ return $args;
+ }
+
+ protected function extract_delete() {
+ $args = $this->extract_shuffle([
+ 'table'
+ ], [
+ 'table',
+ 'where',
+ 'conds',
+ 'limit',
+ 'order'
+ ], func_get_args());
+
+ if (isset($args['conds'])) {
+ $args['where'] = $args['conds'];
+ unset($args['conds']);
+ }
+
+ return $args;
+ }
+
+ protected function extract_shuffle($required, $keys, $options) {
+ if (count($options) === 1 && is_array(reset($options)) && is_hash(reset($options))) {
+ $args = reset($options);
+ } else {
+ $args = [];
+
+ foreach ($keys as $i => $key) {
+ $args[$key] = isset($options[$i]) ? $options[$i] : null;
+ }
+ }
+
+ foreach ($required as $req) {
+ if (!isset($args[$req])) {
+ throw new InvalidArgumentException('Missing ' . $req);
+ }
+ }
+
+ return $args;
+ }
+
+ protected function extract_shuffle_select($table = null, $options = []) {
// Argument shuffling
if (is_array($table)) {
$options = $table;
View
4 system/classes/database/query/builders/interface.php
@@ -8,7 +8,7 @@
interface DatabaseQueryBuilderInterface {
public function select();
public function insert($table, $data);
- public function update($table, $data, $where = []);
+ public function update();
public function structure($table);
- public function delete($table);
+ public function delete();
}
View
110 system/classes/database/query/builders/sql.php
@@ -7,37 +7,25 @@
*/
class DatabaseQueryBuilderSQL extends DatabaseQueryBuilder {
- protected $operators = ['=', '>', '<', '<>', '!='];
+ protected $operators = ['=', '>', '<', '<>', '!='];
protected $joins = ['AND', 'OR'];
protected $default_meta = ['connector' => 'AND', 'operator' => '='];
public function select() {
$args = func_get_args();
- $options = call_user_func_array([$this, 'extract'], $args);
+ $options = call_user_func_array([$this, 'extract_select'], $args);
- if ((count($args) === 1 && is_string(reset($args))) || $this->chained()) {
- return $this->start('select', recursive_overwrite($this->query_opts, $options));
+ if ($this->chained($args)) {
+ return $this->start('select', $options);
}
- $options = call_user_func_array([$this, 'extract'], $args);
extract($options);
if (!is_array($table)) {
$table = [$table];
}
- $parts = [];
- foreach ($table as $key => $val) {
- $col = $this->backtick(is_int($key) ? $val : $key);
-
- if (!is_int($key)) {
- $col .= ' AS ' . $this->backtick($val);
- }
-
- $parts[] = $col;
- }
-
- $table = implode(',', $parts);
+ $table = $this->table($table);
$vals = $this->backtick($vals);
@@ -110,84 +98,61 @@ public function insert($table, $data = null) {
return $query;
}
- public function update($table, $data = null, $where = null) {
-
- $default = [
- 'table' => null,
- 'data' => [],
- 'conds' => []
- ];
-
- $options = [];
-
- if (is_array($table)) {
- $options = $table;
- } else {
- $options['table'] = $table;
- }
+ public function update() {
- if (!is_null($data)) {
- $options['data'] = $data;
- }
+ $args = func_get_args();
+ $options = call_user_func_array([$this, 'extract_update'], $args);
- if (!is_null($where)) {
- $options['conds'] = $where;
+ if ($this->chained($args)) {
+ $this->start('update', $options);
+ return $this;
}
- $options = recursive_overwrite($default, $options);
- list($table, $data, $where) = array_values($options);
-
-
- if ($this->chained(func_get_args())) {
- return $this->start('update', $options);
- }
+ extract($options);
if (count($data) === 0) {
throw new InvalidArgumentException('You must pass data to set');
}
- $table = $this->backtick($table);
+ if (!is_array($table)) {
+ $table = [$table];
+ }
+
+ $table = $this->table($table);
$keys = $this->backtick(array_keys($data));
$data = $this->escape($data);
$query = 'UPDATE ' . $table . ' SET ' . $this->pairs($keys, $data);
if (count($where) > 0) $query .= ' ' . $this->where_array($where);
+ if (count($order) > 0) $query .= ' ' . $this->order_array($order);
+ if (count($limit) > 0) $query .= ' ' . $this->limit_array($limit);
$query .= ';';
return $query;
}
- public function delete($table, $where = null) {
+ public function delete() {
- $defaults = [
- 'table' => null,
- 'conds' => []
- ];
-
- $options = [];
-
- if (is_array($table)) {
- $options = $table;
- } else {
- $options['table'] = $table;
- }
+ $args = func_get_args();
+ $options = call_user_func_array([$this, 'extract_delete'], $args);
- if (!is_null($where)) {
- $options['conds'] = $where;
+ if ($this->chained($args)) {
+ return $this->start('delete', $options);
}
- $options = recursive_overwrite($defaults, $options);
- list($table, $where) = array_values($options);
+ extract($options);
- if ($this->chained(func_get_args())) {
- return $this->start('delete', $options);
+ if (!is_array($table)) {
+ $table = [$table];
}
- $table = $this->backtick($table);
+ $table = $this->table($table);
$query = 'DELETE FROM ' . $table;
if (count($where) > 0) $query .= ' ' . $this->where_array($where);
+ if (count($order) > 0) $query .= ' ' . $this->order_array($order);
+ if (count($limit) > 0) $query .= ' ' . $this->limit_array($limit);
$query .= ';';
@@ -437,4 +402,19 @@ protected function escape($value) {
return $value;
}
+
+ protected function table($table) {
+ $parts = [];
+ foreach ($table as $key => $val) {
+ $col = $this->backtick(is_int($key) ? $val : $key);
+
+ if (!is_int($key)) {
+ $col .= ' AS ' . $this->backtick($val);
+ }
+
+ $parts[] = $col;
+ }
+
+ return implode(',', $parts);
+ }
}
View
122 tests/DatabaseQueryBuilderSQLTest.php
@@ -288,6 +288,56 @@ public function testUpdate() {
$this->assertEquals('UPDATE `users` SET `name` = \'Bob\' WHERE `name` = \'Paul\';', $sql);
}
+ public function testUpdateWithLimit() {
+ $sql = $this->builder->update([
+ 'table' => 'users',
+ 'data' => [
+ 'name' => 'Bob'
+ ],
+ 'where' => [
+ 'name' => 'Paul'
+ ],
+ 'limit' => [23, 43]
+ ]);
+
+ $this->assertEquals('UPDATE `users` SET `name` = \'Bob\' WHERE `name` = \'Paul\' LIMIT 23, 43;', $sql);
+ }
+
+ public function testUpdateWithOrder() {
+ $sql = $this->builder->update([
+ 'table' => 'users',
+ 'data' => [
+ 'name' => 'Bob'
+ ],
+ 'where' => [
+ 'name' => 'Paul'
+ ],
+ 'order' => [
+ ['name', 'DESC']
+ ]
+ ]);
+
+ $this->assertEquals('UPDATE `users` SET `name` = \'Bob\' WHERE `name` = \'Paul\' ORDER BY `name` DESC;', $sql);
+ }
+
+ public function testUpdateWithOrderAndLimit() {
+ $sql = $this->builder->update([
+ 'table' => 'users',
+ 'data' => [
+ 'name' => 'Bob'
+ ],
+ 'where' => [
+ 'name' => 'Paul'
+ ],
+ 'order' => [
+ ['name', 'DESC']
+ ],
+ 'limit' => [23, 43]
+ ]);
+
+ $this->assertEquals('UPDATE `users` SET `name` = \'Bob\' WHERE `name` = \'Paul\' ORDER BY `name` DESC LIMIT 23, 43;', $sql);
+ }
+
public function testUpdateWithoutWhere() {
$sql = $this->builder->update('users', [
'name' => 'Bob'
@@ -320,6 +370,21 @@ public function testUpdateChained() {
$this->assertEquals('UPDATE `users` SET `name` = \'nat\' WHERE `name` = \'bob\';', $sql);
}
+ public function testUpdateChainedOrder() {
+ $sql = $this->builder->start()->update('users')->set('name', 'nat')->where('name', 'bob')->order('name', 'desc')->end();
+ $this->assertEquals('UPDATE `users` SET `name` = \'nat\' WHERE `name` = \'bob\' ORDER BY `name` DESC;', $sql);
+ }
+
+ public function testUpdateChainedLimit() {
+ $sql = $this->builder->start()->update('users')->set('name', 'nat')->where('name', 'bob')->limit(22, 56)->end();
+ $this->assertEquals('UPDATE `users` SET `name` = \'nat\' WHERE `name` = \'bob\' LIMIT 22, 56;', $sql);
+ }
+
+ public function testUpdateChainedOrderAndLimit() {
+ $sql = $this->builder->start()->update('users')->set('name', 'nat')->where('name', 'bob')->order('name', 'desc')->limit(22, 56)->end();
+ $this->assertEquals('UPDATE `users` SET `name` = \'nat\' WHERE `name` = \'bob\' ORDER BY `name` DESC LIMIT 22, 56;', $sql);
+ }
+
public function testUpdateChainedWithoutStart() {
$sql = $this->builder->update('users')->set('name', 'nat')->where('name', 'bob')->end();
$this->assertEquals('UPDATE `users` SET `name` = \'nat\' WHERE `name` = \'bob\';', $sql);
@@ -351,6 +416,48 @@ public function testDelete() {
$this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\';', $sql);
}
+ public function testDeleteWithOrder() {
+ $sql = $this->builder->delete([
+ 'table' => 'users',
+ 'where' => [
+ 'name' => 'Harry'
+ ],
+ 'order' => [
+ ['name', 'DESC']
+ ]
+ ]);
+
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' ORDER BY `name` DESC;', $sql);
+ }
+
+ public function testDeleteWithLimit() {
+ $sql = $this->builder->delete([
+ 'table' => 'users',
+ 'where' => [
+ 'name' => 'Harry'
+ ],
+ 'order' => [
+ ['name', 'DESC']
+ ],
+ 'limit' => [26, 50]
+ ]);
+
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' ORDER BY `name` DESC LIMIT 26, 50;', $sql);
+ }
+
+ public function testDeleteWithOrderAndLimit() {
+ $sql = $this->builder->delete([
+ 'table' => 'users',
+ 'where' => [
+ 'name' => 'Harry'
+ ],
+ 'limit' => [26, 50]
+ ]);
+
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' LIMIT 26, 50;', $sql);
+ }
+
+
public function testDeleteChained() {
$sql = $this->builder->start()->delete('users')->where('name', 'Harry')->end();
$this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\';', $sql);
@@ -361,6 +468,21 @@ public function testDeleteChainedWithoutStart() {
$this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\';', $sql);
}
+ public function testDeleteChainedWithOrder() {
+ $sql = $this->builder->start()->delete('users')->where('name', 'Harry')->order('name', 'desc')->end();
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' ORDER BY `name` DESC;', $sql);
+ }
+
+ public function testDeleteChainedWithLimit() {
+ $sql = $this->builder->start()->delete('users')->where('name', 'Harry')->limit(22, 30)->end();
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' LIMIT 22, 30;', $sql);
+ }
+
+ public function testDeleteChainedWithLimitAndOrder() {
+ $sql = $this->builder->start()->delete('users')->where('name', 'Harry')->order('name', 'desc')->limit(22, 30)->end();
+ $this->assertEquals('DELETE FROM `users` WHERE `name` = \'Harry\' ORDER BY `name` DESC LIMIT 22, 30;', $sql);
+ }
+
public function testDeleteWithComplexWhere() {
$sql = $this->builder->delete('users', [
'logins' => Database::where_gt(5)
Something went wrong with that request. Please try again.