Enclosing virtual fields in parentheses to avoid SQL errors

Added new tests to improve  code coverage on virtual fields
This commit is contained in:
José Lorenzo Rodríguez 2009-12-17 14:42:46 -04:30
parent c65e2f3f18
commit 8f29f59c1a
2 changed files with 124 additions and 5 deletions

View file

@ -1788,7 +1788,7 @@ class DboSource extends DataSource {
foreach ($fields as $field) {
$virtualField = $this->name("{$alias}__{$field}");
$expression = $this->__quoteFields($model->getVirtualField($field));
$virtual[] = $expression . " {$this->alias} {$virtualField}";
$virtual[] = '(' .$expression . ") {$this->alias} {$virtualField}";
}
return $virtual;
}
@ -2123,7 +2123,9 @@ class DboSource extends DataSource {
break;
}
}
if ($virtual) {
return "({$key}) {$operator} {$value}";
}
return "{$key} {$operator} {$value}";
}
@ -2241,7 +2243,7 @@ class DboSource extends DataSource {
$key = trim($key);
if (!preg_match('/\s/', $key) && !strpos($key,'.')) {
if (is_object($model) && $model->isVirtualField($key)) {
$key = $this->__quoteFields($model->getVirtualField($key));
$key = '('.$this->__quoteFields($model->getVirtualField($key)).')';
} else {
$key = $this->name($key);
}

View file

@ -3609,8 +3609,8 @@ class DboSourceTest extends CakeTestCase {
$this->testDb->fieldParameters['param'] = array(
'value' => 'COLLATE',
'quote' => false,
'join' => ' ',
'column' => 'Collate',
'join' => ' ',
'column' => 'Collate',
'position' => 'beforeDefault',
'options' => array('GOOD', 'OK')
);
@ -4081,5 +4081,122 @@ class DboSourceTest extends CakeTestCase {
$this->assertNoPattern('/Num:/s', $contents);
$this->assertNoPattern('/Took:/s', $contents);
}
function testVirtualFields() {
$this->loadFixtures('Article');
$Article =& ClassRegistry::init('Article');
$Article->virtualFields = array(
'this_moment' => 'NOW()',
'two' => '1 + 1',
'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id'
);
$result = $this->db->fields($Article);
$expected = array(
'`Article`.`id`',
'`Article`.`user_id`',
'`Article`.`title`',
'`Article`.`body`',
'`Article`.`published`',
'`Article`.`created`',
'`Article`.`updated`',
'(NOW()) AS `Article__this_moment`',
'(1 + 1) AS `Article__two`',
'(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `Article__comment_count`'
);
$this->assertEqual($expected,$result);
$result = $this->db->fields($Article,null,array('this_moment','title'));
$expected = array(
'`Article`.`title`',
'(NOW()) AS `Article__this_moment`',
);
$this->assertEqual($expected,$result);
}
function testVirtualFieldsInConditions() {
$this->loadFixtures('Article');
$Article =& ClassRegistry::init('Article');
$Article->virtualFields = array(
'this_moment' => 'NOW()',
'two' => '1 + 1',
'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id'
);
$conditions = array('two' => 2);
$result = $this->db->conditions($conditions,true,false,$Article);
$expected = '(1 + 1) = 2';
$this->assertEqual($expected,$result);
$conditions = array('this_moment BETWEEN ? AND ?' => array(1,2));
$expected = 'NOW() BETWEEN 1 AND 2';
$result = $this->db->conditions($conditions,true,false,$Article);
$this->assertEqual($expected,$result);
$conditions = array('comment_count >' => 5);
$expected = '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) > 5';
$result = $this->db->conditions($conditions,true,false,$Article);
$this->assertEqual($expected,$result);
$conditions = array('NOT' => array('two' => 2));
$result = $this->db->conditions($conditions,true,false,$Article);
$expected = 'NOT ((1 + 1) = 2)';
$this->assertEqual($expected,$result);
}
function testVirtualFieldsInOrder() {
$this->loadFixtures('Article');
$Article =& ClassRegistry::init('Article');
$Article->virtualFields = array(
'this_moment' => 'NOW()',
'two' => '1 + 1',
);
$order = array('two','this_moment');
$result = $this->db->order($order,'ASC',$Article);
$expected = ' ORDER BY (1 + 1) ASC, (NOW()) ASC';
$this->assertEqual($expected,$result);
}
function testVirtualFieldsInCalculate() {
$this->loadFixtures('Article');
$Article =& ClassRegistry::init('Article');
$Article->virtualFields = array(
'this_moment' => 'NOW()',
'two' => '1 + 1',
'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id'
);
$result = $this->db->calculate($Article,'count',array('this_moment'));
$expected = 'COUNT(NOW()) AS `count`';
$this->assertEqual($expected,$result);
$result = $this->db->calculate($Article,'max',array('comment_count'));
$expected = 'MAX(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `comment_count`';
$this->assertEqual($expected,$result);
}
function testVirtualFieldsFetch() {
$this->loadFixtures('Article','Comment');
$Article =& ClassRegistry::init('Article');
$Article->virtualFields = array(
'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id'
);
$conditions = array('comment_count >' => 2);
$query = 'SELECT ' . join(',',$this->db->fields($Article,null,array('id','comment_count'))) .
' FROM ' . $this->db->fullTableName($Article) . ' Article ' . $this->db->conditions($conditions,true,true,$Article);
$result = $this->db->fetchAll($query);
$expected = array(array(
'Article' => array('id' => 1, 'comment_count' => 4)
));
$this->assertEqual($expected,$result);
}
}
?>