Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Expression value support for PDO datasources and value casting #492

Merged
merged 1 commit into from

3 participants

@jails
Collaborator

Close #28 and #402.

@nateabele nateabele merged commit 64187f2 into UnionOfRAD:data
@nateabele
Owner

One of the tests in the PR failed:

Assertion assertIdentical failed in lithium\tests\cases\data\source\DatabaseTest::testValueWithSchema() on line 104:
expected: '\'1970-01-01 01:00:00\''
result: '\'1970-01-01 00:00:00\''

Looks like it was somehow off by an hour. Any ideas?

@jails
Collaborator

Sorry I had not even noticed the 01:00:00. This is probably due to my time zone (UTC+1)

@nateabele
Owner

Okay, so if I just change the assertion, everything will be okay, or do we need to do timezone offset handling as well?

@jails
Collaborator

Yeah it will be ok for travis but it might fail for people which use a different time zone. I think te best would be to set 'UTC' as the default time zone for tests. But imo we can patch this locally with someting like :

$date = date_default_timezone_get();
date_default_timezone_set('UTC');
$result = $this->db->value('Hello World', array('type' => 'timestamp'));
date_default_timezone_set($date);
@davidpersson

I'd suggest to put the change to the timezone + the reverting later at the start end of that test method needing it. As long as this is just needed once or twice I think that approach is without any side-effects thus good.

Also see http://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)

