From 272dfd62d45ae53ba9b4c0133b62ba7f0f69370a Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 13 Apr 2012 12:49:13 -0400 Subject: [PATCH] Implement select_max, select_min, select_avg, and select_sum methods in query builder --- README.md | 2 +- classes/db_pdo.php | 12 +- classes/db_sql.php | 12 ++ classes/query_builder.php | 149 ++++++++++++++++++----- tests/databases/firebird/firebird-qb.php | 40 ++++++ tests/db_files/FB_TEST_DB.FDB | Bin 802816 -> 802816 bytes tests/parent.php | 40 ++++++ 7 files changed, 223 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 675acdb..83d31af 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Create a connection array or object similar to this: The parameters required depend on the database. ### Running Queries -Query uses the same interface as CodeIgniter's [Active Record class](http://codeigniter.com/user_guide/database/active_record.html). However, it does not implement the `select_` methods, `count_all_results`, `distinct`, `having`, `or_having`, `insert_batch`, `update_batch`, or `count_all` methods. +Query uses the same interface as CodeIgniter's [Active Record class](http://codeigniter.com/user_guide/database/active_record.html). However, it does not implement the `count_all_results`, `distinct`, `having`, `or_having`, `insert_batch`, `update_batch`, or `count_all` methods. #### Retrieving Results diff --git a/classes/db_pdo.php b/classes/db_pdo.php index 9839852..90f8560 100644 --- a/classes/db_pdo.php +++ b/classes/db_pdo.php @@ -27,6 +27,11 @@ abstract class DB_PDO extends PDO { /** * PDO constructor wrapper + * + * @param string $dsn + * @param string $username + * @param string $password + * @param array $driver_options */ public function __construct($dsn, $username=NULL, $password=NULL, $driver_options=array()) { @@ -35,7 +40,9 @@ abstract class DB_PDO extends PDO { $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } - // ------------------------------------------------------------------------- + // -------------------------------------------------------------------------- + // ! Concrete functions that can be overridden in child classes + // -------------------------------------------------------------------------- /** * Simplifies prepared statements for database queries @@ -327,9 +334,8 @@ abstract class DB_PDO extends PDO { return $this->driver_query($this->sql->system_table_list()); } - // ------------------------------------------------------------------------- - // ! Abstract public functions to override in child classes + // ! Abstract public functions to implement in child classes // ------------------------------------------------------------------------- /** diff --git a/classes/db_sql.php b/classes/db_sql.php index b85f293..45b6a60 100644 --- a/classes/db_sql.php +++ b/classes/db_sql.php @@ -67,6 +67,18 @@ abstract class DB_SQL { return ' AVG'; } + // -------------------------------------------------------------------------- + + /** + * Get the 'sum' keyword + * + * @return string + */ + public function sum() + { + return ' SUM'; + } + // -------------------------------------------------------------------------- // ! Abstract Methods // -------------------------------------------------------------------------- diff --git a/classes/query_builder.php b/classes/query_builder.php index 98f07e9..cb92099 100644 --- a/classes/query_builder.php +++ b/classes/query_builder.php @@ -38,7 +38,7 @@ class Query_Builder { private $limit, $offset; - // Alias to $this->db->sql + // Alias to $this->sql private $sql; // Query component order mapping @@ -59,7 +59,7 @@ class Query_Builder { /** * Constructor * - * @param object $conn_name - the name of the connection/parameters + * @param object $params - the connection parametere */ public function __construct($params) { @@ -111,9 +111,6 @@ class Query_Builder { break; } - // Set the charset - //$dsn .= ";charset=utf-8"; - // Create the database connection if ( ! empty($params->user)) { @@ -180,6 +177,102 @@ class Query_Builder { return $this; } + + // -------------------------------------------------------------------------- + + /** + * Selects the maximum value of a field from a query + * + * @param string $field + * @param string $as + * @return $this + */ + public function select_max($field, $as=FALSE) + { + // Escape the identifiers + $field = $this->quote_ident($field); + + $as = ($as !== FALSE) + ? $this->quote_ident($as) + : $field; + + // Create the select string + $this->select_string = $this->sql->max()."({$field}) AS {$as} "; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Selects the minimum value of a field from a query + * + * @param string $field + * @param string $as + * @return $this + */ + public function select_min($field, $as=FALSE) + { + // Escape the identifiers + $field = $this->quote_ident($field); + + $as = ($as !== FALSE) + ? $this->quote_ident($as) + : $field; + + // Create the select string + $this->select_string = $this->sql->min()."({$field}) AS {$as} "; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Selects the average value of a field from a query + * + * @param string $field + * @param string $as + * @return $this + */ + public function select_avg($field, $as=FALSE) + { + // Escape the identifiers + $field = $this->quote_ident($field); + + $as = ($as !== FALSE) + ? $this->quote_ident($as) + : $field; + + // Create the select string + $this->select_string = $this->sql->avg()."({$field}) AS {$as} "; + + return $this; + } + + // -------------------------------------------------------------------------- + + /** + * Selects the sum of a field from a query + * + * @param string $field + * @param string $as + * @return $this + */ + public function select_sum($field, $as=FALSE) + { + // Escape the identifiers + $field = $this->quote_ident($field); + + $as = ($as !== FALSE) + ? $this->quote_ident($as) + : $field; + + // Create the select string + $this->select_string = $this->sql->sum()."({$field}) AS {$as} "; + + return $this; + } // -------------------------------------------------------------------------- @@ -218,7 +311,7 @@ class Query_Builder { */ public function like($field, $val, $pos='both') { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); // Add the like string into the order map $l = $field. ' LIKE ?'; @@ -260,7 +353,7 @@ class Query_Builder { */ public function or_like($field, $val, $pos='both') { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); // Add the like string into the order map $l = $field. ' LIKE ?'; @@ -302,7 +395,7 @@ class Query_Builder { */ public function not_like($field, $val, $pos='both') { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); // Add the like string into the order map $l = $field. ' NOT LIKE ?'; @@ -344,7 +437,7 @@ class Query_Builder { */ public function or_not_like($field, $val, $pos='both') { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); // Add the like string into the order map $l = $field. ' NOT LIKE ?'; @@ -430,7 +523,7 @@ class Query_Builder { // is an operator such as >, <, !=, etc. $f_array = explode(' ', trim($f)); - $item = $this->db->quote_ident($f_array[0]); + $item = $this->quote_ident($f_array[0]); // Simple key value, or an operator $item .= (count($f_array === 1)) ? '= ?' : " {$f_array[1]} ?"; @@ -469,11 +562,11 @@ class Query_Builder { // Simple key = val if (count($f_array) === 1) { - $item = $this->db->quote_ident($f_array[0]) . '= ?'; + $item = $this->quote_ident($f_array[0]) . '= ?'; } else // Other operators { - $item = $this->db->quote_ident($f_array[0]) . " {$f_array[1]} ?"; + $item = $this->quote_ident($f_array[0]) . " {$f_array[1]} ?"; } // Put in the query map for select statements @@ -498,7 +591,7 @@ class Query_Builder { */ public function where_in($field, $val=array()) { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); $params = array_fill(0, count($val), '?'); foreach($val as $v) @@ -528,7 +621,7 @@ class Query_Builder { */ public function or_where_in($field, $val=array()) { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); $params = array_fill(0, count($val), '?'); foreach($val as $v) @@ -558,7 +651,7 @@ class Query_Builder { */ public function where_not_in($field, $val=array()) { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); $params = array_fill(0, count($val), '?'); foreach($val as $v) @@ -588,7 +681,7 @@ class Query_Builder { */ public function or_where_not_in($field, $val=array()) { - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); $params = array_fill(0, count($val), '?'); foreach($val as $v) @@ -627,8 +720,8 @@ class Query_Builder { $cond_array = explode(' ', trim($condition)); $cond_array = array_map('trim', $cond_array); - $condition = $table . ' ON ' . $this->db->quote_ident($cond_array[0]) . $cond_array[1] . - ' ' . $this->db->quote_ident($cond_array[2]); + $condition = $table . ' ON ' . $this->quote_ident($cond_array[0]) . $cond_array[1] . + ' ' . $this->quote_ident($cond_array[2]); $this->query_map[] = array( 'type' => 'join', @@ -655,7 +748,7 @@ class Query_Builder { } else { - $this->group_array[] = $this->db->quote_ident($field); + $this->group_array[] = $this->quote_ident($field); } $this->group_string = ' GROUP BY ' . implode(', ', $this->group_array); @@ -681,7 +774,7 @@ class Query_Builder { } // Set fields for later manipulation - $field = $this->db->quote_ident($field); + $field = $this->quote_ident($field); $this->order_array[$field] = $type; $order_clauses = array(); @@ -825,12 +918,12 @@ class Query_Builder { // Do prepared statements for anything involving a "where" clause if ( ! empty($this->query_map)) { - $result = $this->db->prepare_execute($sql, $this->values); + $result = $this->prepare_execute($sql, $this->values); } else { // Otherwise, a simple query will do. - $result = $this->db->query($sql); + $result = $this->query($sql); } // Reset for next query @@ -878,7 +971,7 @@ class Query_Builder { $sql = $this->_compile("insert", $table); - $res = $this->db->prepare_execute($sql, $this->values); + $res = $this->prepare_execute($sql, $this->values); $this->_reset(); @@ -904,7 +997,7 @@ class Query_Builder { $sql = $this->_compile('update', $table); - $res = $this->db->prepare_execute($sql, $this->values); + $res = $this->prepare_execute($sql, $this->values); $this->_reset(); @@ -932,7 +1025,7 @@ class Query_Builder { // Create the SQL and parameters $sql = $this->_compile("delete", $table); - $res = $this->db->prepare_execute($sql, $this->values); + $res = $this->prepare_execute($sql, $this->values); $this->_reset(); @@ -1090,13 +1183,13 @@ class Query_Builder { case "insert": $param_count = count($this->set_array); $params = array_fill(0, $param_count, '?'); - $sql = 'INSERT INTO '. $this->db->quote_ident($table) . + $sql = 'INSERT INTO '. $this->quote_ident($table) . ' (' . implode(', ', $this->set_array_keys) . ') VALUES ('.implode(', ', $params).')'; break; case "update": - $sql = 'UPDATE '.$this->db->quote_ident($table). ' SET '. $this->set_string; + $sql = 'UPDATE '.$this->quote_ident($table). ' SET '. $this->set_string; // Set the where string if ( ! empty($this->query_map)) @@ -1109,7 +1202,7 @@ class Query_Builder { break; case "delete": - $sql = 'DELETE FROM '.$this->db->quote_ident($table); + $sql = 'DELETE FROM '.$this->quote_ident($table); // Set the where string if ( ! empty($this->query_map)) diff --git a/tests/databases/firebird/firebird-qb.php b/tests/databases/firebird/firebird-qb.php index ba26ee5..2c1f2f8 100644 --- a/tests/databases/firebird/firebird-qb.php +++ b/tests/databases/firebird/firebird-qb.php @@ -76,6 +76,46 @@ class FirebirdQBTest extends QBTest { $this->assertIsA($query, 'Firebird_Result'); } + function TestSelectMax() + { + if (empty($this->db)) return; + + $query = $this->db->select_max('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'Firebird_Result'); + } + + function TestSelectMin() + { + if (empty($this->db)) return; + + $query = $this->db->select_min('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'Firebird_Result'); + } + + function TestSelectAvg() + { + if (empty($this->db)) return; + + $query = $this->db->select_avg('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'Firebird_Result'); + } + + function TestSelectSum() + { + if (empty($this->db)) return; + + $query = $this->db->select_sum('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'Firebird_Result'); + } + function TestGetWhere() { if (empty($this->db)) return; diff --git a/tests/db_files/FB_TEST_DB.FDB b/tests/db_files/FB_TEST_DB.FDB index 9f4ec8271361ac5add1ac78e56f1b8904e4329e8..3674a55c9c9f12b03274a880b04df50e45bfe5c3 100755 GIT binary patch delta 1007 zcmZ9K&ubGw6vy9eHvN%Db=qDcwjoIqQ!7Fut)d4tTJRSri1a8`C_*Vza`7S(EbP%( zqCRSnAn^y@N^P4<_23_%XGKbrG-;bwg134Qe6y2jgR|_;erIRDpZDFj>2xBUPFxpo zI$jUJ{*ajVG?khQ{Q&Ry1h7Qz2f(dU-(r5h-XOu^W84*juZ8}Pq49--kEJ7pBP~aI z9BDh!>&P}owmY)Jk)6xZXG`(E=neW(?b-9Pt@t43o9S@kzU4UD^S2**wYRyBiC$O~ zQCPHtFlrCNt|tn%CkSg+7)Cu^uwo6sGiwm0>;V{NeV_GZD+)o@YD9SLsU3zlq6>bC z;@vg8Ai7nk&+cOZV)`5uXsLuZM1j0zyvWns8ir`Hj6RZQikLE1M%{Rd*vaw~5C@R<-zS+mwJ2UcXZ2_2XNdHLKV$ zTHyupoPKXG`^y%yjhFeHM(bMGyUB99%YRa)mCfHFqjO)abMB1J{i4pfGdlNbopWbe za?et-h9_ud8@rDhFWqX`^LA_L+t-3VZQ~LxRI!hq>|mTG8+e$$?{M#4uA{#g{)MYI F{{c_o?}PvV delta 1088 zcmZvaO=uHA6vyAB*?#2ZW11pFXl;@vv;`}PtrSJjSfPi4qLdy>loq`Ovq+Ut8V&5h zf*+?RcvA4-P1H7*s#v@W;z>O;O`A4twO0iN-|X(RLHd^6+5f(s`Tyq66pQI%F?~V6 z$<*f~uwN33O|DYod>6odz5zVq$yb2!;ZMEci1UL44_{eZ2!76Yy^dvHh3-mA3QKw{ z*N%56VW=mv1T0_WDY#kFw2H%D0$8@5{+4!&zECCqxH) z!6dANqHsDChe$99OTj)!1fnn%2ml1)@ZH}7Yr!5EXZ^U$#QS+?e-JC>-CD&?%I;zxEv;gL&i=%sZ+~5WoI{q2>*J0Aqr85~9*NCPjf> ztTR!;Av#=RqFK7MjmOEXVS7e9I7I0ot(`bdfYxC}#2zy)QAla_nbAZWH6~JBT?Y{j zZZOe|$|xp$RM^0NRw^pdOvmaNZ5hqyOmpxyJ*{Jm!kZY+XhX0g8O>|0Bh=afHYUtQ zKxQ#DAZ;?B>gqZOu)4{Briv^<19i^IY{>1V$}L9Ab;i;*4i?+Ewhq?5wz2p~=G=bJ z%`vC3Mz?T4assertIsA($query, 'PDOStatement'); } + function TestSelectMax() + { + if (empty($this->db)) return; + + $query = $this->db->select_max('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectMin() + { + if (empty($this->db)) return; + + $query = $this->db->select_min('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectAvg() + { + if (empty($this->db)) return; + + $query = $this->db->select_avg('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + + function TestSelectSum() + { + if (empty($this->db)) return; + + $query = $this->db->select_sum('id', 'di') + ->get('create_test'); + + $this->assertIsA($query, 'PDOStatement'); + } + function TestGetWhere() { if (empty($this->db)) return;