Browse Source

"yii\sphinx\Query" has been composed, unit test for it added.

tags/2.0.0-beta
Paul Klimov 11 years ago
parent
commit
36da1617e8
  1. 74
      extensions/sphinx/Query.php
  2. 25
      extensions/sphinx/QueryBuilder.php
  3. 138
      tests/unit/extensions/sphinx/QueryTest.php

74
extensions/sphinx/Query.php

@ -30,10 +30,14 @@ class Query extends Component
*/ */
const SORT_DESC = true; const SORT_DESC = true;
/**
* @var array the columns being selected. For example, `['id', 'group_id']`.
* This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns.
* @see select()
*/
public $select; public $select;
/** /**
* @var string additional option that should be appended to the 'SELECT' keyword. For example, * @var string additional option that should be appended to the 'SELECT' keyword.
* in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used.
*/ */
public $selectOption; public $selectOption;
/** /**
@ -41,15 +45,45 @@ class Query extends Component
* the SELECT clause would be changed to SELECT DISTINCT. * the SELECT clause would be changed to SELECT DISTINCT.
*/ */
public $distinct; public $distinct;
/**
* @var array the index(es) to be selected from. For example, `['idx_user', 'idx_post']`.
* This is used to construct the FROM clause in a SQL statement.
* @see from()
*/
public $from; public $from;
/**
* @var string|array query condition. This refers to the WHERE clause in a SQL statement.
* For example, `MATCH('ipod') AND team = 1`.
* @see where()
*/
public $where; public $where;
/**
* @var integer maximum number of records to be returned.
* Note: if not set implicit LIMIT 0,20 is present by default.
*/
public $limit; public $limit;
/**
* @var integer zero-based offset from where the records are to be returned. If not set or
* less than 0, it means starting from the beginning.
* Note: implicit LIMIT 0,20 is present by default.
*/
public $offset; public $offset;
/**
* @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement.
* The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which
* can be either [[Query::SORT_ASC]] or [[Query::SORT_DESC]]. The array may also contain [[Expression]] objects.
* If that is the case, the expressions will be converted into strings without any change.
*/
public $orderBy; public $orderBy;
/**
* @var array how to group the query results. For example, `['company', 'department']`.
* This is used to construct the GROUP BY clause in a SQL statement.
*/
public $groupBy; public $groupBy;
/** /**
* @var string WITHIN GROUP ORDER BY clause. This is a Sphinx specific extension * @var string WITHIN GROUP ORDER BY clause. This is a Sphinx specific extension
* that lets you control how the best row within a group will to be selected. * that lets you control how the best row within a group will to be selected.
* The possible value matches the [[orderBy]] one.
*/ */
public $within; public $within;
/** /**
@ -502,13 +536,25 @@ class Query extends Component
return $this; return $this;
} }
public function options(array $options) /**
* Sets the query options.
* @param array $options query options in format: optionName => optionValue
* @return static the query object itself
* @see addOptions()
*/
public function options($options)
{ {
$this->options = $options; $this->options = $options;
return $this; return $this;
} }
public function addOptions(array $options) /**
* Adds additional query options.
* @param array $options query options in format: optionName => optionValue
* @return static the query object itself
* @see options()
*/
public function addOptions($options)
{ {
if (is_array($this->options)) { if (is_array($this->options)) {
$this->options = array_merge($this->options, $options); $this->options = array_merge($this->options, $options);
@ -518,12 +564,32 @@ class Query extends Component
return $this; return $this;
} }
/**
* Sets the WITHIN GROUP ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to find best row within a group.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return static the query object itself
* @see addWithin()
*/
public function within($columns) public function within($columns)
{ {
$this->within = $this->normalizeOrderBy($columns); $this->within = $this->normalizeOrderBy($columns);
return $this; return $this;
} }
/**
* Adds additional WITHIN GROUP ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to find best row within a group.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return static the query object itself
* @see within()
*/
public function addWithin($columns) public function addWithin($columns)
{ {
$columns = $this->normalizeOrderBy($columns); $columns = $this->normalizeOrderBy($columns);

25
extensions/sphinx/QueryBuilder.php

@ -62,7 +62,7 @@ class QueryBuilder extends Object
$this->buildWithin($query->within), $this->buildWithin($query->within),
$this->buildOrderBy($query->orderBy), $this->buildOrderBy($query->orderBy),
$this->buildLimit($query->limit, $query->offset), $this->buildLimit($query->limit, $query->offset),
$this->buildOption($query->options), $this->buildOption($query->options, $params),
]; ];
return [implode($this->separator, array_filter($clauses)), $params]; return [implode($this->separator, array_filter($clauses)), $params];
} }
@ -311,9 +311,13 @@ class QueryBuilder extends Object
if (!empty($options)) { if (!empty($options)) {
$optionParts = []; $optionParts = [];
foreach ($options as $name => $value) { foreach ($options as $name => $value) {
$phName = self::PARAM_PREFIX . count($params); if ($value instanceof Expression) {
$params[$phName] = $value; $actualValue = $value->expression;
$optionParts[] = $phName . ' AS ' . $name; } else {
$actualValue = self::PARAM_PREFIX . count($params);
$params[$actualValue] = $value;
}
$optionParts[] = $actualValue . ' AS ' . $name;
} }
$optionSql = ', ' . implode(', ', $optionParts); $optionSql = ', ' . implode(', ', $optionParts);
} else { } else {
@ -768,17 +772,24 @@ class QueryBuilder extends Object
} }
/** /**
* @param array $options * @param array $options query options in format: optionName => optionValue
* @param array $params the binding parameters to be populated
* @return string the OPTION clause build from [[query]] * @return string the OPTION clause build from [[query]]
*/ */
public function buildOption(array $options) public function buildOption($options, &$params)
{ {
if (empty($options)) { if (empty($options)) {
return ''; return '';
} }
$optionLines = []; $optionLines = [];
foreach ($options as $name => $value) { foreach ($options as $name => $value) {
$optionLines[] = $name . ' = ' . $value; if ($value instanceof Expression) {
$actualValue = $value->expression;
} else {
$actualValue = self::PARAM_PREFIX . count($params);
$params[$actualValue] = $value;
}
$optionLines[] = $name . ' = ' . $actualValue;
} }
return 'OPTION ' . implode(', ', $optionLines); return 'OPTION ' . implode(', ', $optionLines);
} }

