Flesh out the table builder a bit, and add some missing driver methods to SQLite

This commit is contained in:
Timothy Warren 2014-04-10 15:54:43 -04:00
parent 3cc260b779
commit 32696a53ff
18 changed files with 316 additions and 65 deletions

View File

@ -77,6 +77,11 @@ function db_filter($array, $index)
/** /**
* Connection function * 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 * @param string|object|array $params
* @return Query\Query_Builder|null * @return Query\Query_Builder|null
*/ */

View File

@ -95,6 +95,26 @@ abstract class Abstract_Driver extends \PDO implements Driver_Interface {
$this->table = new Table_Builder('', array(), $this); $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 // ! Concrete functions that can be overridden in child classes
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@ -33,9 +33,9 @@ abstract class Abstract_Util {
/** /**
* Save a reference to the connection object for later use * 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; $this->conn = $conn;
} }
@ -61,10 +61,10 @@ abstract class Abstract_Util {
/** /**
* Convienience public function to generate sql for creating a db table * Convienience public function to generate sql for creating a db table
* *
* @deprecated Use the table builder class instead
* @param string $name * @param string $name
* @param array $fields * @param array $fields
* @param array $constraints * @param array $constraints
*
* @return string * @return string
*/ */
public function create_table($name, $fields, array $constraints=array()) public function create_table($name, $fields, array $constraints=array())

View File

@ -14,6 +14,9 @@
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
namespace Query\Table; namespace Query\Table;
use Query\Driver\Driver_Interface;
// --------------------------------------------------------------------------
/** /**
* Abstract class defining database / table creation methods * Abstract class defining database / table creation methods
@ -64,23 +67,20 @@ class Table_Builder {
/** /**
* Constructor * Constructor
* *
* @param string $name * @param [string] $name
* @param array $options * @param [array] $options
* @param Driver_Interface $driver * @param [Driver_Interface] $driver
* @return Table_Builder * @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;
if ( ! empty($options))
{ {
$this->table_options = array_merge($this->table_options, $options); $this->table_options = array_merge($this->table_options, $options);
}
if ( ! is_null($driver)) $this->set_driver($driver);
if ($name !== '')
{ {
$this->driver = $driver; $this->name = (isset($this->driver)) ? $this->driver->prefix_table($name) : $name;
} }
return $this; return $this;
@ -91,13 +91,14 @@ class Table_Builder {
/** /**
* Alias to constructor * Alias to constructor
* *
* @param string $name * @param [string] $name
* @param array $options * @param [array] $options
* @param \Query\Driver_Interface $driver * @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 * Set the reference to the current database driver
* *
* @param \Query\Driver_Interface $driver * @param \Query\Driver\Driver_Interface $driver
* @return \Query\Table_Builder * @return Table_Builder
*/ */
public function set_driver(\Query\Driver_Interface $driver) public function set_driver(Driver_Interface $driver = NULL)
{
if ( ! is_null($driver))
{ {
$this->driver = $driver; $this->driver = $driver;
}
return $this; return $this;
} }
@ -136,32 +140,35 @@ class Table_Builder {
* @param string $column_name * @param string $column_name
* @param string $type * @param string $type
* @param array $options * @param array $options
* @return Table_Builder
*/ */
public function add_column($column_name, $type = NULL, $options = array()) public function add_column($column_name, $type = NULL, $options = array())
{ {
$col = new Table_Column($column_name, $type, $options); $col = new Table_Column($column_name, $type, $options);
$this->columns[] = $col; $this->columns[] = $col;
return $this;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function remove_column($column_name) public function remove_column($column_name)
{ {
return $this;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function rename_column($old_name, $new_name) public function rename_column($old_name, $new_name)
{ {
return $this;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function change_column($column_name, $new_column_type, $options = array()) 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()) 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()) public function remove_index($columns, $options = array())
{ {
return $this;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function remove_index_by_name($name) 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()) 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() public function exists()
{ {
$tables = $this->driver->get_tables();
return in_array($this->name, $tables);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -261,14 +275,14 @@ class Table_Builder {
public function create() public function create()
{ {
$this->reset();
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function update() public function update()
{ {
$this->reset();
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -278,15 +292,23 @@ class Table_Builder {
($this->exists()) ($this->exists())
? $this->update() ? $this->update()
: $this->create(); : $this->create();
$this->reset();
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
public function reset() public function reset()
{ {
$skip = array(
'driver' => 'driver'
);
foreach($this as $key => $val)
{
if ( ! isset($skip[$key]))
{
$this->$key = NULL;
}
}
} }
} }

View File

@ -59,7 +59,11 @@ class Table_Column extends Abstract_Table {
*/ */
public function __construct($name, $type = NULL, $options = array()) 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() public function __toString()
{ {
$num_args = func_num_args();
} }
} }

View File

@ -15,6 +15,10 @@
namespace Query\Driver; namespace Query\Driver;
use Query\Table\Table_Builder;
// --------------------------------------------------------------------------
/** /**
* Firebird Database class * Firebird Database class
* *
@ -77,14 +81,14 @@ class Firebird extends Abstract_Driver {
: '\\fbird_connect'; : '\\fbird_connect';
$this->conn = $connect_function($dbpath, $user, $pass, 'utf-8', 0); $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 // Throw an exception to make this match other pdo classes
if ( ! \is_resource($this->conn)) throw new \PDOException(\fbird_errmsg(), \fbird_errcode(), NULL); if ( ! \is_resource($this->conn)) throw new \PDOException(\fbird_errmsg(), \fbird_errcode(), NULL);
// Load these classes here because this // Load these classes here because this
// driver does not call the constructor // 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 // class variables for the other drivers
// Load the sql class // Load the sql class
@ -94,6 +98,9 @@ class Firebird extends Abstract_Driver {
// Load the util class // Load the util class
$class = __CLASS__."_util"; $class = __CLASS__."_util";
$this->util = new $class($this); $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() public function __destruct()
{ {
fbird_service_detach($this->service); \fbird_service_detach($this->service);
fbird_close($this->conn);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -130,7 +136,7 @@ class Firebird extends Abstract_Driver {
public function truncate($table) public function truncate($table)
{ {
// Firebird lacks a truncate command // Firebird lacks a truncate command
$sql = 'DELETE FROM "'.$table.'"'; $sql = 'DELETE FROM '.$this->quote_table($table);
$this->statement = $this->query($sql); $this->statement = $this->query($sql);
} }

View File

@ -99,6 +99,7 @@ class Firebird_SQL extends Abstract_SQL {
SELECT TRIM("RDB\$RELATION_NAME") SELECT TRIM("RDB\$RELATION_NAME")
FROM "RDB\$RELATIONS" FROM "RDB\$RELATIONS"
WHERE "RDB\$SYSTEM_FLAG"=0 WHERE "RDB\$SYSTEM_FLAG"=0
AND "RDB\$VIEW_BLR" IS NULL
ORDER BY "RDB\$RELATION_NAME" ASC ORDER BY "RDB\$RELATION_NAME" ASC
SQL; SQL;
} }

View File

@ -30,7 +30,7 @@ class Firebird_Util extends Abstract_Util {
/** /**
* Convienience public function to generate sql for creating a db table * Convienience public function to generate sql for creating a db table
* *
* @deprecated * @deprecated Use the table builder class instead
* @param string $name * @param string $name
* @param array $fields * @param array $fields
* @param array $constraints * @param array $constraints

View File

@ -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 * Create sql for batch insert
* *

View File

@ -51,7 +51,7 @@ class SQLite_SQL extends Abstract_SQL {
/** /**
* Returns sql to list other databases * Returns sql to list other databases
* *
* @return NULL * @return string
*/ */
public function db_list() public function db_list()
{ {
@ -71,6 +71,7 @@ class SQLite_SQL extends Abstract_SQL {
SELECT DISTINCT "name" SELECT DISTINCT "name"
FROM "sqlite_master" FROM "sqlite_master"
WHERE "type"='table' WHERE "type"='table'
AND "name" NOT LIKE 'sqlite_%'
ORDER BY "name" DESC ORDER BY "name" DESC
SQL; SQL;
} }
@ -84,7 +85,7 @@ SQL;
*/ */
public function system_table_list() 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() 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 * Get the list of foreign keys for the current
* table * table
* *
* @parma string $table * @param string $table
* @return string * @return string
*/ */
public function fk_list($table) public function fk_list($table)

View File

@ -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_test.php');
require_once(QTEST_DIR . '/core/db_qp_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/db_qb_test.php');
require_once(QTEST_DIR . '/core/table_builder.php');
// Preset SQLite connection, so there aren't locking issues // Preset SQLite connection, so there aren't locking issues
if (extension_loaded('pdo_sqlite')) if (extension_loaded('pdo_sqlite'))

View File

@ -0,0 +1,32 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Parent Table Builder Test Class
*/
abstract class TableBuilderTest extends Query_TestCase {
public function testExists()
{
$this->assertTrue($this->db->table('test')->exists());
}
public function testGetDriver()
{
$this->assertEqual($this->db, $this->db->table()->get_driver());
}
}
// End of table_builder.php

View File

@ -0,0 +1,37 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Parent Table Builder Test Class
*/
class FirebirdTableTest extends TableBuilderTest {
public function setUp()
{
$dbpath = QTEST_DIR.QDS.'db_files'.QDS.'FB_TEST_DB.FDB';
if ( ! function_exists('\\fbird_connect'))
{
$this->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

View File

@ -0,0 +1,48 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Parent Table Builder Test Class
*/
class MySQLTableTest extends TableBuilderTest {
public function setUp()
{
// If the database isn't installed, skip the tests
if ( ! class_exists("\\Query\\Driver\\MySQL"))
{
$this->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

View File

@ -0,0 +1,48 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Parent Table Builder Test Class
*/
class PgSQLTableTest extends TableBuilderTest {
public function setUp()
{
$class = "\\Query\\Driver\\PgSQL";
// If the database isn't installed, skip the tests
if ( ! class_exists($class))
{
$this->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

View File

@ -0,0 +1,30 @@
<?php
/**
* Query
*
* Free Query Builder / Database Abstraction Layer
*
* @package Query
* @author Timothy J. Warren
* @copyright Copyright (c) 2012 - 2014
* @link https://github.com/aviat4ion/Query
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Parent Table Builder Test Class
*/
class SQLiteTableTest extends TableBuilderTest {
public function setUp()
{
// Set up in the bootstrap to mitigate
// connection locking issues
$this->db = Query('test_sqlite');
$this->db->table_prefix = 'create_';
}
}
// End of SQLiteTableTest.php

View File

@ -232,12 +232,6 @@ SQL;
public function testNullMethods() 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(); $sql = $this->db->sql->function_list();
$this->assertEqual(NULL, $sql); $this->assertEqual(NULL, $sql);
@ -247,4 +241,16 @@ SQL;
$sql = $this->db->sql->sequence_list(); $sql = $this->db->sql->sequence_list();
$this->assertEqual(NULL, $sql); $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));
}
} }

View File

@ -18,18 +18,22 @@
</testsuite> </testsuite>
<testsuite name="FirebirdTests"> <testsuite name="FirebirdTests">
<file>databases/firebird/FirebirdTest.php</file> <file>databases/firebird/FirebirdTest.php</file>
<file>databases/firebird/FirebirdTableTest.php</file>
<file>databases/firebird/FirebirdQBTest.php</file> <file>databases/firebird/FirebirdQBTest.php</file>
</testsuite> </testsuite>
<testsuite name="MySQLTests"> <testsuite name="MySQLTests">
<file>databases/mysql/MySQLTest.php</file> <file>databases/mysql/MySQLTest.php</file>
<file>databases/mysql/MySQLTableTest.php</file>
<file>databases/mysql/MySQLQBTest.php</file> <file>databases/mysql/MySQLQBTest.php</file>
</testsuite> </testsuite>
<testsuite name="PgSQLTests"> <testsuite name="PgSQLTests">
<file>databases/pgsql/PgSQLTest.php</file> <file>databases/pgsql/PgSQLTest.php</file>
<file>databases/pgsql/PgSQLTableTest.php</file>
<file>databases/pgsql/PgSQLQBTest.php</file> <file>databases/pgsql/PgSQLQBTest.php</file>
</testsuite> </testsuite>
<testsuite name="SQLiteTests"> <testsuite name="SQLiteTests">
<file>databases/sqlite/SqliteTest.php</file> <file>databases/sqlite/SqliteTest.php</file>
<file>databases/sqlite/SqliteTableTest.php</file>
<file>databases/sqlite/SqliteQBTest.php</file> <file>databases/sqlite/SqliteQBTest.php</file>
</testsuite> </testsuite>
</testsuites> </testsuites>