Skip to content
Permalink
Browse files

Starting to implement orWhere and andWhere

  • Loading branch information...
lorenzo committed Dec 31, 2012
1 parent 30e9369 commit dfb2964353129ba0cdc3fa85b1dbaf73fc136fcb
@@ -55,7 +55,7 @@ public function bind($token, $value, $type) {
if (is_numeric($token)) {
$param = '?';
} else if ($param[0] !== ':') {
$identifier = substr(spl_object_hash($this), -7);
$identifier = spl_object_hash($this);
$param = sprintf(':c%s%s', $identifier, count($this->_bindings));
}
@@ -101,7 +101,7 @@ protected function _addConditions(array $conditions, array $types) {
foreach ($conditions as $k => $c) {
$numericKey = is_numeric($k);
if ($numericKey && !empty($c)) {
if ($numericKey && empty($c)) {
continue;
}
@@ -111,11 +111,11 @@ protected function _addConditions(array $conditions, array $types) {
}
if ($numericKey && is_array($c) || in_array(strtolower($k), $operators)) {
$this->_conditions[] = new self($c, $k);
$this->_conditions[] = new self($c, $types, $numericKey ? 'AND' : $k);
continue;
}
if ($conditions instanceof QueryExpression && count($c) > 0) {
if ($c instanceof QueryExpression && count($c) > 0) {
$this->_conditions[] = $c;
continue;
}
@@ -79,21 +79,23 @@ public function connection($connection = null) {
public function execute() {
$statement = $this->_connection->prepare($this->sql());
$visitor = function($expression) use($statement) {
$binder = function($expression) use($statement) {
if (!($expression instanceof QueryExpression)) {
return;
}
$bindings = $expression->bindings();
$params = $values = $types = [];
foreach ($bindings as $b) {
$params[$b['placeholder']] = $b['value'];
$types[$b['placeholder']] = $b['type'];
}
$statement->bind($params, $types);
//Visit all expressions and subexpressions to get every bound value
$expression->traverse(function($expression) use($statement) {
$params = $types = [];
foreach ($expression->bindings() as $b) {
$params[$b['placeholder']] = $b['value'];
$types[$b['placeholder']] = $b['type'];
}
$statement->bind($params, $types);
});
};
$this->build($visitor);
$this->build($binder);
$statement->execute();
return $statement;
}
@@ -239,13 +241,31 @@ public function where($conditions = null, $types = [], $overwrite = false) {
return $this;
}
public function andWhere($field, $value = null) {
$this->where($field, $value);
public function andWhere($conditions, $types = []) {
$where = $this->_parts['where'];
if ($where->type() === 'AND') {
$where->add($conditions, $types);
} else {
$where = new QueryExpression([$conditions, $where], $types, 'AND');
}
$this->_parts['where'] = $where;
$this->_dirty = true;
return $this;
}
public function orWhere($field, $value = null) {
$this->_parts['where']->orWhere($field, $value);
public function orWhere($conditions, $types = []) {
$where = $this->_parts['where'];
if ($where->type() === 'OR') {
$where->add($conditions, $types);
} else {
$where = new QueryExpression([$conditions, $where], $types, 'OR');
}
$this->_parts['where'] = $where;
$this->_dirty = true;
return $this;
}
@@ -35,9 +35,9 @@ public function cast($value, $type) {
**/
public function matchTypes($columns, $types) {
if (!is_int(key($types))) {
$positons = array_intersect_key(array_flip($columns), $types);
$types = array_intersect_key($types, $positons);
$types = array_combine($positons, $types);
$positions = array_intersect_key(array_flip($columns), $types);
$types = array_intersect_key($types, $positions);
$types = array_combine($positions, $types);
}
return $types;
}
@@ -327,7 +327,7 @@ public function testUpdateWithConditionsAndTypes() {
$title = 'changed the title!';
$body = new \DateTime('2012-01-01');
$values = compact('title', 'body');
$this->connection->update('things', $values, ['id' => '1-string-parsed-as-int'], ['body' => 'date', 'id' => 'integer']);
$this->connection->update('things', $values, ['id' => '1-string-parsed-as-int'], ['body' => 'date', 'id' => 'integer']);
$result = $this->connection->execute('SELECT * FROM things WHERE title = :title AND body = :body', $values, ['body' => 'date']);
$this->assertCount(1, $result);
$row = $result->fetch('assoc');
@@ -35,6 +35,7 @@ public function setUp() {
public function tearDown() {
$this->connection->execute('DROP TABLE IF EXISTS articles');
$this->connection->execute('DROP TABLE IF EXISTS authors');
$this->connection->execute('DROP TABLE IF EXISTS dates');
}
/**
@@ -66,6 +67,8 @@ protected function _insertTwoRecords() {
$result->bindValue(3, 'another body');
$result->bindValue(4, 2);
$result->execute();
return $result;
}
/**
@@ -364,4 +367,17 @@ public function testSelectWhereTypes() {
$this->assertEquals(array('id' => 1), $result->fetch('assoc'));
}
public function testSelectOrWhere() {
$this->_insertDateRecords();
$query = new Query($this->connection);
$result = $query
->select(['id'])
->from('dates')
->where(['posted' => new \DateTime('2012-12-21 12:00')], ['posted' => 'datetime'])
->orWhere(['posted' => new \DateTime('2012-12-22 12:00')], ['posted' => 'datetime'])

This comment has been minimized.

Copy link
@pocketcrocodile

pocketcrocodile Jan 2, 2013

It's commonly done like this, but inconsistent. (not the test, but the code example).

This comment has been minimized.

Copy link
@lorenzo

lorenzo Jan 2, 2013

Author Member

Sorry, what is inconsistent?

This comment has been minimized.

Copy link
@pocketcrocodile

pocketcrocodile Jan 2, 2013

the syntax with the methods where, orWhere, andWhere. imagine just a little more complex where condition with at minimum 1 level of braces and try to express it with the andWhere orWhere methods. but perhaps this discussion comes to late.

This comment has been minimized.

Copy link
@lorenzo

lorenzo via email Jan 2, 2013

Author Member
->execute();
$this->assertCount(2, $result);
$this->assertEquals(array('id' => 1), $result->fetch('assoc'));
$this->assertEquals(array('id' => 2), $result->fetch('assoc'));
}
}

2 comments on commit dfb2964

@markstory

This comment has been minimized.

Copy link
Member

replied Jan 2, 2013

Would it be simpler to not have these tests hit the database, and instead just compare the generated SQL of the query object?

@lorenzo

This comment has been minimized.

Copy link
Member Author

replied Jan 2, 2013

@markstory To an extent, yes. My main reason of doing an integration test instead just inte test the query object alone is because testing parameter binding is super tricky and is best validated by PDO itself. Also because in the long run I want to achieve (almost) complete independence of the driver being used and this is the best way I can provide to make sure that with a single test case I cover all drivers.

Please sign in to comment.
You can’t perform that action at this time.