138
tests/unit/extensions/sphinx/QueryTest.php

@ -0,0 +1,138 @@
<?php
namespace yiiunit\extensions\sphinx;
use yii\sphinx\Query;
/**
* @group sphinx
*/
class QueryTest extends SphinxTestCase
{
public function testSelect()
{
// default
$query = new Query;
$query->select('*');
$this->assertEquals(['*'], $query->select);
$this->assertNull($query->distinct);
$this->assertEquals(null, $query->selectOption);
$query = new Query;
$query->select('id, name', 'something')->distinct(true);
$this->assertEquals(['id', 'name'], $query->select);
$this->assertTrue($query->distinct);
$this->assertEquals('something', $query->selectOption);
}
public function testFrom()
{
$query = new Query;
$query->from('tbl_user');
$this->assertEquals(['tbl_user'], $query->from);
}
public function testWhere()
{
$query = new Query;
$query->where('id = :id', [':id' => 1]);
$this->assertEquals('id = :id', $query->where);
$this->assertEquals([':id' => 1], $query->params);
$query->andWhere('name = :name', [':name' => 'something']);
$this->assertEquals(['and', 'id = :id', 'name = :name'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something'], $query->params);
$query->orWhere('age = :age', [':age' => '30']);
$this->assertEquals(['or', ['and', 'id = :id', 'name = :name'], 'age = :age'], $query->where);
$this->assertEquals([':id' => 1, ':name' => 'something', ':age' => '30'], $query->params);
}
public function testGroup()
{
$query = new Query;
$query->groupBy('team');
$this->assertEquals(['team'], $query->groupBy);
$query->addGroupBy('company');
$this->assertEquals(['team', 'company'], $query->groupBy);
$query->addGroupBy('age');
$this->assertEquals(['team', 'company', 'age'], $query->groupBy);
}
public function testOrder()
{
$query = new Query;
$query->orderBy('team');
$this->assertEquals(['team' => false], $query->orderBy);
$query->addOrderBy('company');
$this->assertEquals(['team' => false, 'company' => false], $query->orderBy);
$query->addOrderBy('age');
$this->assertEquals(['team' => false, 'company' => false, 'age' => false], $query->orderBy);
$query->addOrderBy(['age' => true]);
$this->assertEquals(['team' => false, 'company' => false, 'age' => true], $query->orderBy);
$query->addOrderBy('age ASC, company DESC');
$this->assertEquals(['team' => false, 'company' => true, 'age' => false], $query->orderBy);
}
public function testLimitOffset()
{
$query = new Query;
$query->limit(10)->offset(5);
$this->assertEquals(10, $query->limit);
$this->assertEquals(5, $query->offset);
}
public function testWithin()
{
$query = new Query;
$query->within('team');
$this->assertEquals(['team' => false], $query->within);
$query->addWithin('company');
$this->assertEquals(['team' => false, 'company' => false], $query->within);
$query->addWithin('age');
$this->assertEquals(['team' => false, 'company' => false, 'age' => false], $query->within);
$query->addWithin(['age' => true]);
$this->assertEquals(['team' => false, 'company' => false, 'age' => true], $query->within);
$query->addWithin('age ASC, company DESC');
$this->assertEquals(['team' => false, 'company' => true, 'age' => false], $query->within);
}
public function testOptions()
{
$query = new Query;
$options = [
'cutoff' => 50,
'max_matches' => 50,
];
$query->options($options);
$this->assertEquals($options, $query->options);
$newMaxMatches = $options['max_matches'] + 10;
$query->addOptions(['max_matches' => $newMaxMatches]);
$this->assertEquals($newMaxMatches, $query->options['max_matches']);
}
public function testRun()
{
$connection = $this->getConnection();
$query = new Query;
$rows = $query->from('yii2_test_article_index')
->where("MATCH('about')")
->options([
'cutoff' => 50,
])
->all($connection);
$this->assertNotEmpty($rows);
}
}
Loading…
Cancel
Save