From 32696a53ff1b75dc798735d6b4f566cfc662a9ee Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 10 Apr 2014 15:54:43 -0400 Subject: [PATCH] Flesh out the table builder a bit, and add some missing driver methods to SQLite --- common.php | 5 ++ core/abstract/abstract_driver.php | 20 +++++ core/abstract/abstract_util.php | 6 +- core/table_builder.php | 82 ++++++++++++------- core/table_column.php | 8 +- drivers/firebird/firebird_driver.php | 16 ++-- drivers/firebird/firebird_sql.php | 1 + drivers/firebird/firebird_util.php | 2 +- drivers/sqlite/sqlite_driver.php | 14 ---- drivers/sqlite/sqlite_sql.php | 9 +- tests/bootstrap.php | 1 + tests/core/table_builder.php | 32 ++++++++ .../databases/firebird/FirebirdTableTest.php | 37 +++++++++ tests/databases/mysql/MySQLTableTest.php | 48 +++++++++++ tests/databases/pgsql/PgSQLTableTest.php | 48 +++++++++++ tests/databases/sqlite/SQLiteTableTest.php | 30 +++++++ tests/databases/sqlite/SqliteTest.php | 18 ++-- tests/phpunit.xml | 4 + 18 files changed, 316 insertions(+), 65 deletions(-) create mode 100644 tests/core/table_builder.php create mode 100644 tests/databases/firebird/FirebirdTableTest.php create mode 100644 tests/databases/mysql/MySQLTableTest.php create mode 100644 tests/databases/pgsql/PgSQLTableTest.php create mode 100644 tests/databases/sqlite/SQLiteTableTest.php diff --git a/common.php b/common.php index 7297d6a..5289812 100644 --- a/common.php +++ b/common.php @@ -77,6 +77,11 @@ function db_filter($array, $index) /** * Connection function * + * Send an array or object as connection parameters to create a connection. If + * the array or object has an 'alias' parameter, passing that string to this + * function will return that connection. Passing no parameters returns the last + * connection created. + * * @param string|object|array $params * @return Query\Query_Builder|null */ diff --git a/core/abstract/abstract_driver.php b/core/abstract/abstract_driver.php index 0aaf32e..b18aad0 100644 --- a/core/abstract/abstract_driver.php +++ b/core/abstract/abstract_driver.php @@ -95,6 +95,26 @@ abstract class Abstract_Driver extends \PDO implements Driver_Interface { $this->table = new Table_Builder('', array(), $this); } + // -------------------------------------------------------------------------- + + /** + * Allow invoke to work on table object + * + * @param string $name + * @param array $args + */ + public function __call($name, $args = array()) + { + if ( + isset($this->$name) + && is_object($this->$name) + && method_exists($this->$name, '__invoke') + ) + { + return call_user_func_array(array($this->$name, '__invoke'), $args); + } + } + // -------------------------------------------------------------------------- // ! Concrete functions that can be overridden in child classes // -------------------------------------------------------------------------- diff --git a/core/abstract/abstract_util.php b/core/abstract/abstract_util.php index e624660..2945f05 100644 --- a/core/abstract/abstract_util.php +++ b/core/abstract/abstract_util.php @@ -33,9 +33,9 @@ abstract class Abstract_Util { /** * Save a reference to the connection object for later use * - * @param object $conn + * @param Driver_Interface $conn */ - public function __construct($conn) + public function __construct(Driver_Interface $conn) { $this->conn = $conn; } @@ -61,10 +61,10 @@ abstract class Abstract_Util { /** * Convienience public function to generate sql for creating a db table * + * @deprecated Use the table builder class instead * @param string $name * @param array $fields * @param array $constraints - * * @return string */ public function create_table($name, $fields, array $constraints=array()) diff --git a/core/table_builder.php b/core/table_builder.php index b274416..393c981 100644 --- a/core/table_builder.php +++ b/core/table_builder.php @@ -14,6 +14,9 @@ // -------------------------------------------------------------------------- namespace Query\Table; +use Query\Driver\Driver_Interface; + +// -------------------------------------------------------------------------- /** * Abstract class defining database / table creation methods @@ -64,23 +67,20 @@ class Table_Builder { /** * Constructor * - * @param string $name - * @param array $options - * @param Driver_Interface $driver + * @param [string] $name + * @param [array] $options + * @param [Driver_Interface] $driver * @return Table_Builder */ - public function __construct($name, $options = array(), \Query\Driver\Driver_Interface $driver = NULL) + public function __construct($name = '', $options = array(), Driver_Interface $driver = NULL) { - $this->name = $name; + $this->table_options = array_merge($this->table_options, $options); - if ( ! empty($options)) - { - $this->table_options = array_merge($this->table_options, $options); - } + $this->set_driver($driver); - if ( ! is_null($driver)) + if ($name !== '') { - $this->driver = $driver; + $this->name = (isset($this->driver)) ? $this->driver->prefix_table($name) : $name; } return $this; @@ -91,13 +91,14 @@ class Table_Builder { /** * Alias to constructor * - * @param string $name - * @param array $options - * @param \Query\Driver_Interface $driver + * @param [string] $name + * @param [array] $options + * @param [\Query\Driver\Driver_Interface] $driver + * @return Table_Builder */ - public function __invoke($name, $options = array(), \Query\Driver\Driver_Interface $driver = NULL) + public function __invoke($name = '', $options = array(), Driver_Interface $driver = NULL) { - $this->__construct($name, $options, $driver); + return $this->__construct($name, $options, $driver); } // -------------------------------------------------------------------------- @@ -105,12 +106,15 @@ class Table_Builder { /** * Set the reference to the current database driver * - * @param \Query\Driver_Interface $driver - * @return \Query\Table_Builder + * @param \Query\Driver\Driver_Interface $driver + * @return Table_Builder */ - public function set_driver(\Query\Driver_Interface $driver) + public function set_driver(Driver_Interface $driver = NULL) { - $this->driver = $driver; + if ( ! is_null($driver)) + { + $this->driver = $driver; + } return $this; } @@ -136,32 +140,35 @@ class Table_Builder { * @param string $column_name * @param string $type * @param array $options + * @return Table_Builder */ public function add_column($column_name, $type = NULL, $options = array()) { $col = new Table_Column($column_name, $type, $options); $this->columns[] = $col; + + return $this; } // -------------------------------------------------------------------------- public function remove_column($column_name) { - + return $this; } // -------------------------------------------------------------------------- public function rename_column($old_name, $new_name) { - + return $this; } // -------------------------------------------------------------------------- public function change_column($column_name, $new_column_type, $options = array()) { - + return $this; } // -------------------------------------------------------------------------- @@ -177,21 +184,24 @@ class Table_Builder { public function add_index($columns, $options = array()) { + $col = new Table_Index($columns, $options); + $this->indexes[] = $col; + return $this; } // -------------------------------------------------------------------------- public function remove_index($columns, $options = array()) { - + return $this; } // -------------------------------------------------------------------------- public function remove_index_by_name($name) { - + return $this; } // -------------------------------------------------------------------------- @@ -207,7 +217,10 @@ class Table_Builder { public function add_foreign_key($columns, $referenced_table, $referenced_columns = array('id'), $options = array()) { + $key = new Table_Foreign_Key($columns, $referenced_table, $referenced_columns, $options); + $this->foreign_keys[] = $key; + return $this; } // -------------------------------------------------------------------------- @@ -230,7 +243,8 @@ class Table_Builder { public function exists() { - + $tables = $this->driver->get_tables(); + return in_array($this->name, $tables); } // -------------------------------------------------------------------------- @@ -261,14 +275,14 @@ class Table_Builder { public function create() { - + $this->reset(); } // -------------------------------------------------------------------------- public function update() { - + $this->reset(); } // -------------------------------------------------------------------------- @@ -278,15 +292,23 @@ class Table_Builder { ($this->exists()) ? $this->update() : $this->create(); - - $this->reset(); } // -------------------------------------------------------------------------- public function reset() { + $skip = array( + 'driver' => 'driver' + ); + foreach($this as $key => $val) + { + if ( ! isset($skip[$key])) + { + $this->$key = NULL; + } + } } } diff --git a/core/table_column.php b/core/table_column.php index 141e0d4..ca5adc3 100644 --- a/core/table_column.php +++ b/core/table_column.php @@ -59,7 +59,11 @@ class Table_Column extends Abstract_Table { */ public function __construct($name, $type = NULL, $options = array()) { - + $this->name = $name; + $this->type = $type; + $this->options = ( ! empty($options)) + ? $this->validate_options($options) + : array(); } // -------------------------------------------------------------------------- @@ -71,7 +75,7 @@ class Table_Column extends Abstract_Table { */ public function __toString() { - + $num_args = func_num_args(); } } diff --git a/drivers/firebird/firebird_driver.php b/drivers/firebird/firebird_driver.php index 567b1c8..213799c 100644 --- a/drivers/firebird/firebird_driver.php +++ b/drivers/firebird/firebird_driver.php @@ -15,6 +15,10 @@ namespace Query\Driver; +use Query\Table\Table_Builder; + +// -------------------------------------------------------------------------- + /** * Firebird Database class * @@ -77,14 +81,14 @@ class Firebird extends Abstract_Driver { : '\\fbird_connect'; $this->conn = $connect_function($dbpath, $user, $pass, 'utf-8', 0); - $this->service = fbird_service_attach('localhost', $user, $pass); + $this->service = \fbird_service_attach('localhost', $user, $pass); // Throw an exception to make this match other pdo classes if ( ! \is_resource($this->conn)) throw new \PDOException(\fbird_errmsg(), \fbird_errcode(), NULL); // Load these classes here because this // driver does not call the constructor - // of DB_PDO, which defines these two + // of DB_PDO, which defines these // class variables for the other drivers // Load the sql class @@ -94,6 +98,9 @@ class Firebird extends Abstract_Driver { // Load the util class $class = __CLASS__."_util"; $this->util = new $class($this); + + // Load the table builder class + $this->table = new Table_Builder('', array(), $this); } // -------------------------------------------------------------------------- @@ -104,8 +111,7 @@ class Firebird extends Abstract_Driver { */ public function __destruct() { - fbird_service_detach($this->service); - fbird_close($this->conn); + \fbird_service_detach($this->service); } // -------------------------------------------------------------------------- @@ -130,7 +136,7 @@ class Firebird extends Abstract_Driver { public function truncate($table) { // Firebird lacks a truncate command - $sql = 'DELETE FROM "'.$table.'"'; + $sql = 'DELETE FROM '.$this->quote_table($table); $this->statement = $this->query($sql); } diff --git a/drivers/firebird/firebird_sql.php b/drivers/firebird/firebird_sql.php index a70213b..ae7e553 100644 --- a/drivers/firebird/firebird_sql.php +++ b/drivers/firebird/firebird_sql.php @@ -99,6 +99,7 @@ class Firebird_SQL extends Abstract_SQL { SELECT TRIM("RDB\$RELATION_NAME") FROM "RDB\$RELATIONS" WHERE "RDB\$SYSTEM_FLAG"=0 + AND "RDB\$VIEW_BLR" IS NULL ORDER BY "RDB\$RELATION_NAME" ASC SQL; } diff --git a/drivers/firebird/firebird_util.php b/drivers/firebird/firebird_util.php index 3270653..b9b4ba0 100644 --- a/drivers/firebird/firebird_util.php +++ b/drivers/firebird/firebird_util.php @@ -30,7 +30,7 @@ class Firebird_Util extends Abstract_Util { /** * Convienience public function to generate sql for creating a db table * - * @deprecated + * @deprecated Use the table builder class instead * @param string $name * @param array $fields * @param array $constraints diff --git a/drivers/sqlite/sqlite_driver.php b/drivers/sqlite/sqlite_driver.php index b957099..f0d808b 100644 --- a/drivers/sqlite/sqlite_driver.php +++ b/drivers/sqlite/sqlite_driver.php @@ -79,20 +79,6 @@ class SQLite extends Abstract_Driver { // -------------------------------------------------------------------------- - /** - * List system tables for the current database - * - * @return string[] - */ - public function get_system_tables() - { - //SQLite only has the sqlite_master table - // that is of any importance. - return array('sqlite_master'); - } - - // -------------------------------------------------------------------------- - /** * Create sql for batch insert * diff --git a/drivers/sqlite/sqlite_sql.php b/drivers/sqlite/sqlite_sql.php index bab2f36..ab9743b 100644 --- a/drivers/sqlite/sqlite_sql.php +++ b/drivers/sqlite/sqlite_sql.php @@ -51,7 +51,7 @@ class SQLite_SQL extends Abstract_SQL { /** * Returns sql to list other databases * - * @return NULL + * @return string */ public function db_list() { @@ -71,6 +71,7 @@ class SQLite_SQL extends Abstract_SQL { SELECT DISTINCT "name" FROM "sqlite_master" WHERE "type"='table' + AND "name" NOT LIKE 'sqlite_%' ORDER BY "name" DESC SQL; } @@ -84,7 +85,7 @@ SQL; */ public function system_table_list() { - return NULL; + return array('sqlite_master', 'sqlite_temp_master', 'sqlite_sequence'); } // -------------------------------------------------------------------------- @@ -110,7 +111,7 @@ SQL; */ public function trigger_list() { - return NULL; + return 'SELECT "name" FROM "sqlite_master" WHERE "type"=\'trigger\''; } // -------------------------------------------------------------------------- @@ -180,7 +181,7 @@ SQL; * Get the list of foreign keys for the current * table * - * @parma string $table + * @param string $table * @return string */ public function fk_list($table) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 525488e..95ae6b7 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -84,6 +84,7 @@ require_once(QTEST_DIR . '/core/core.php'); require_once(QTEST_DIR . '/core/db_test.php'); require_once(QTEST_DIR . '/core/db_qp_test.php'); require_once(QTEST_DIR . '/core/db_qb_test.php'); +require_once(QTEST_DIR . '/core/table_builder.php'); // Preset SQLite connection, so there aren't locking issues if (extension_loaded('pdo_sqlite')) diff --git a/tests/core/table_builder.php b/tests/core/table_builder.php new file mode 100644 index 0000000..f69b63f --- /dev/null +++ b/tests/core/table_builder.php @@ -0,0 +1,32 @@ +assertTrue($this->db->table('test')->exists()); + } + + public function testGetDriver() + { + $this->assertEqual($this->db, $this->db->table()->get_driver()); + } + +} +// End of table_builder.php \ No newline at end of file diff --git a/tests/databases/firebird/FirebirdTableTest.php b/tests/databases/firebird/FirebirdTableTest.php new file mode 100644 index 0000000..6f26093 --- /dev/null +++ b/tests/databases/firebird/FirebirdTableTest.php @@ -0,0 +1,37 @@ +markTestSkipped('Firebird extension does not exist'); + } + + // test the db driver directly + $this->db = new \Query\Driver\Firebird('localhost:'.$dbpath); + $this->db->table_prefix = 'create_'; + $this->tables = $this->db->get_tables(); + } + +} +// End of FirebirdTableTest.php \ No newline at end of file diff --git a/tests/databases/mysql/MySQLTableTest.php b/tests/databases/mysql/MySQLTableTest.php new file mode 100644 index 0000000..0138592 --- /dev/null +++ b/tests/databases/mysql/MySQLTableTest.php @@ -0,0 +1,48 @@ +markTestSkipped("MySQL extension for PDO not loaded"); + } + + // Attempt to connect, if there is a test config file + if (is_file(QTEST_DIR . "/settings.json")) + { + $params = json_decode(file_get_contents(QTEST_DIR . "/settings.json")); + $params = $params->mysql; + + $this->db = new \Query\Driver\MySQL("mysql:host={$params->host};dbname={$params->database}", $params->user, $params->pass, array( + PDO::ATTR_PERSISTENT => TRUE + )); + } + elseif (($var = getenv('CI'))) + { + $this->db = new \Query\Driver\MySQL('host=127.0.0.1;port=3306;dbname=test', 'root'); + } + + $this->db->table_prefix = 'create_'; + } + +} +// End of MySQLTableTest.php \ No newline at end of file diff --git a/tests/databases/pgsql/PgSQLTableTest.php b/tests/databases/pgsql/PgSQLTableTest.php new file mode 100644 index 0000000..51053bb --- /dev/null +++ b/tests/databases/pgsql/PgSQLTableTest.php @@ -0,0 +1,48 @@ +markTestSkipped("Postgres extension for PDO not loaded"); + } + + // Attempt to connect, if there is a test config file + if (is_file(QTEST_DIR . "/settings.json")) + { + $params = json_decode(file_get_contents(QTEST_DIR . "/settings.json")); + $params = $params->pgsql; + + $this->db = new $class("pgsql:dbname={$params->database}", $params->user, $params->pass); + } + elseif (($var = getenv('CI'))) + { + $this->db = new $class('host=127.0.0.1;port=5432;dbname=test', 'postgres'); + } + + $this->db->table_prefix = 'create_'; + } + +} +// End of PgSQLTableTest.php \ No newline at end of file diff --git a/tests/databases/sqlite/SQLiteTableTest.php b/tests/databases/sqlite/SQLiteTableTest.php new file mode 100644 index 0000000..f3d1233 --- /dev/null +++ b/tests/databases/sqlite/SQLiteTableTest.php @@ -0,0 +1,30 @@ +db = Query('test_sqlite'); + $this->db->table_prefix = 'create_'; + } + +} +// End of SQLiteTableTest.php \ No newline at end of file diff --git a/tests/databases/sqlite/SqliteTest.php b/tests/databases/sqlite/SqliteTest.php index 58b70f2..81523da 100644 --- a/tests/databases/sqlite/SqliteTest.php +++ b/tests/databases/sqlite/SqliteTest.php @@ -232,12 +232,6 @@ SQL; public function testNullMethods() { - $sql = $this->db->sql->system_table_list(); - $this->assertEqual(NULL, $sql); - - $sql = $this->db->sql->trigger_list(); - $this->assertEqual(NULL, $sql); - $sql = $this->db->sql->function_list(); $this->assertEqual(NULL, $sql); @@ -247,4 +241,16 @@ SQL; $sql = $this->db->sql->sequence_list(); $this->assertEqual(NULL, $sql); } + + public function testGetSystemTables() + { + $sql = $this->db->get_system_tables(); + $this->assertTrue(is_array($sql)); + } + + public function testGetTriggers() + { + $sql = $this->db->get_triggers(); + $this->assertTrue(is_array($sql)); + } } \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 7706541..3127779 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -18,18 +18,22 @@ databases/firebird/FirebirdTest.php + databases/firebird/FirebirdTableTest.php databases/firebird/FirebirdQBTest.php databases/mysql/MySQLTest.php + databases/mysql/MySQLTableTest.php databases/mysql/MySQLQBTest.php databases/pgsql/PgSQLTest.php + databases/pgsql/PgSQLTableTest.php databases/pgsql/PgSQLQBTest.php databases/sqlite/SqliteTest.php + databases/sqlite/SqliteTableTest.php databases/sqlite/SqliteQBTest.php