@jails jails referenced this pull request from a commit
@jails jails Fix #492 time zone issue. f7fb3c5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
50 data/source/Database.php
@@ -190,24 +190,22 @@ public function value($value, array $schema = array()) {
}
return $value;
}
+
+ if (is_object($value) && isset($value->scalar)) {
+ return $value->scalar;
+ }
+
if ($value === null) {
return 'NULL';
}
+
switch ($type = isset($schema['type']) ? $schema['type'] : $this->_introspectType($value)) {
case 'boolean':
- return $this->_toNativeBoolean($value);
case 'float':
- return floatval($value);
case 'integer':
- return intval($value);
- case 'timestamp':
- if ($value === 'CURRENT_TIMESTAMP') {
- return 'NULL';
- } else if (is_numeric($value)) {
- return date('Y-m-d H:i:s', $value);
- } else {
- return strtotime($value);
- }
+ return $this->_cast($type, $value);
+ default:
+ return $this->connection->quote($this->_cast($type, $value));
}
}
@@ -942,6 +940,36 @@ public function cast($entity, array $data, array $options = array()) {
return $data;
}
+ /**
+ * Cast a value according to a column type.
+ *
+ * @param string $type Name of the column type
+ * @param string $value Value to cast
+ *
+ * @return mixed Casted value
+ *
+ */
+ protected function _cast($type, $value) {
+ if (is_object($value) || $value === null) {
+ return $value;
+ }
+ if ($type == 'boolean') {
+ return $this->_toNativeBoolean($value);
+ }
+ if (!isset($this->_columns[$type]) || !isset($this->_columns[$type]['formatter'])) {
+ return $value;
+ }
+
+ $column = $this->_columns[$type];
+
+ switch ($column['formatter']) {
+ case 'date':
+ return $column['formatter']($column['format'], strtotime($value));
+ default:
+ return $column['formatter']($value);
+ }
+ }
+
protected function _createFields($data, $schema, $context) {
$fields = $values = array();
View
49 tests/cases/data/source/DatabaseTest.php
@@ -94,14 +94,29 @@ public function testValueWithSchema() {
$result = $this->db->value('1', array('type' => 'string'));
$this->assertIdentical("'1'", $result);
- $result = $this->db->value('CURRENT_TIMESTAMP', array('type' => 'timestamp'));
- $this->assertIdentical('NULL', $result);
+ $result = $this->db->value((object) 'CURRENT_TIMESTAMP', array('type' => 'timestamp'));
+ $this->assertIdentical('CURRENT_TIMESTAMP', $result);
+
+ $result = $this->db->value((object) 'REGEXP "^fo$"');
+ $this->assertIdentical('REGEXP "^fo$"', $result);
+
+ $result = $this->db->value('Hello World', array('type' => 'timestamp'));
+ $this->assertIdentical("'1970-01-01 01:00:00'", $result);
- $result = $this->db->value('1234567', array('type' => 'timestamp'));
- $this->assertIdentical(date('Y-m-d H:i:s', 1234567), $result);
+ $result = $this->db->value('2012-05-25 22:44:00', array('type' => 'timestamp'));
+ $this->assertIdentical("'2012-05-25 22:44:00'", $result);
+
+ $result = $this->db->value('2012-05-25', array('type' => 'date'));
+ $this->assertIdentical("'2012-05-25'", $result);
$result = $this->db->value('now', array('type' => 'timestamp'));
- $this->assertIdentical(time(), $result);
+ $this->assertPattern("/^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'/", $result);
+
+ $result = $this->db->value('now', array('type' => 'date'));
+ $this->assertPattern("/^'\d{4}-\d{2}-\d{2}'/", $result);
+
+ $result = $this->db->value('now', array('type' => 'time'));
+ $this->assertPattern("/^'\d{2}:\d{2}:\d{2}'/", $result);
}
public function testValueByIntrospect() {
@@ -571,7 +586,10 @@ public function testConditions() {
'or' => array(
'id' => 'value1',
'title' => 'value2',
- 'and' => array('author_id' => '1', 'created' => '2'),
+ 'and' => array(
+ 'author_id' => '1',
+ 'created' => '2012-05-25 23:41:00'
+ ),
array('title' => 'value2'),
array('title' => null)
),
@@ -581,9 +599,10 @@ public function testConditions() {
));
$sql = "SELECT * FROM {mock_database_posts} AS {MockDatabasePost} WHERE ";
$sql .= "({MockDatabasePost}.{id} = 0 OR {MockDatabasePost}.{title} = 'value2' OR ";
- $sql .= "({MockDatabasePost}.{author_id} = 1 AND {MockDatabasePost}.{created} = '2') OR ";
- $sql .= "({MockDatabasePost}.{title} = 'value2') OR ({MockDatabasePost}.{title} IS NULL)) AND ";
- $sql .= "{MockDatabasePost}.{id} = 3 AND {MockDatabasePost}.{author_id} = 0;";
+ $sql .= "({MockDatabasePost}.{author_id} = 1 AND {MockDatabasePost}.{created} = ";
+ $sql .= "'2012-05-25 23:41:00') OR ({MockDatabasePost}.{title} = 'value2') OR ";
+ $sql .= "({MockDatabasePost}.{title} IS NULL)) AND {MockDatabasePost}.{id} = 3 AND ";
+ $sql .= "{MockDatabasePost}.{author_id} = 0;";
$this->assertEqual($sql, $this->db->renderCommand($query));
$query = new Query(array(
@@ -603,7 +622,10 @@ public function testHaving() {
'or' => array(
'id' => 'value1',
'title' => 'value2',
- 'and' => array('author_id' => '1', 'created' => '2'),
+ 'and' => array(
+ 'author_id' => '1',
+ 'created' => '2012-05-25 23:41:00'
+ ),
array('title' => 'value2'),
array('title' => null)
),
@@ -613,9 +635,10 @@ public function testHaving() {
));
$sql = "SELECT * FROM {mock_database_posts} AS {MockDatabasePost} HAVING ";
$sql .= "({MockDatabasePost}.{id} = 0 OR {MockDatabasePost}.{title} = 'value2' OR ";
- $sql .= "({MockDatabasePost}.{author_id} = 1 AND {MockDatabasePost}.{created} = '2') OR ";
- $sql .= "({MockDatabasePost}.{title} = 'value2') OR ({MockDatabasePost}.{title} IS NULL)) AND ";
- $sql .= "{MockDatabasePost}.{id} = 3 AND {MockDatabasePost}.{author_id} = 0;";
+ $sql .= "({MockDatabasePost}.{author_id} = 1 AND {MockDatabasePost}.{created} = ";
+ $sql .= "'2012-05-25 23:41:00') OR ({MockDatabasePost}.{title} = 'value2') OR ";
+ $sql .= "({MockDatabasePost}.{title} IS NULL)) AND {MockDatabasePost}.{id} = 3 AND ";
+ $sql .= "{MockDatabasePost}.{author_id} = 0;";
$this->assertEqual($sql, $this->db->renderCommand($query));
$query = new Query(array(
View
32 tests/mocks/data/model/MockDatabase.php
@@ -12,10 +12,42 @@
class MockDatabase extends \lithium\data\source\Database {
+ /**
+ * Mock column type definitions.
+ *
+ * @var array
+ */
+ protected $_columns = array(
+ 'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
+ 'string' => array('name' => 'varchar', 'length' => 255),
+ 'text' => array('name' => 'text'),
+ 'integer' => array('name' => 'int', 'length' => 11, 'formatter' => 'intval'),
+ 'float' => array('name' => 'float', 'formatter' => 'floatval'),
+ 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
+ 'timestamp' => array(
+ 'name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'
+ ),
+ 'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
+ 'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
+ 'binary' => array('name' => 'blob'),
+ 'boolean' => array('name' => 'tinyint', 'length' => 1)
+ );
+
+ public $connection = null;
+
public $sql = null;
protected $_quotes = array('{', '}');
+ public function __construct(array $config = array()) {
+ parent::__construct($config);
+ $this->connection = $this;
+ }
+
+ public function quote($value) {
+ return "'{$value}'";
+ }
+
public function connect() {
return true;
}
Something went wrong with that request. Please try again.