summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortag <[email protected]>2012-11-23 22:51:33 -0500
committertag <[email protected]>2012-11-23 22:51:33 -0500
commit7c95314624d427e99a5213e2868d305f421b6962 (patch)
treede4ba72e89a9177582f3a824260f094ee9f87a6f
parent13d291f4442d268ba170b6635e44cd11d3f1049b (diff)
Multiple connection support for Idiorm
Mutiple connections code, including documentation and unit tests. Utilizes key names to distinguish connections, but uses a default connection if none specified. I don't (yet) use multiple connections in my work (it's pending), so this has not been tested "in the wild". Added unit tests with additional connections, ran unit tests for Paris against this build too, so an unmodified Paris is forward-compatible with this commit (mulitple connections support not yet coded for Paris). Does *NOT* add support for queries across multiple connections. (I don't even want to go there ...) ##### Edge-case compatibility breaks: * ORM::_setup_identifier_quote_character visibility was changed to protected (which was likely original intent, judging by prefixed name) * May break compatibility if ORM has been extended, **and** subclasses directly utilize `::_config`, `::_db`, `::_query_log`, or `::_query_cache` instead of using pre-existing accessor methods. (Paris does not do this; all Paris tests pass) * Re-use of `Tester` class outside of Idiorm repo, as `Tester::check_equal()` was renamed to `Tester::check_equal_query()` ##### Other notes New method: `ORM::get_connection_keys()`. New `Tester` method: `Tester::check_equal_string()`. TODO: Consider adding methods to get (connection-specific) configuration info.
-rw-r--r--README.markdown51
-rw-r--r--idiorm.php213
-rw-r--r--test/test_classes.php57
-rwxr-xr-xtest/test_queries.php199
4 files changed, 369 insertions, 151 deletions
diff --git a/README.markdown b/README.markdown
index 427f6bb..ca3a554 100644
--- a/README.markdown
+++ b/README.markdown
@@ -620,3 +620,54 @@ When query caching is enabled, Idiorm will cache the results of every `SELECT` q
* Idiorm's cache is very simple, and does not attempt to invalidate itself when data changes. This means that if you run a query to retrieve some data, modify and save it, and then run the same query again, the results will be stale (ie, they will not reflect your modifications). This could potentially cause subtle bugs in your application. If you have caching enabled and you are experiencing odd behaviour, disable it and try again. If you do need to perform such operations but still wish to use the cache, you can call the `ORM::clear_cache()` to clear all existing cached queries.
* Enabling the cache will increase the memory usage of your application, as all database rows that are fetched during each request are held in memory. If you are working with large quantities of data, you may wish to disable the cache.
+
+### Mulitple Connections ###
+Idiorm now works with multiple conections. Most of the static functions work with an optional connection name as an extra parameter. For the `ORM::configure` method, this means that when passing connection strings for a new connection, the second parameter, which is typically omitted, should be `null`. In all cases, if a connection name is no provided, it defaults to `ORM::DEFAULT_CONNECTION`.
+
+When chaining, once `for_table()` has been used in the chain, remaining calls use the correct connection.
+
+```php
+ // Default connection
+ ORM::configure('sqlite:./example.db');
+
+ // A named connection, where 'remote' is an arbitrary key name
+ ORM::configure('mysql:host=localhost;dbname=my_database', null, 'remote');
+ ORM::configure('username', 'database_user', 'remote');
+ ORM::configure('password', 'top_secret', 'remote');
+
+ // Using default connection
+ $person = ORM::for_table('person')->find_one(5);
+
+ // Using default connection, explicitly
+ $person = ORM::for_table('person', ORM::DEFAULT_CONNECTION)->find_one(5);
+
+ // Using named connection
+ $person = ORM::for_table('different_person', 'remote')->find_one(5);
+
+
+ // Last query on *any* connection
+ ORM::get_last_query(); // returns query on 'different_person' using 'remote'
+
+ // returns query on 'person' using default
+ ORM::get_last_query(ORM::DEFAULT_CONNECTION);
+
+```
+
+* **There is no support for joins across connections**
+
+* Multiple connections do not share configuration settings. This means if one connection has `logging` set to `true` and the other does not, only queries from the logged connection will be available via `ORM::get_last_query()` and `ORM::get_query_log()`
+
+* A new method has been added, `ORM::get_connection_keys()`, which returns an array of connection names.
+
+* Cachine *should* work with multiple connections (remember to turn caching on for each connection), but the unit tests are not robust. Please report any errors.
+
+##### Supported Methods #####
+In each of these cases, the `$which` parameter is optional.
+
+* `ORM::configure($key, $value, $which)`
+* `ORM::for_table($table_name, $which)`
+* `ORM::set_db($pdo, $which)`
+* `ORM::get_db($which)`
+* `ORM::raw_execute($query, $parameters, $which)`
+* `ORM::get_last_query($which)`
+* `ORM::get_query_log($which)` \ No newline at end of file
diff --git a/idiorm.php b/idiorm.php
index d955c72..2446258 100644
--- a/idiorm.php
+++ b/idiorm.php
@@ -48,12 +48,14 @@
const WHERE_FRAGMENT = 0;
const WHERE_VALUES = 1;
+ const DEFAULT_CONNECTION = 'default';
+
// ------------------------ //
// --- CLASS PROPERTIES --- //
// ------------------------ //
// Class configuration
- protected static $_config = array(
+ protected static $_default_config = array(
'connection_string' => 'sqlite::memory:',
'id_column' => 'id',
'id_column_overrides' => array(),
@@ -66,13 +68,15 @@
'caching' => false,
);
- // Database connection, instance of the PDO class
- protected static $_db;
+ protected static $_config = array();
+
+ // Map of database connections, instances of the PDO class
+ protected static $_db = array();
// Last query run, only populated if logging is enabled
protected static $_last_query;
- // Log of all queries run, only populated if logging is enabled
+ // Log of all queries run, mapped by connection key, only populated if logging is enabled
protected static $_query_log = array();
// Query cache, only used if query caching is enabled
@@ -82,6 +86,9 @@
// --- INSTANCE PROPERTIES --- //
// --------------------------- //
+ // Key name of the connections in self::$_db used by this instance
+ protected $_which_db;
+
// The name of the table the current ORM instance is associated with
protected $_table_name;
@@ -158,21 +165,23 @@
* you wish to configure, another shortcut is to pass an array
* of settings (and omit the second argument).
*/
- public static function configure($key, $value=null) {
+ public static function configure($key, $value = null, $which = self::DEFAULT_CONNECTION) {
+ self::_setup_db_config($which); //ensures at least default config is set
+
if (is_array($key)) {
// Shortcut: If only one array argument is passed,
// assume it's an array of configuration settings
foreach ($key as $conf_key => $conf_value) {
- self::configure($conf_key, $conf_value);
+ self::configure($conf_key, $conf_value, $which);
}
} else {
- if (is_null($value)) {
+ if (empty($value)) {
// Shortcut: If only one string argument is passed,
// assume it's a connection string
$value = $key;
$key = 'connection_string';
}
- self::$_config[$key] = $value;
+ self::$_config[$which][$key] = $value;
}
}
@@ -183,34 +192,52 @@
* ORM::for_table('table_name')->find_one()-> etc. As such,
* this will normally be the first method called in a chain.
*/
- public static function for_table($table_name) {
- self::_setup_db();
- return new self($table_name);
+ public static function for_table($table_name, $which = self::DEFAULT_CONNECTION)
+ {
+ self::_setup_db($which);
+ return new self($table_name, array(), $which);
}
/**
* Set up the database connection used by the class.
- */
- protected static function _setup_db() {
- if (!is_object(self::$_db)) {
- $connection_string = self::$_config['connection_string'];
- $username = self::$_config['username'];
- $password = self::$_config['password'];
- $driver_options = self::$_config['driver_options'];
- $db = new PDO($connection_string, $username, $password, $driver_options);
- $db->setAttribute(PDO::ATTR_ERRMODE, self::$_config['error_mode']);
- self::set_db($db);
+ * Default value of parameter used for compatibility with Paris, until it can be updated
+ * @todo After paris is updated to support multiple connections, remove default value of parameter
+ */
+ protected static function _setup_db($which = self::DEFAULT_CONNECTION)
+ {
+ if (!is_object(self::$_db[$which])) {
+ self::_setup_db_config($which);
+
+ $db = new PDO(
+ self::$_config[$which]['connection_string'],
+ self::$_config[$which]['username'],
+ self::$_config[$which]['password'],
+ self::$_config[$which]['driver_options']);
+
+ $db->setAttribute(PDO::ATTR_ERRMODE, self::$_config[$which]['error_mode']);
+ self::set_db($db, $which);
+ }
+ }
+
+ /**
+ * Ensures configuration (mulitple connections) is at least set to default.
+ */
+ protected static function _setup_db_config($which) {
+ if (!array_key_exists($which, self::$_config)) {
+ self::$_config[$which] = self::$_default_config;
}
}
/**
* Set the PDO object used by Idiorm to communicate with the database.
* This is public in case the ORM should use a ready-instantiated
- * PDO object as its database connection.
+ * PDO object as its database connection. Accepts an optional string key
+ * to identify the connection if multiple connections are used.
*/
- public static function set_db($db) {
- self::$_db = $db;
- self::_setup_identifier_quote_character();
+ public static function set_db($db, $which = self::DEFAULT_CONNECTION) {
+ self::_setup_db_config($which);
+ self::$_db[$which] = $db;
+ self::_setup_identifier_quote_character($which);
}
/**
@@ -219,9 +246,10 @@
* manually using ORM::configure('identifier_quote_character', 'some-char'),
* this will do nothing.
*/
- public static function _setup_identifier_quote_character() {
- if (is_null(self::$_config['identifier_quote_character'])) {
- self::$_config['identifier_quote_character'] = self::_detect_identifier_quote_character();
+ protected static function _setup_identifier_quote_character($which) {
+ if (is_null(self::$_config[$which]['identifier_quote_character'])) {
+ self::$_config[$which]['identifier_quote_character'] =
+ self::_detect_identifier_quote_character($which);
}
}
@@ -229,8 +257,8 @@
* Return the correct character used to quote identifiers (table
* names, column names etc) by looking at the driver being used by PDO.
*/
- protected static function _detect_identifier_quote_character() {
- switch(self::$_db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
+ protected static function _detect_identifier_quote_character($which) {
+ switch(self::$_db[$which]->getAttribute(PDO::ATTR_DRIVER_NAME)) {
case 'pgsql':
case 'sqlsrv':
case 'dblib':
@@ -248,11 +276,12 @@
/**
* Returns the PDO instance used by the the ORM to communicate with
* the database. This can be called if any low-level DB access is
- * required outside the class.
+ * required outside the class. If multiple connections are used,
+ * accepts an optional key name for the connection.
*/
- public static function get_db() {
- self::_setup_db(); // required in case this is called before Idiorm is instantiated
- return self::$_db;
+ public static function get_db($which = self::DEFAULT_CONNECTION) {
+ self::_setup_db($which); // required in case this is called before Idiorm is instantiated
+ return self::$_db[$which];
}
/**
@@ -263,13 +292,18 @@
* @example raw_execute('INSERT OR REPLACE INTO `widget` (`id`, `name`) SELECT `id`, `name` FROM `other_table`')
* @param string $query The raw SQL query
* @param array $parameters Optional bound parameters
+ * @param array
* @return bool Success
*/
- public static function raw_execute($query, $parameters = array()) {
- self::_setup_db();
+ public static function raw_execute(
+ $query,
+ $parameters = array(),
+ $which = self::DEFAULT_CONNECTION
+ ) {
+ self::_setup_db($which);
- self::_log_query($query, $parameters);
- $statement = self::$_db->prepare($query);
+ self::_log_query($query, $parameters, $which);
+ $statement = self::$_db[$which]->prepare($query);
return $statement->execute($parameters);
}
@@ -282,15 +316,19 @@
* parameters to the database which takes care of the binding) but
* doing it this way makes the logged queries more readable.
*/
- protected static function _log_query($query, $parameters) {
+ protected static function _log_query($query, $parameters, $which) {
// If logging is not enabled, do nothing
- if (!self::$_config['logging']) {
+ if (!self::$_config[$which]['logging']) {
return false;
}
+ if (!isset(self::$_query_log[$which])) {
+ self::$_query_log[$which] = array();
+ }
+
if (count($parameters) > 0) {
// Escape the parameters
- $parameters = array_map(array(self::$_db, 'quote'), $parameters);
+ $parameters = array_map(array(self::$_db[$which], 'quote'), $parameters);
// Avoid %format collision for vsprintf
$query = str_replace("%", "%%", $query);
@@ -309,26 +347,41 @@
}
self::$_last_query = $bound_query;
- self::$_query_log[] = $bound_query;
+ self::$_query_log[$which][] = $bound_query;
return true;
}
/**
* Get the last query executed. Only works if the
* 'logging' config option is set to true. Otherwise
- * this will return null.
+ * this will return null. Returns last query from all connections
*/
- public static function get_last_query() {
- return self::$_last_query;
+ public static function get_last_query($which = null) {
+ if ($which === null) {
+ return self::$_last_query;
+ }
+ if (!isset(self::$_query_log[$which])) {
+ return '';
+ }
+
+ return implode('', array_slice(self::$_query_log[$which], -1));
+ // Used implode(array_slice()) instead of end() to avoid resetting interal array pointer
}
/**
- * Get an array containing all the queries run up to
- * now. Only works if the 'logging' config option is
- * set to true. Otherwise returned array will be empty.
+ * Get an array containing all the queries run on a
+ * specified connection up to now.
+ * Only works if the 'logging' config option is
+ * set to true. Otherwise, returned array will be empty.
+ * @param string $which Key of database connection
*/
- public static function get_query_log() {
- return self::$_query_log;
+ public static function get_query_log($which = self::DEFAULT_CONNECTION) {
+ return isset(self::$_query_log[$which]) ? self::$_query_log[$which] : array();
+ }
+
+ public static function get_connection_keys()
+ {
+ return array_keys(self::$_db);
}
// ------------------------ //
@@ -339,9 +392,16 @@
* "Private" constructor; shouldn't be called directly.
* Use the ORM::for_table factory method instead.
*/
- protected function __construct($table_name, $data=array()) {
+ protected function __construct(
+ $table_name,
+ $data = array(),
+ $which = self::DEFAULT_CONNECTION
+ ) {
$this->_table_name = $table_name;
$this->_data = $data;
+
+ $this->_which_db = $which;
+ self::_setup_db_config($which);
}
/**
@@ -378,7 +438,7 @@
* array of data fetched from the database)
*/
protected function _create_instance_from_row($row) {
- $instance = self::for_table($this->_table_name);
+ $instance = self::for_table($this->_table_name, $this->_which_db);
$instance->use_id_column($this->_instance_id_column);
$instance->hydrate($row);
return $instance;
@@ -1118,7 +1178,7 @@
if ($part === '*') {
return $part;
}
- $quote_character = self::$_config['identifier_quote_character'];
+ $quote_character = self::$_config[$this->_which_db]['identifier_quote_character'];
return $quote_character . $part . $quote_character;
}
@@ -1135,8 +1195,9 @@
* Check the query cache for the given cache key. If a value
* is cached for the key, return the value. Otherwise, return false.
*/
- protected static function _check_query_cache($cache_key) {
- if (isset(self::$_query_cache[$cache_key])) {
+ protected static function _check_query_cache($cache_key, $which = self::DEFAULT_CONNECTION)
+ {
+ if (isset(self::$_query_cache[$which][$cache_key])) {
return self::$_query_cache[$cache_key];
}
return false;
@@ -1152,8 +1213,15 @@
/**
* Add the given value to the query cache.
*/
- protected static function _cache_query_result($cache_key, $value) {
- self::$_query_cache[$cache_key] = $value;
+ protected static function _cache_query_result(
+ $cache_key,
+ $value,
+ $which = self::DEFAULT_CONNECTION
+ ) {
+ if (!isset(self::$_query_cache[$which])) {
+ self::$_query_cache[$which] = array();
+ }
+ self::$_query_cache[$which][$cache_key] = $value;
}
/**
@@ -1162,19 +1230,19 @@
*/
protected function _run() {
$query = $this->_build_select();
- $caching_enabled = self::$_config['caching'];
+ $caching_enabled = self::$_config[$this->_which_db]['caching'];
if ($caching_enabled) {
$cache_key = self::_create_cache_key($query, $this->_values);
- $cached_result = self::_check_query_cache($cache_key);
+ $cached_result = self::_check_query_cache($cache_key, $this->_which_db);
if ($cached_result !== false) {
return $cached_result;
}
}
- self::_log_query($query, $this->_values);
- $statement = self::$_db->prepare($query);
+ self::_log_query($query, $this->_values, $this->_which_db);
+ $statement = self::$_db[$this->_which_db]->prepare($query);
$statement->execute($this->_values);
$rows = array();
@@ -1183,7 +1251,7 @@
}
if ($caching_enabled) {
- self::_cache_query_result($cache_key, $rows);
+ self::_cache_query_result($cache_key, $rows, $this->_which_db);
}
return $rows;
@@ -1219,10 +1287,10 @@
if (!is_null($this->_instance_id_column)) {
return $this->_instance_id_column;
}
- if (isset(self::$_config['id_column_overrides'][$this->_table_name])) {
- return self::$_config['id_column_overrides'][$this->_table_name];
+ if (isset(self::$_config[$this->_which_db]['id_column_overrides'][$this->_table_name])) {
+ return self::$_config[$this->_which_db]['id_column_overrides'][$this->_table_name];
} else {
- return self::$_config['id_column'];
+ return self::$_config[$this->_which_db]['id_column'];
}
}
@@ -1298,15 +1366,16 @@
$query = $this->_build_insert();
}
- self::_log_query($query, $values);
- $statement = self::$_db->prepare($query);
+ self::_log_query($query, $values, $this->_which_db);
+ $statement = self::$_db[$this->_which_db]->prepare($query);
$success = $statement->execute($values);
// If we've just inserted a new record, set the ID of this object
if ($this->_is_new) {
$this->_is_new = false;
if (is_null($this->id())) {
- $this->_data[$this->_get_id_column_name()] = self::$_db->lastInsertId();
+ $this->_data[$this->_get_id_column_name()] =
+ self::$_db[$this->_which_db]->lastInsertId();
}
}
@@ -1362,8 +1431,8 @@
"= ?",
));
$params = array($this->id());
- self::_log_query($query, $params);
- $statement = self::$_db->prepare($query);
+ self::_log_query($query, $params, $this->_which_db);
+ $statement = self::$_db[$this->_which_db]->prepare($query);
return $statement->execute($params);
}
@@ -1378,8 +1447,8 @@
$this->_quote_identifier($this->_table_name),
$this->_build_where(),
));
- self::_log_query($query, $this->_values);
- $statement = self::$_db->prepare($query);
+ self::_log_query($query, $this->_values, $this->_which_db);
+ $statement = self::$_db[$this->_which_db]->prepare($query);
return $statement->execute($this->_values);
}
diff --git a/test/test_classes.php b/test/test_classes.php
index a948d01..cf805c0 100644
--- a/test/test_classes.php
+++ b/test/test_classes.php
@@ -11,7 +11,11 @@
/**
* Return some dummy data
*/
- public function fetch($fetch_style=PDO::FETCH_BOTH, $cursor_orientation=PDO::FETCH_ORI_NEXT, $cursor_offset=0) {
+ public function fetch(
+ $fetch_style = PDO::FETCH_BOTH,
+ $cursor_orientation = PDO::FETCH_ORI_NEXT,
+ $cursor_offset = 0
+ ) {
if ($this->current_row == 5) {
return false;
} else {
@@ -39,6 +43,44 @@
}
/**
+ * Another mock PDOStatement class, for testing multiple connections
+ */
+ class DummyDifferentPDOStatement extends PDOStatement {
+
+ private $current_row = 0;
+ /**
+ * Return some dummy data
+ */
+ public function fetch(
+ $fetch_style = PDO::FETCH_BOTH,
+ $cursor_orientation = PDO::FETCH_ORI_NEXT,
+ $cursor_offset = 0
+ ) {
+ if ($this->current_row == 5) {
+ return false;
+ } else {
+ $this->current_row++;
+ return array('name' => 'Steve', 'age' => 80, 'id' => "{$this->current_row}");
+ }
+ }
+ }
+
+ /**
+ * A different mock database class, for testing multiple connections
+ * Mock database class implementing a subset of the PDO API.
+ */
+ class DummyDifferentPDO extends PDO {
+
+ /**
+ * Return a dummy PDO statement
+ */
+ public function prepare($statement, $driver_options = array()) {
+ $this->last_query = new DummyDifferentPDOStatement($statement);
+ return $this->last_query;
+ }
+ }
+
+ /**
*
* Class to provide simple testing functionality
*
@@ -110,12 +152,19 @@
* Check the provided string is equal to the last
* query generated by the dummy database class.
*/
- public static function check_equal($test_name, $query) {
+ public static function check_equal_query($test_name, $query) {
$last_query = ORM::get_last_query();
- if ($query === $last_query) {
+ self::check_equal_string($test_name, $query, $last_query);
+ }
+
+ /**
+ * Check the provided strings are equal
+ */
+ public static function check_equal_string($test_name, $s1, $s2) {
+ if ($s1 === $s2) {
self::report_pass($test_name);
} else {
- self::report_failure($test_name, $query, $last_query);
+ self::report_failure($test_name, $s1, $s2);
}
}
}
diff --git a/test/test_queries.php b/test/test_queries.php
index 8cc26d6..a16194e 100755
--- a/test/test_queries.php
+++ b/test/test_queries.php
@@ -18,229 +18,229 @@
ORM::for_table('widget')->find_many();
$expected = "SELECT * FROM `widget`";
- Tester::check_equal("Basic unfiltered find_many query", $expected);
+ Tester::check_equal_query("Basic unfiltered find_many query", $expected);
ORM::for_table('widget')->find_one();
$expected = "SELECT * FROM `widget` LIMIT 1";
- Tester::check_equal("Basic unfiltered find_one query", $expected);
+ Tester::check_equal_query("Basic unfiltered find_one query", $expected);
ORM::for_table('widget')->where_id_is(5)->find_one();
$expected = "SELECT * FROM `widget` WHERE `id` = '5' LIMIT 1";
- Tester::check_equal("where_id_is method", $expected);
+ Tester::check_equal_query("where_id_is method", $expected);
ORM::for_table('widget')->find_one(5);
$expected = "SELECT * FROM `widget` WHERE `id` = '5' LIMIT 1";
- Tester::check_equal("Filtering on ID passed into find_one method", $expected);
+ Tester::check_equal_query("Filtering on ID passed into find_one method", $expected);
ORM::for_table('widget')->count();
$expected = "SELECT COUNT(*) AS `count` FROM `widget` LIMIT 1";
- Tester::check_equal("COUNT query", $expected);
+ Tester::check_equal_query("COUNT query", $expected);
ORM::for_table('person')->max('height');
$expected = "SELECT MAX(`height`) AS `max` FROM `person` LIMIT 1";
- Tester::check_equal("MAX query", $expected);
+ Tester::check_equal_query("MAX query", $expected);
ORM::for_table('person')->min('height');
$expected = "SELECT MIN(`height`) AS `min` FROM `person` LIMIT 1";
- Tester::check_equal("MIN query", $expected);
+ Tester::check_equal_query("MIN query", $expected);
ORM::for_table('person')->avg('height');
$expected = "SELECT AVG(`height`) AS `avg` FROM `person` LIMIT 1";
- Tester::check_equal("AVG query", $expected);
+ Tester::check_equal_query("AVG query", $expected);
ORM::for_table('person')->sum('height');
$expected = "SELECT SUM(`height`) AS `sum` FROM `person` LIMIT 1";
- Tester::check_equal("SUM query", $expected);
+ Tester::check_equal_query("SUM query", $expected);
ORM::for_table('widget')->where('name', 'Fred')->find_one();
$expected = "SELECT * FROM `widget` WHERE `name` = 'Fred' LIMIT 1";
- Tester::check_equal("Single where clause", $expected);
+ Tester::check_equal_query("Single where clause", $expected);
ORM::for_table('widget')->where('name', 'Fred')->where('age', 10)->find_one();
$expected = "SELECT * FROM `widget` WHERE `name` = 'Fred' AND `age` = '10' LIMIT 1";
- Tester::check_equal("Multiple WHERE clauses", $expected);
+ Tester::check_equal_query("Multiple WHERE clauses", $expected);
ORM::for_table('widget')->where_not_equal('name', 'Fred')->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` != 'Fred'";
- Tester::check_equal("where_not_equal method", $expected);
+ Tester::check_equal_query("where_not_equal method", $expected);
ORM::for_table('widget')->where_like('name', '%Fred%')->find_one();
$expected = "SELECT * FROM `widget` WHERE `name` LIKE '%Fred%' LIMIT 1";
- Tester::check_equal("where_like method", $expected);
+ Tester::check_equal_query("where_like method", $expected);
ORM::for_table('widget')->where_not_like('name', '%Fred%')->find_one();
$expected = "SELECT * FROM `widget` WHERE `name` NOT LIKE '%Fred%' LIMIT 1";
- Tester::check_equal("where_not_like method", $expected);
+ Tester::check_equal_query("where_not_like method", $expected);
ORM::for_table('widget')->where_in('name', array('Fred', 'Joe'))->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` IN ('Fred', 'Joe')";
- Tester::check_equal("where_in method", $expected);
+ Tester::check_equal_query("where_in method", $expected);
ORM::for_table('widget')->where_not_in('name', array('Fred', 'Joe'))->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` NOT IN ('Fred', 'Joe')";
- Tester::check_equal("where_not_in method", $expected);
+ Tester::check_equal_query("where_not_in method", $expected);
ORM::for_table('widget')->limit(5)->find_many();
$expected = "SELECT * FROM `widget` LIMIT 5";
- Tester::check_equal("LIMIT clause", $expected);
+ Tester::check_equal_query("LIMIT clause", $expected);
ORM::for_table('widget')->limit(5)->offset(5)->find_many();
$expected = "SELECT * FROM `widget` LIMIT 5 OFFSET 5";
- Tester::check_equal("LIMIT and OFFSET clause", $expected);
+ Tester::check_equal_query("LIMIT and OFFSET clause", $expected);
ORM::for_table('widget')->order_by_desc('name')->find_one();
$expected = "SELECT * FROM `widget` ORDER BY `name` DESC LIMIT 1";
- Tester::check_equal("ORDER BY DESC", $expected);
+ Tester::check_equal_query("ORDER BY DESC", $expected);
ORM::for_table('widget')->order_by_asc('name')->find_one();
$expected = "SELECT * FROM `widget` ORDER BY `name` ASC LIMIT 1";
- Tester::check_equal("ORDER BY ASC", $expected);
+ Tester::check_equal_query("ORDER BY ASC", $expected);
ORM::for_table('widget')->order_by_expr('SOUNDEX(`name`)')->find_one();
$expected = "SELECT * FROM `widget` ORDER BY SOUNDEX(`name`) LIMIT 1";
- Tester::check_equal("ORDER BY expression", $expected);
+ Tester::check_equal_query("ORDER BY expression", $expected);
ORM::for_table('widget')->order_by_asc('name')->order_by_desc('age')->find_one();
$expected = "SELECT * FROM `widget` ORDER BY `name` ASC, `age` DESC LIMIT 1";
- Tester::check_equal("Multiple ORDER BY", $expected);
+ Tester::check_equal_query("Multiple ORDER BY", $expected);
ORM::for_table('widget')->group_by('name')->find_many();
$expected = "SELECT * FROM `widget` GROUP BY `name`";
- Tester::check_equal("GROUP BY", $expected);
+ Tester::check_equal_query("GROUP BY", $expected);
ORM::for_table('widget')->group_by('name')->group_by('age')->find_many();
$expected = "SELECT * FROM `widget` GROUP BY `name`, `age`";
- Tester::check_equal("Multiple GROUP BY", $expected);
+ Tester::check_equal_query("Multiple GROUP BY", $expected);
ORM::for_table('widget')->group_by_expr("FROM_UNIXTIME(`time`, '%Y-%m')")->find_many();
$expected = "SELECT * FROM `widget` GROUP BY FROM_UNIXTIME(`time`, '%Y-%m')";
- Tester::check_equal("GROUP BY expression", $expected);
+ Tester::check_equal_query("GROUP BY expression", $expected);
ORM::for_table('widget')->where('name', 'Fred')->limit(5)->offset(5)->order_by_asc('name')->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` = 'Fred' ORDER BY `name` ASC LIMIT 5 OFFSET 5";
- Tester::check_equal("Complex query", $expected);
+ Tester::check_equal_query("Complex query", $expected);
ORM::for_table('widget')->where_lt('age', 10)->where_gt('age', 5)->find_many();
$expected = "SELECT * FROM `widget` WHERE `age` < '10' AND `age` > '5'";
- Tester::check_equal("Less than and greater than", $expected);
+ Tester::check_equal_query("Less than and greater than", $expected);
ORM::for_table('widget')->where_lte('age', 10)->where_gte('age', 5)->find_many();
$expected = "SELECT * FROM `widget` WHERE `age` <= '10' AND `age` >= '5'";
- Tester::check_equal("Less than or equal and greater than or equal", $expected);
+ Tester::check_equal_query("Less than or equal and greater than or equal", $expected);
ORM::for_table('widget')->where_null('name')->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` IS NULL";
- Tester::check_equal("where_null method", $expected);
+ Tester::check_equal_query("where_null method", $expected);
ORM::for_table('widget')->where_not_null('name')->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` IS NOT NULL";
- Tester::check_equal("where_not_null method", $expected);
+ Tester::check_equal_query("where_not_null method", $expected);
ORM::for_table('widget')->where_raw('`name` = ? AND (`age` = ? OR `age` = ?)', array('Fred', 5, 10))->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` = 'Fred' AND (`age` = '5' OR `age` = '10')";
- Tester::check_equal("Raw WHERE clause", $expected);
+ Tester::check_equal_query("Raw WHERE clause", $expected);
ORM::for_table('widget')->where_raw('STRFTIME("%Y", "now") = ?', array(2012))->find_many();
$expected = "SELECT * FROM `widget` WHERE STRFTIME(\"%Y\", \"now\") = '2012'";
- Tester::check_equal("Raw WHERE clause with '%'", $expected);
+ Tester::check_equal_query("Raw WHERE clause with '%'", $expected);
ORM::for_table('widget')->where_raw('`name` = "Fred"')->find_many();
$expected = "SELECT * FROM `widget` WHERE `name` = \"Fred\"";
- Tester::check_equal("Raw WHERE clause with no parameters", $expected);
+ Tester::check_equal_query("Raw WHERE clause with no parameters", $expected);
ORM::for_table('widget')->where('age', 18)->where_raw('(`name` = ? OR `name` = ?)', array('Fred', 'Bob'))->where('size', 'large')->find_many();
$expected = "SELECT * FROM `widget` WHERE `age` = '18' AND (`name` = 'Fred' OR `name` = 'Bob') AND `size` = 'large'";
- Tester::check_equal("Raw WHERE clause in method chain", $expected);
+ Tester::check_equal_query("Raw WHERE clause in method chain", $expected);
ORM::for_table('widget')->raw_query('SELECT `w`.* FROM `widget` w')->find_many();
$expected = "SELECT `w`.* FROM `widget` w";
- Tester::check_equal("Raw query", $expected);
+ Tester::check_equal_query("Raw query", $expected);
ORM::for_table('widget')->raw_query('SELECT `w`.* FROM `widget` w WHERE `name` = ? AND `age` = ?', array('Fred', 5))->find_many();
$expected = "SELECT `w`.* FROM `widget` w WHERE `name` = 'Fred' AND `age` = '5'";
- Tester::check_equal("Raw query with parameters", $expected);
+ Tester::check_equal_query("Raw query with parameters", $expected);
ORM::for_table('widget')->select('name')->find_many();
$expected = "SELECT `name` FROM `widget`";
- Tester::check_equal("Simple result column", $expected);
+ Tester::check_equal_query("Simple result column", $expected);
ORM::for_table('widget')->select('name')->select('age')->find_many();
$expected = "SELECT `name`, `age` FROM `widget`";
- Tester::check_equal("Multiple simple result columns", $expected);
+ Tester::check_equal_query("Multiple simple result columns", $expected);
ORM::for_table('widget')->select('widget.name')->find_many();
$expected = "SELECT `widget`.`name` FROM `widget`";
- Tester::check_equal("Specify table name and column in result columns", $expected);
+ Tester::check_equal_query("Specify table name and column in result columns", $expected);
ORM::for_table('widget')->select('widget.name', 'widget_name')->find_many();
$expected = "SELECT `widget`.`name` AS `widget_name` FROM `widget`";
- Tester::check_equal("Aliases in result columns", $expected);
+ Tester::check_equal_query("Aliases in result columns", $expected);
ORM::for_table('widget')->select_expr('COUNT(*)', 'count')->find_many();
$expected = "SELECT COUNT(*) AS `count` FROM `widget`";
- Tester::check_equal("Literal expression in result columns", $expected);
+ Tester::check_equal_query("Literal expression in result columns", $expected);
ORM::for_table('widget')->select_many(array('widget_name' => 'widget.name'), 'widget_handle')->find_many();
$expected = "SELECT `widget`.`name` AS `widget_name`, `widget_handle` FROM `widget`";
- Tester::check_equal("Aliases in select many result columns", $expected);
+ Tester::check_equal_query("Aliases in select many result columns", $expected);
ORM::for_table('widget')->select_many_expr(array('count' => 'COUNT(*)'), 'SUM(widget_order)')->find_many();
$expected = "SELECT COUNT(*) AS `count`, SUM(widget_order) FROM `widget`";
- Tester::check_equal("Literal expression in select many result columns", $expected);
+ Tester::check_equal_query("Literal expression in select many result columns", $expected);
ORM::for_table('widget')->join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_many();
$expected = "SELECT * FROM `widget` JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Simple join", $expected);
+ Tester::check_equal_query("Simple join", $expected);
ORM::for_table('widget')->join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_one(5);
$expected = "SELECT * FROM `widget` JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id` WHERE `widget`.`id` = '5' LIMIT 1";
- Tester::check_equal("Simple join with where_id_is method", $expected);
+ Tester::check_equal_query("Simple join with where_id_is method", $expected);
ORM::for_table('widget')->inner_join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_many();
$expected = "SELECT * FROM `widget` INNER JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Inner join", $expected);
+ Tester::check_equal_query("Inner join", $expected);
ORM::for_table('widget')->left_outer_join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_many();
$expected = "SELECT * FROM `widget` LEFT OUTER JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Left outer join", $expected);
+ Tester::check_equal_query("Left outer join", $expected);
ORM::for_table('widget')->right_outer_join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_many();
$expected = "SELECT * FROM `widget` RIGHT OUTER JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Right outer join", $expected);
+ Tester::check_equal_query("Right outer join", $expected);
ORM::for_table('widget')->full_outer_join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))->find_many();
$expected = "SELECT * FROM `widget` FULL OUTER JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Full outer join", $expected);
+ Tester::check_equal_query("Full outer join", $expected);
ORM::for_table('widget')
->join('widget_handle', array('widget_handle.widget_id', '=', 'widget.id'))
->join('widget_nozzle', array('widget_nozzle.widget_id', '=', 'widget.id'))
->find_many();
$expected = "SELECT * FROM `widget` JOIN `widget_handle` ON `widget_handle`.`widget_id` = `widget`.`id` JOIN `widget_nozzle` ON `widget_nozzle`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Multiple join sources", $expected);
+ Tester::check_equal_query("Multiple join sources", $expected);
ORM::for_table('widget')->table_alias('w')->find_many();
$expected = "SELECT * FROM `widget` `w`";
- Tester::check_equal("Main table alias", $expected);
+ Tester::check_equal_query("Main table alias", $expected);
ORM::for_table('widget')->join('widget_handle', array('wh.widget_id', '=', 'widget.id'), 'wh')->find_many();
$expected = "SELECT * FROM `widget` JOIN `widget_handle` `wh` ON `wh`.`widget_id` = `widget`.`id`";
- Tester::check_equal("Join with alias", $expected);
+ Tester::check_equal_query("Join with alias", $expected);
ORM::for_table('widget')->join('widget_handle', "widget_handle.widget_id = widget.id")->find_many();
$expected = "SELECT * FROM `widget` JOIN `widget_handle` ON widget_handle.widget_id = widget.id";
- Tester::check_equal("Join with string constraint", $expected);
+ Tester::check_equal_query("Join with string constraint", $expected);
ORM::for_table('widget')->distinct()->select('name')->find_many();
$expected = "SELECT DISTINCT `name` FROM `widget`";
- Tester::check_equal("Select with DISTINCT", $expected);
+ Tester::check_equal_query("Select with DISTINCT", $expected);
$widget = ORM::for_table('widget')->create();
$widget->name = "Fred";
$widget->age = 10;
$widget->save();
$expected = "INSERT INTO `widget` (`name`, `age`) VALUES ('Fred', '10')";
- Tester::check_equal("Insert data", $expected);
+ Tester::check_equal_query("Insert data", $expected);
$widget = ORM::for_table('widget')->create();
$widget->name = "Fred";
@@ -248,14 +248,14 @@
$widget->set_expr('added', 'NOW()');
$widget->save();
$expected = "INSERT INTO `widget` (`name`, `age`, `added`) VALUES ('Fred', '10', NOW())";
- Tester::check_equal("Insert data containing an expression", $expected);
+ Tester::check_equal_query("Insert data containing an expression", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->name = "Fred";
$widget->age = 10;
$widget->save();
$expected = "UPDATE `widget` SET `name` = 'Fred', `age` = '10' WHERE `id` = '1'";
- Tester::check_equal("Update data", $expected);
+ Tester::check_equal_query("Update data", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->name = "Fred";
@@ -263,20 +263,20 @@
$widget->set_expr('added', 'NOW()');
$widget->save();
$expected = "UPDATE `widget` SET `name` = 'Fred', `age` = '10', `added` = NOW() WHERE `id` = '1'";
- Tester::check_equal("Update data containing an expression", $expected);
+ Tester::check_equal_query("Update data containing an expression", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->set(array("name" => "Fred", "age" => 10));
$widget->save();
$expected = "UPDATE `widget` SET `name` = 'Fred', `age` = '10' WHERE `id` = '1'";
- Tester::check_equal("Update multiple fields", $expected);
+ Tester::check_equal_query("Update multiple fields", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->set(array("name" => "Fred", "age" => 10));
$widget->set_expr(array("added" => "NOW()", "lat_long" => "GeomFromText('POINT(1.2347 2.3436)')"));
$widget->save();
$expected = "UPDATE `widget` SET `name` = 'Fred', `age` = '10', `added` = NOW(), `lat_long` = GeomFromText('POINT(1.2347 2.3436)') WHERE `id` = '1'";
- Tester::check_equal("Update multiple fields containing an expression", $expected);
+ Tester::check_equal_query("Update multiple fields containing an expression", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->set(array("name" => "Fred", "age" => 10));
@@ -284,41 +284,72 @@
$widget->lat_long = 'unknown';
$widget->save();
$expected = "UPDATE `widget` SET `name` = 'Fred', `age` = '10', `added` = NOW(), `lat_long` = 'unknown' WHERE `id` = '1'";
- Tester::check_equal("Update multiple fields containing an expression (override previously set expression with plain value)", $expected);
+ Tester::check_equal_query("Update multiple fields containing an expression (override previously set expression with plain value)", $expected);
$widget = ORM::for_table('widget')->find_one(1);
$widget->delete();
$expected = "DELETE FROM `widget` WHERE `id` = '1'";
- Tester::check_equal("Delete data", $expected);
+ Tester::check_equal_query("Delete data", $expected);
$widget = ORM::for_table('widget')->where_equal('age', 10)->delete_many();
$expected = "DELETE FROM `widget` WHERE `age` = '10'";
- Tester::check_equal("Delete many", $expected);
+ Tester::check_equal_query("Delete many", $expected);
ORM::raw_execute("INSERT OR IGNORE INTO `widget` (`id`, `name`) VALUES (?, ?)", array(1, 'Tolstoy'));
$expected = "INSERT OR IGNORE INTO `widget` (`id`, `name`) VALUES ('1', 'Tolstoy')";
- Tester::check_equal("Raw execute", $expected); // A bit of a silly test, as query is passed through
+ Tester::check_equal_query("Raw execute", $expected); // A bit of a silly test, as query is passed through
+ // Tests of muliple connections
+ define('ALTERNATE', 'alternate');
+ ORM::set_db(new DummyDifferentPDO('sqlite::memory:'), 'alternate');
+ ORM::configure('logging', true, ALTERNATE);
+
+ $person1 = ORM::for_table('person')->find_one();
+ $person2 = ORM::for_table('person', ALTERNATE)->find_one();
+ $expected = "SELECT * FROM `person` LIMIT 1";
+
+ Tester::check_equal_string("Multiple connection (1)", $person1->name, 'Fred');
+ Tester::check_equal_string("Multiple connection (2)", $person2->name, 'Steve');
+
+ $expectedToo = "SELECT * FROM `widget`";
+ ORM::raw_execute("SELECT * FROM `widget`", array(), ALTERNATE);
+
+ Tester::check_equal_string(
+ "Multiple connection log (1)",
+ ORM::get_last_query(ORM::DEFAULT_CONNECTION),
+ $expected
+ );
+ Tester::check_equal_string(
+ "Multiple connection query log (2)",
+ ORM::get_last_query(),
+ $expectedToo
+ );
+ Tester::check_equal_string(
+ "Multiple connection query log (3)",
+ ORM::get_last_query(ALTERNATE),
+ $expectedToo
+ );
+
// Regression tests
$widget = ORM::for_table('widget')->select('widget.*')->find_one();
$expected = "SELECT `widget`.* FROM `widget` LIMIT 1";
- Tester::check_equal("Issue #12 - incorrect quoting of column wildcard", $expected);
+ Tester::check_equal_query("Issue #12 - incorrect quoting of column wildcard", $expected);
$widget = ORM::for_table('widget')->where_raw('username LIKE "ben%"')->find_many();
$expected = 'SELECT * FROM `widget` WHERE username LIKE "ben%"';
- Tester::check_equal('Issue #57 - _log_query method raises a warning when query contains "%"', $expected);
+ Tester::check_equal_query('Issue #57 - _log_query method raises a warning when query contains "%"', $expected);
$widget = ORM::for_table('widget')->where_raw('comments LIKE "has been released?%"')->find_many();
$expected = 'SELECT * FROM `widget` WHERE comments LIKE "has been released?%"';
- Tester::check_equal('Issue #57 - _log_query method raises a warning when query contains "?"', $expected);
+ Tester::check_equal_query('Issue #57 - _log_query method raises a warning when query contains "?"', $expected);
// Tests that alter Idiorm's config are done last
ORM::configure('id_column', 'primary_key');
ORM::for_table('widget')->find_one(5);
$expected = "SELECT * FROM `widget` WHERE `primary_key` = '5' LIMIT 1";
- Tester::check_equal("Setting: id_column", $expected);
+ Tester::check_equal_query("Setting: id_column", $expected);
ORM::configure('id_column_overrides', array(
'widget' => 'widget_id',
@@ -327,27 +358,27 @@
ORM::for_table('widget')->find_one(5);
$expected = "SELECT * FROM `widget` WHERE `widget_id` = '5' LIMIT 1";
- Tester::check_equal("Setting: id_column_overrides, first test", $expected);
+ Tester::check_equal_query("Setting: id_column_overrides, first test", $expected);
ORM::for_table('widget_handle')->find_one(5);
$expected = "SELECT * FROM `widget_handle` WHERE `widget_handle_id` = '5' LIMIT 1";
- Tester::check_equal("Setting: id_column_overrides, second test", $expected);
+ Tester::check_equal_query("Setting: id_column_overrides, second test", $expected);
ORM::for_table('widget_nozzle')->find_one(5);
$expected = "SELECT * FROM `widget_nozzle` WHERE `primary_key` = '5' LIMIT 1";
- Tester::check_equal("Setting: id_column_overrides, third test", $expected);
+ Tester::check_equal_query("Setting: id_column_overrides, third test", $expected);
ORM::for_table('widget')->use_id_column('new_id')->find_one(5);
$expected = "SELECT * FROM `widget` WHERE `new_id` = '5' LIMIT 1";
- Tester::check_equal("Instance ID column, first test", $expected);
+ Tester::check_equal_query("Instance ID column, first test", $expected);
ORM::for_table('widget_handle')->use_id_column('new_id')->find_one(5);
$expected = "SELECT * FROM `widget_handle` WHERE `new_id` = '5' LIMIT 1";
- Tester::check_equal("Instance ID column, second test", $expected);
+ Tester::check_equal_query("Instance ID column, second test", $expected);
ORM::for_table('widget_nozzle')->use_id_column('new_id')->find_one(5);
$expected = "SELECT * FROM `widget_nozzle` WHERE `new_id` = '5' LIMIT 1";
- Tester::check_equal("Instance ID column, third test", $expected);
+ Tester::check_equal_query("Instance ID column, third test", $expected);
// Test caching. This is a bit of a hack.
ORM::configure('caching', true);
@@ -355,7 +386,25 @@
ORM::for_table('widget')->where('name', 'Bob')->where('age', 42)->find_one();
$expected = ORM::get_last_query();
ORM::for_table('widget')->where('name', 'Fred')->where('age', 17)->find_one(); // this shouldn't run a query!
- Tester::check_equal("Caching, same query not run twice", $expected);
+ Tester::check_equal_query("Caching, same query not run twice", $expected);
+
+ // Test caching with multiple connections (also a bit of a hack)
+ ORM::configure('caching', true, ALTERNATE);
+ ORM::for_table('widget', ALTERNATE)->where('name', 'Steve')->where('age', 80)->find_one();
+ ORM::for_table('widget', ALTERNATE)->where('name', 'Tom')->where('age', 120)->find_one();
+ $expectedToo = ORM::get_last_query();
+ ORM::for_table('widget', ALTERNATE)->where('name', 'Steve')->where('age', 80)->find_one(); // this shouldn't run a query!
+ Tester::check_equal_query(
+ "Multi-connection caching, same query not run twice, on alternate connection",
+ $expectedToo
+ );
+
+ ORM::for_table('widget')->where('name', 'Fred')->where('age', 17)->find_one(); // this still shouldn't run a query!
+ Tester::check_equal_string(
+ "Multi-conneciton caching, same query not run twice across connections",
+ ORM::get_last_query(ORM::DEFAULT_CONNECTION),
+ $expected
+ );
Tester::report();