From cd6629ad23ba9468002d063483e9c49b59e200aa Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Fri, 23 Jan 2009 08:07:37 +0000 Subject: Add support for parenthetical grouping to Database queries. Turns out that this is something they kind of want for Kohana :-) Upstream ticket for this change: http://dev.kohanaphp.com/ticket/1070 --- core/libraries/MY_Database.php | 45 ++++++++++++++++++++++ core/libraries/MY_ORM.php | 30 +++++++++++++++ core/tests/Database_Test.php | 86 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 core/libraries/MY_Database.php create mode 100644 core/libraries/MY_ORM.php create mode 100644 core/tests/Database_Test.php (limited to 'core') diff --git a/core/libraries/MY_Database.php b/core/libraries/MY_Database.php new file mode 100644 index 00000000..f5e412a6 --- /dev/null +++ b/core/libraries/MY_Database.php @@ -0,0 +1,45 @@ +where[] = "("; + return $this; + } + + public function close_paren() { + // Search backwards for the last opening paren and resolve it + $i = count($this->where) - 1; + $this->where[$i] .= ")"; + while (--$i >= 0) { + if ($this->where[$i] == "(") { + // Remove the paren from the where clauses, and add it to the right of the operator of the + // next where clause. If removing the paren makes the next where clause the first element + // in the where list, then the operator shouldn't be there. It's there because we + // calculate whether or not we need an operator based on the number of where clauses, and + // the open paren seems like a where clause even though it isn't. + array_splice($this->where, $i, 1); + $this->where[$i] = preg_replace("/^(AND|OR) /", $i ? "\\1 (" : "(", $this->where[$i]); + return $this; + } + } + + throw new Kohana_Database_Exception('database.missing_open_paren'); + } +} \ No newline at end of file diff --git a/core/libraries/MY_ORM.php b/core/libraries/MY_ORM.php new file mode 100644 index 00000000..f0bca39b --- /dev/null +++ b/core/libraries/MY_ORM.php @@ -0,0 +1,30 @@ +db->open_paren(); + return $this; + } + + public function close_paren() { + $this->db->close_paren(); + return $this; + } +} diff --git a/core/tests/Database_Test.php b/core/tests/Database_Test.php new file mode 100644 index 00000000..0d4351c9 --- /dev/null +++ b/core/tests/Database_Test.php @@ -0,0 +1,86 @@ +where("a", 1) + ->where("b", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same("SELECT * WHERE `a` = 1 AND `b` = 2", $sql); + } + + function compound_where_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->where("inner1", 1) + ->orwhere("inner2", 2) + ->close_paren() + ->where("outer2", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2) AND `outer2` = 2", + $sql); + } + + function group_first_test() { + $sql = Database::instance() + ->open_paren() + ->where("inner1", 1) + ->orwhere("inner2", 2) + ->close_paren() + ->where("outer1", 1) + ->where("outer2", 2) + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE (`inner1` = 1 OR `inner2` = 2) AND `outer1` = 1 AND `outer2` = 2", + $sql); + } + + function where_array_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->where("inner1", 1) + ->orwhere(array("inner2" => 2, "inner3" => 3)) + ->close_paren() + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 AND (`inner1` = 1 OR `inner2` = 2 OR `inner3` = 3)", + $sql); + } + + function notlike_test() { + $sql = Database::instance() + ->where("outer1", 1) + ->open_paren() + ->ornotlike("inner1", 1) + ->close_paren() + ->compile(); + $sql = str_replace("\n", " ", $sql); + $this->assert_same( + "SELECT * WHERE `outer1` = 1 OR ( `inner1` NOT LIKE '%1%')", + $sql); + } +} -- cgit v1.2.3