Skip to content

Commit

Permalink
Adding support fro traversing TupleComparison expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Jan 11, 2014
1 parent 6733a93 commit 9b92cc8
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
67 changes: 62 additions & 5 deletions Cake/Database/Expression/TupleComparison.php
Expand Up @@ -51,24 +51,29 @@ public function sql(ValueBinder $generator) {
$fields[] = $field instanceof ExpressionInterface ? $field->sql($generator) : $field;
}

$values = $this->_extractValues($generator);
$values = $this->_stringifyValues($generator);

$field = implode(', ', $fields);
return sprintf($template, $field, $this->_conjunction, $values);
}

protected function _extractValues($generator) {
/**
* Returns a string with the values as placeholders in a string to be used
* for the SQL version of this expression
*
* @param \Cake\Database\ValueBiender $generator
* @return string
*/
protected function _stringifyValues($generator) {
$values = [];
foreach ($this->getValue() as $i => $value) {
if ($value instanceof ExpressionInterface) {
$values[] = $value->sql($generator);
continue;
}

$multi = in_array(strtolower($this->_conjunction), ['in', 'not in']);
$type = isset($this->_type[$i]) ? $this->_type[$i] : null;

if ($multi || strpos($type, '[]') !== false) {
if ($this->_isMulti($i, $type)) {
$type = str_replace('[]', '', $type);
$value = $this->_flattenValue($value, $generator, $type);
$values[] = "($value)";
Expand All @@ -81,4 +86,56 @@ protected function _extractValues($generator) {
return implode(', ', $values);
}

/*
* Traverses the tree of expressions stored in this object, visiting first
* expressions in the left hand side and the the rest.
*
* Callback function receives as only argument an instance of a ExpresisonInterface
*
* @param callable $callable
* @return void
*/
public function traverse(callable $callable) {
foreach ($this->getField() as $field) {
$this->_traverseValue($field, $callable);
}
foreach ($this->getValue() as $i => $value) {
$type = isset($this->_type[$i]) ? $this->_type[$i] : null;
if ($this->_isMulti($type)) {
foreach ($value as $v) {
$this->_traverseValue($v, $callable);
}
} else {
$this->_traverseValue($value, $callable);
}
}
}

/**
* Conditionally executes the callback for the passed value if
* it is an ExpressionInterface
*
* @param mixed $value
* @Param callable $callable
* @return void
*/
protected function _traverseValue($value, $callable) {
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
}
}

/**
* Determines if each of the values in this expressions is a tuple in
* itself
*
* @param string $type the type to bind for values
* @return boolean
*/
protected function _isMulti($type) {
$multi = in_array(strtolower($this->_conjunction), ['in', 'not in']);
return $multi || strpos($type, '[]') !== false;
}

}
35 changes: 34 additions & 1 deletion Test/TestCase/Database/Expression/TupleComparisonTest.php
Expand Up @@ -75,7 +75,6 @@ public function testTupleWithExpressionValues() {
* @return void
*/
public function testTupleWithInComparison() {
$value1 = new QueryExpression(['a' => 1]);
$f = new TupleComparison(
['field1', 'field2'],
[[1, 2], [3, 4]],
Expand All @@ -90,4 +89,38 @@ public function testTupleWithInComparison() {
$this->assertSame(4, $binder->bindings()[':c3']['value']);
}

/**
* Tests traversing
*
* @return void
*/
public function testTraverse() {
$value1 = new QueryExpression(['a' => 1]);
$field2 = new QueryExpression(['b' => 2]);
$f = new TupleComparison(['field1', $field2], [$value1, 2], ['integer', 'integer'], '=');
$binder = new ValueBinder;
$expressions = [];

$collector = function($e) use (&$expressions) {
$expressions[] = $e;
};

$f->traverse($collector);
$this->assertCount(4, $expressions);
$this->assertSame($field2, $expressions[0]);
$this->assertSame($value1, $expressions[2]);

$f = new TupleComparison(
['field1', $field2],
[[1, 2], [3, $value1]],
['integer', 'integer'],
'IN'
);
$expressions = [];
$f->traverse($collector);
$this->assertCount(4, $expressions);
$this->assertSame($field2, $expressions[0]);
$this->assertSame($value1, $expressions[2]);
}

}

0 comments on commit 9b92cc8

Please sign in to comment.