Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
e15860c3
Commit
e15860c3
authored
Nov 24, 2013
by
Carsten Brandt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more on elasticsearch Query interface added facet search
parent
a0a3c36c
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
412 additions
and
233 deletions
+412
-233
ActiveRecord.php
framework/yii/db/ActiveRecord.php
+1
-1
QueryBuilder.php
framework/yii/db/QueryBuilder.php
+3
-2
ActiveQuery.php
framework/yii/elasticsearch/ActiveQuery.php
+2
-2
ActiveRecord.php
framework/yii/elasticsearch/ActiveRecord.php
+4
-0
Command.php
framework/yii/elasticsearch/Command.php
+12
-5
Connection.php
framework/yii/elasticsearch/Connection.php
+3
-7
Query.php
framework/yii/elasticsearch/Query.php
+161
-57
QueryBuilder.php
framework/yii/elasticsearch/QueryBuilder.php
+31
-101
ActiveRecordTest.php
tests/unit/framework/elasticsearch/ActiveRecordTest.php
+15
-10
ElasticSearchConnectionTest.php
...t/framework/elasticsearch/ElasticSearchConnectionTest.php
+0
-48
QueryTest.php
tests/unit/framework/elasticsearch/QueryTest.php
+180
-0
No files found.
framework/yii/db/ActiveRecord.php
View file @
e15860c3
...
...
@@ -132,7 +132,7 @@ class ActiveRecord extends Model
* - an array of name-value pairs: query by a set of column values and return a single record matching all of them.
* - null: return a new [[ActiveQuery]] object for further query purpose.
*
* @return ActiveQuery|Active
QueryInterface|static
|null When `$q` is null, a new [[ActiveQuery]] instance
* @return ActiveQuery|Active
Record
|null When `$q` is null, a new [[ActiveQuery]] instance
* is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be
* returned (null will be returned if there is no matching).
* @throws InvalidConfigException if the AR class does not have a primary key
...
...
framework/yii/db/QueryBuilder.php
View file @
e15860c3
...
...
@@ -7,6 +7,7 @@
namespace
yii\db
;
use
yii\base\InvalidParamException
;
use
yii\base\NotSupportedException
;
/**
...
...
@@ -761,7 +762,7 @@ class QueryBuilder extends \yii\base\Object
* on how to specify a condition.
* @param array $params the binding parameters to be populated
* @return string the generated SQL expression
* @throws
\yii\db\
Exception if the condition is in bad format
* @throws
InvalidParam
Exception if the condition is in bad format
*/
public
function
buildCondition
(
$condition
,
&
$params
)
{
...
...
@@ -790,7 +791,7 @@ class QueryBuilder extends \yii\base\Object
array_shift
(
$condition
);
return
$this
->
$method
(
$operator
,
$condition
,
$params
);
}
else
{
throw
new
Exception
(
'Found unknown operator in query: '
.
$operator
);
throw
new
InvalidParam
Exception
(
'Found unknown operator in query: '
.
$operator
);
}
}
else
{
// hash format: 'column1' => 'value1', 'column2' => 'value2', ...
return
$this
->
buildHashCondition
(
$condition
,
$params
);
...
...
framework/yii/elasticsearch/ActiveQuery.php
View file @
e15860c3
...
...
@@ -71,8 +71,8 @@ class ActiveQuery extends Query implements ActiveQueryInterface
$this
->
index
=
$modelClass
::
index
();
$this
->
type
=
$modelClass
::
type
();
}
$
query
=
$db
->
getQueryBuilder
()
->
build
(
$this
);
return
$db
->
createCommand
(
$
query
,
$this
->
index
,
$this
->
type
);
$
commandConfig
=
$db
->
getQueryBuilder
()
->
build
(
$this
);
return
$db
->
createCommand
(
$
commandConfig
);
}
/**
...
...
framework/yii/elasticsearch/ActiveRecord.php
View file @
e15860c3
...
...
@@ -110,6 +110,10 @@ class ActiveRecord extends \yii\db\ActiveRecord
return
$models
;
}
// TODO add more like this feature http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-more-like-this.html
// TODO add percolate functionality http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html
/**
* @inheritDoc
*/
...
...
framework/yii/elasticsearch/Command.php
View file @
e15860c3
...
...
@@ -6,6 +6,7 @@
namespace
yii\elasticsearch
;
use
Guzzle\Http\Exception\ClientErrorResponseException
;
use
yii\base\Component
;
use
yii\db\Exception
;
use
yii\helpers\Json
;
...
...
@@ -35,15 +36,16 @@ class Command extends Component
* @var string|array the types to execute the query on. Defaults to null meaning all types
*/
public
$type
;
/**
* @var array
|string array or json
* @var array
list of arrays or json strings that become parts of a query
*/
public
$query
;
public
$queryParts
;
public
$options
=
[];
public
function
queryAll
(
$options
=
[])
{
$query
=
$this
->
query
;
$query
=
$this
->
query
Parts
;
if
(
empty
(
$query
))
{
$query
=
'{}'
;
}
...
...
@@ -55,7 +57,11 @@ class Command extends Component
$this
->
type
!==
null
?
$this
->
type
:
'_all'
,
'_search'
];
try
{
$response
=
$this
->
db
->
http
()
->
post
(
$this
->
createUrl
(
$url
,
$options
),
null
,
$query
)
->
send
();
}
catch
(
ClientErrorResponseException
$e
)
{
throw
new
Exception
(
"elasticsearch error:
\n\n
"
.
$query
.
"
\n\n
"
.
$e
->
getMessage
()
.
$e
->
getResponse
()
->
getBody
(
true
),
[],
0
,
$e
);
}
return
Json
::
decode
(
$response
->
getBody
(
true
))[
'hits'
];
}
...
...
@@ -405,7 +411,8 @@ class Command extends Component
return
urlencode
(
is_array
(
$a
)
?
implode
(
','
,
$a
)
:
$a
);
},
$path
));
if
(
!
empty
(
$options
))
{
if
(
!
empty
(
$options
)
||
!
empty
(
$this
->
options
))
{
$options
=
array_merge
(
$this
->
options
,
$options
);
$url
.=
'?'
.
http_build_query
(
$options
);
}
...
...
framework/yii/elasticsearch/Connection.php
View file @
e15860c3
...
...
@@ -58,15 +58,11 @@ class Connection extends Component
* @param string $query the SQL statement to be executed
* @return Command the DB command
*/
public
function
createCommand
(
$
query
=
null
,
$index
=
null
,
$type
=
null
)
public
function
createCommand
(
$
config
=
[]
)
{
$this
->
open
();
$command
=
new
Command
(
array
(
'db'
=>
$this
,
'query'
=>
$query
,
'index'
=>
$index
,
'type'
=>
$type
,
));
$config
[
'db'
]
=
$this
;
$command
=
new
Command
(
$config
);
return
$command
;
}
...
...
framework/yii/elasticsearch/Query.php
View file @
e15860c3
...
...
@@ -50,6 +50,16 @@ class Query extends Component implements QueryInterface
*/
public
$timeout
;
public
$query
;
public
$filter
;
public
$facets
=
[];
public
$facetResults
=
[];
public
$totalCount
;
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the database connection used to execute the query.
...
...
@@ -62,8 +72,8 @@ class Query extends Component implements QueryInterface
$db
=
Yii
::
$app
->
getComponent
(
'elasticsearch'
);
}
$
query
=
$db
->
getQueryBuilder
()
->
build
(
$this
);
return
$db
->
createCommand
(
$
query
,
$this
->
index
,
$this
->
type
);
$
commandConfig
=
$db
->
getQueryBuilder
()
->
build
(
$this
);
return
$db
->
createCommand
(
$
commandConfig
);
}
/**
...
...
@@ -74,11 +84,13 @@ class Query extends Component implements QueryInterface
*/
public
function
all
(
$db
=
null
)
{
$rows
=
$this
->
createCommand
(
$db
)
->
queryAll
()[
'hits'
];
$result
=
$this
->
createCommand
(
$db
)
->
queryAll
();
// TODO publish facet results
$rows
=
$result
[
'hits'
];
if
(
$this
->
indexBy
===
null
&&
$this
->
fields
===
null
)
{
return
$rows
;
}
$
result
=
[];
$
models
=
[];
foreach
(
$rows
as
$key
=>
$row
)
{
if
(
$this
->
fields
!==
null
)
{
$row
[
'_source'
]
=
isset
(
$row
[
'fields'
])
?
$row
[
'fields'
]
:
[];
...
...
@@ -91,9 +103,9 @@ class Query extends Component implements QueryInterface
$key
=
call_user_func
(
$this
->
indexBy
,
$row
);
}
}
$
result
[
$key
]
=
$row
;
$
models
[
$key
]
=
$row
;
}
return
$
result
;
return
$
models
;
}
/**
...
...
@@ -107,6 +119,7 @@ class Query extends Component implements QueryInterface
{
$options
[
'size'
]
=
1
;
$result
=
$this
->
createCommand
(
$db
)
->
queryAll
(
$options
);
// TODO publish facet results
if
(
empty
(
$result
[
'hits'
]))
{
return
false
;
}
...
...
@@ -119,6 +132,20 @@ class Query extends Component implements QueryInterface
}
/**
* Executes the query and deletes all matching documents.
*
* This will not run facet queries.
*
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `elasticsearch` application component will be used.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public
function
delete
(
$db
=
null
)
{
// TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
}
/**
* Returns the query result as a scalar value.
* The value returned will be the specified field in the first document of the query results.
* @param string $field name of the attribute to select
...
...
@@ -146,11 +173,12 @@ class Query extends Component implements QueryInterface
*/
public
function
column
(
$field
,
$db
=
null
)
{
$query
=
clone
$this
;
$rows
=
$query
->
fields
([
$field
])
->
createCommand
(
$db
)
->
queryAll
()[
'hits'
];
$command
=
$this
->
createCommand
(
$db
);
$command
->
queryParts
[
'fields'
]
=
[
$field
];
$rows
=
$command
->
queryAll
()[
'hits'
];
$result
=
[];
foreach
(
$rows
as
$row
)
{
$result
[]
=
$row
[
'fields'
][
$field
]
;
$result
[]
=
isset
(
$row
[
'fields'
][
$field
])
?
$row
[
'fields'
][
$field
]
:
null
;
}
return
$result
;
}
...
...
@@ -164,6 +192,10 @@ class Query extends Component implements QueryInterface
*/
public
function
count
(
$q
=
'*'
,
$db
=
null
)
{
// TODO consider sending to _count api instead of _search for performance
// only when no facety are registerted.
// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-count.html
$count
=
$this
->
createCommand
(
$db
)
->
queryCount
()[
'total'
];
if
(
$this
->
limit
===
null
&&
$this
->
offset
===
null
)
{
return
$count
;
...
...
@@ -173,84 +205,156 @@ class Query extends Component implements QueryInterface
return
$this
->
limit
===
null
?
$count
:
(
$this
->
limit
>
$count
?
$count
:
$this
->
limit
);
}
/**
* Returns the sum of the specified column values.
* @param string $q the column name or expression.
* Make sure you properly quote column names in the expression.
* Returns a value indicating whether the query result contains any row of data.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `elasticsearch` application component will be used.
* @return
integer the sum of the specified column values
* @return
boolean whether the query result contains any row of data.
*/
public
function
sum
(
$q
,
$db
=
null
)
public
function
exists
(
$db
=
null
)
{
$this
->
select
=
[
"SUM(
$q
)"
];
return
$this
->
createCommand
(
$db
)
->
queryScalar
();
return
self
::
one
(
$db
)
!==
false
;
}
/**
*
Returns the average of the specified column values
.
* @param string $
q the column name or expression.
*
Make sure you properly quote column names in the expression
.
* @param
Connection $db the database connection used to execute the query
.
*
If this parameter is not given, the `elasticsearch` application component will be used.
* @
return integer the average of the specified column values.
*
Adds a facet search to this query
.
* @param string $
name the name of this facet
*
@param string $type the facet type. e.g. `terms`, `range`, `histogram`..
.
* @param
string|array $options the configuration options for this facet. Can be an array or a json string
.
*
@return static
* @
see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-query-facet.html
*/
public
function
a
verage
(
$q
,
$db
=
null
)
public
function
a
ddFacet
(
$name
,
$type
,
$options
)
{
$this
->
select
=
[
"AVG(
$q
)"
];
return
$this
->
createCommand
(
$db
)
->
queryScalar
()
;
$this
->
facets
[
$name
]
=
[
$type
=>
$options
];
return
$this
;
}
/**
* Returns the minimum of the specified column values.
* @param string $q the column name or expression.
* Make sure you properly quote column names in the expression.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `elasticsearch` application component will be used.
* @return integer the minimum of the specified column values.
* The `terms facet` allow to specify field facets that return the N most frequent terms.
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-facet.html
*/
public
function
min
(
$q
,
$db
=
null
)
public
function
addTermFacet
(
$name
,
$options
)
{
$this
->
select
=
[
"MIN(
$q
)"
];
return
$this
->
createCommand
(
$db
)
->
queryScalar
();
return
$this
->
addFacet
(
$name
,
'terms'
,
$options
);
}
/**
* R
eturns the maximum of the specified column values.
*
@param string $q the column name or expression
.
*
Make sure you properly quote column names in the expression.
* @param
Connection $db the database connection used to execute the query
.
*
If this parameter is not given, the `elasticsearch` application component will be used.
* @
return integer the maximum of the specified column values.
* R
ange facet allows to specify a set of ranges and get both the number of docs (count) that fall
*
within each range, and aggregated data either based on the field, or using another field
.
*
@param string $name the name of this facet
* @param
array $options additional option. Please refer to the elasticsearch documentation for details
.
*
@return static
* @
see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-range-facet.html
*/
public
function
max
(
$q
,
$db
=
null
)
public
function
addRangeFacet
(
$name
,
$options
)
{
$this
->
select
=
[
"MAX(
$q
)"
];
return
$this
->
createCommand
(
$db
)
->
queryScalar
();
return
$this
->
addFacet
(
$name
,
'range'
,
$options
);
}
/**
* Returns a value indicating whether the query result contains any row of data.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `elasticsearch` application component will be used.
* @return boolean whether the query result contains any row of data.
* The histogram facet works with numeric data by building a histogram across intervals of the field values.
* Each value is "rounded" into an interval (or placed in a bucket), and statistics are provided per
* interval/bucket (count and total).
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-histogram-facet.html
*/
public
function
exists
(
$db
=
null
)
public
function
addHistogramFacet
(
$name
,
$options
)
{
// TODO check for exists
return
$this
->
one
(
$db
)
!==
null
;
return
$this
->
addFacet
(
$name
,
'histogram'
,
$options
);
}
/**
* Executes the query and returns all results as an array.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `elasticsearch` application component will be used.
* @return array the query results. If the query results in nothing, an empty array will be returned.
* A specific histogram facet that can work with date field types enhancing it over the regular histogram facet.
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-date-histogram-facet.html
*/
public
function
delete
(
$db
=
null
)
public
function
addDateHistogramFacet
(
$name
,
$options
)
{
// TODO http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
return
$this
->
addFacet
(
$name
,
'date_histogram'
,
$options
);
}
/**
* A filter facet (not to be confused with a facet filter) allows you to return a count of the hits matching the filter.
* The filter itself can be expressed using the Query DSL.
* @param string $name the name of this facet
* @param string $filter the query in Query DSL
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-filter-facet.html
*/
public
function
addFilterFacet
(
$name
,
$filter
)
{
return
$this
->
addFacet
(
$name
,
'filter'
,
$filter
);
}
/**
* A facet query allows to return a count of the hits matching the facet query.
* The query itself can be expressed using the Query DSL.
* @param string $name the name of this facet
* @param string $query the query in Query DSL
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-query-facet.html
*/
public
function
addQueryFacet
(
$name
,
$query
)
{
return
$this
->
addFacet
(
$name
,
'query'
,
$query
);
}
/**
* Statistical facet allows to compute statistical data on a numeric fields. The statistical data include count,
* total, sum of squares, mean (average), minimum, maximum, variance, and standard deviation.
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-statistical-facet.html
*/
public
function
addStatisticalFacet
(
$name
,
$options
)
{
return
$this
->
addFacet
(
$name
,
'statistical'
,
$options
);
}
/**
* The `terms_stats` facet combines both the terms and statistical allowing to compute stats computed on a field,
* per term value driven by another field.
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html
*/
public
function
addTermsStatsFacet
(
$name
,
$options
)
{
return
$this
->
addFacet
(
$name
,
'terms_stats'
,
$options
);
}
/**
* The `geo_distance` facet is a facet providing information for ranges of distances from a provided `geo_point`
* including count of the number of hits that fall within each range, and aggregation information (like `total`).
* @param string $name the name of this facet
* @param array $options additional option. Please refer to the elasticsearch documentation for details.
* @return static
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-geo-distance-facet.html
*/
public
function
addGeoDistanceFacet
(
$name
,
$options
)
{
return
$this
->
addFacet
(
$name
,
'geo_distance'
,
$options
);
}
// TODO add suggesters http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters.html
// TODO add validate query http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-validate.html
// TODO support multi query via static method http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-multi-search.html
public
function
query
()
{
}
/**
...
...
framework/yii/elasticsearch/QueryBuilder.php
View file @
e15860c3
...
...
@@ -7,15 +7,14 @@
namespace
yii\elasticsearch
;
use
yii\base\InvalidParamException
;
use
yii\base\NotSupportedException
;
/**
* QueryBuilder builds a
SELECT SQL statement
based on the specification given as a [[Query]] object.
* QueryBuilder builds a
n elasticsearch query
based on the specification given as a [[Query]] object.
*
* QueryBuilder can also be used to build SQL statements such as INSERT, UPDATE, DELETE, CREATE TABLE,
* from a [[Query]] object.
*
* @author
Qiang Xue <qiang.xue@gmail.com
>
* @author
Carsten Brandt <mail@cebe.cc
>
* @since 2.0
*/
class
QueryBuilder
extends
\yii\base\Object
...
...
@@ -30,105 +29,51 @@ class QueryBuilder extends \yii\base\Object
* @param Connection $connection the database connection.
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public
function
__construct
(
$connection
,
$config
=
array
()
)
public
function
__construct
(
$connection
,
$config
=
[]
)
{
$this
->
db
=
$connection
;
parent
::
__construct
(
$config
);
}
/**
* Generates
a SELECT SQL statement
from a [[Query]] object.
* @param Query $query the [[Query]] object from which the
SQL statement
will be generated
* Generates
query
from a [[Query]] object.
* @param Query $query the [[Query]] object from which the
query
will be generated
* @return array the generated SQL statement (the first array element) and the corresponding
* parameters to be bound to the SQL statement (the second array element).
*/
public
function
build
(
$query
)
{
$searchQuery
=
array
();
$this
->
buildFields
(
$searchQuery
,
$query
->
fields
);
// $this->buildFrom($searchQuery, $query->from);
$this
->
buildCondition
(
$searchQuery
,
$query
->
where
);
$this
->
buildOrderBy
(
$searchQuery
,
$query
->
orderBy
);
$this
->
buildLimit
(
$searchQuery
,
$query
->
limit
,
$query
->
offset
);
$parts
=
[];
return
$searchQuery
;
}
/**
* Converts an abstract column type into a physical column type.
* The conversion is done using the type map specified in [[typeMap]].
* The following abstract column types are supported (using MySQL as an example to explain the corresponding
* physical types):
*
* - `pk`: an auto-incremental primary key type, will be converted into "int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY"
* - `bigpk`: an auto-incremental primary key type, will be converted into "bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY"
* - `string`: string type, will be converted into "varchar(255)"
* - `text`: a long string type, will be converted into "text"
* - `smallint`: a small integer type, will be converted into "smallint(6)"
* - `integer`: integer type, will be converted into "int(11)"
* - `bigint`: a big integer type, will be converted into "bigint(20)"
* - `boolean`: boolean type, will be converted into "tinyint(1)"
* - `float``: float number type, will be converted into "float"
* - `decimal`: decimal number type, will be converted into "decimal"
* - `datetime`: datetime type, will be converted into "datetime"
* - `timestamp`: timestamp type, will be converted into "timestamp"
* - `time`: time type, will be converted into "time"
* - `date`: date type, will be converted into "date"
* - `money`: money type, will be converted into "decimal(19,4)"
* - `binary`: binary data type, will be converted into "blob"
*
* If the abstract type contains two or more parts separated by spaces (e.g. "string NOT NULL"), then only
* the first part will be converted, and the rest of the parts will be appended to the converted result.
* For example, 'string NOT NULL' is converted to 'varchar(255) NOT NULL'.
*
* For some of the abstract types you can also specify a length or precision constraint
* by prepending it in round brackets directly to the type.
* For example `string(32)` will be converted into "varchar(32)" on a MySQL database.
* If the underlying DBMS does not support these kind of constraints for a type it will
* be ignored.
*
* If a type cannot be found in [[typeMap]], it will be returned without any change.
* @param string $type abstract column type
* @return string physical column type.
*/
public
function
getColumnType
(
$type
)
{
if
(
isset
(
$this
->
typeMap
[
$type
]))
{
return
$this
->
typeMap
[
$type
];
}
elseif
(
preg_match
(
'/^(\w+)\((.+?)\)(.*)$/'
,
$type
,
$matches
))
{
if
(
isset
(
$this
->
typeMap
[
$matches
[
1
]]))
{
return
preg_replace
(
'/\(.+\)/'
,
'('
.
$matches
[
2
]
.
')'
,
$this
->
typeMap
[
$matches
[
1
]])
.
$matches
[
3
];
}
}
elseif
(
preg_match
(
'/^(\w+)\s+/'
,
$type
,
$matches
))
{
if
(
isset
(
$this
->
typeMap
[
$matches
[
1
]]))
{
return
preg_replace
(
'/^\w+/'
,
$this
->
typeMap
[
$matches
[
1
]],
$type
);
if
(
$query
->
fields
!==
null
)
{
$parts
[
'fields'
]
=
(
array
)
$query
->
fields
;
}
if
(
$query
->
limit
!==
null
&&
$query
->
limit
>=
0
)
{
$parts
[
'size'
]
=
$query
->
limit
;
}
return
$type
;
if
(
$query
->
offset
>
0
)
{
$parts
[
'from'
]
=
(
int
)
$query
->
offset
;
}
/**
* @param array $columns
* @param boolean $distinct
* @param string $selectOption
* @return string the SELECT clause built from [[query]].
*/
public
function
buildFields
(
&
$query
,
$columns
)
{
if
(
$columns
===
null
)
{
return
;
}
foreach
(
$columns
as
$i
=>
$column
)
{
if
(
is_object
(
$column
))
{
$columns
[
$i
]
=
(
string
)
$column
;
}
$this
->
buildCondition
(
$parts
,
$query
->
where
);
$this
->
buildOrderBy
(
$parts
,
$query
->
orderBy
);
if
(
empty
(
$parts
[
'query'
]))
{
$parts
[
'query'
]
=
[
"match_all"
=>
(
object
)[]];
}
$query
[
'fields'
]
=
$columns
;
return
[
'queryParts'
=>
$parts
,
'index'
=>
$query
->
index
,
'type'
=>
$query
->
type
,
'options'
=>
[
'timeout'
=>
$query
->
timeout
],
];
}
/**
* @param array $columns
* @return string the ORDER BY clause built from [[query]].
* adds order by condition to the query
*/
public
function
buildOrderBy
(
&
$query
,
$columns
)
{
...
...
@@ -143,28 +88,13 @@ class QueryBuilder extends \yii\base\Object
}
elseif
(
is_string
(
$direction
))
{
$orders
[]
=
$direction
;
}
else
{
$orders
[]
=
array
(
$name
=>
(
$direction
===
Query
::
SORT_DESC
?
'desc'
:
'asc'
));
$orders
[]
=
array
(
$name
=>
(
$direction
===
SORT_DESC
?
'desc'
:
'asc'
));
}
}
$query
[
'sort'
]
=
$orders
;
}
/**
* @param integer $limit
* @param integer $offset
* @return string the LIMIT and OFFSET clauses built from [[query]].
*/
public
function
buildLimit
(
&
$query
,
$limit
,
$offset
)
{
if
(
$limit
!==
null
&&
$limit
>=
0
)
{
$query
[
'size'
]
=
$limit
;
}
if
(
$offset
>
0
)
{
$query
[
'from'
]
=
(
int
)
$offset
;
}
}
/**
* Parses the condition specification and generates the corresponding SQL expression.
* @param string|array $condition the condition specification. Please refer to [[Query::where()]]
* on how to specify a condition.
...
...
@@ -191,7 +121,7 @@ class QueryBuilder extends \yii\base\Object
return
;
}
if
(
!
is_array
(
$condition
))
{
throw
new
NotSupportedException
(
'String conditions are not supported by elasticsearch.'
);
throw
new
NotSupportedException
(
'String conditions
in where()
are not supported by elasticsearch.'
);
}
if
(
isset
(
$condition
[
0
]))
{
// operator format: operator, operand 1, operand 2, ...
$operator
=
strtoupper
(
$condition
[
0
]);
...
...
@@ -200,7 +130,7 @@ class QueryBuilder extends \yii\base\Object
array_shift
(
$condition
);
$this
->
$method
(
$query
,
$operator
,
$condition
);
}
else
{
throw
new
Exception
(
'Found unknown operator in query: '
.
$operator
);
throw
new
InvalidParam
Exception
(
'Found unknown operator in query: '
.
$operator
);
}
}
else
{
// hash format: 'column1' => 'value1', 'column2' => 'value2', ...
$this
->
buildHashCondition
(
$query
,
$condition
);
...
...
tests/unit/framework/elasticsearch/ActiveRecordTest.php
View file @
e15860c3
...
...
@@ -296,17 +296,22 @@ class ActiveRecordTest extends ElasticSearchTestCase
$this
->
assertEquals
(
1
,
count
(
Customer
::
find
()
->
where
(
array
(
'AND'
,
array
(
'name'
=>
array
(
'user2'
,
'user3'
)),
array
(
'BETWEEN'
,
'status'
,
2
,
4
)))
->
all
()));
}
// public function testSum
()
//
{
// $this->assertEquals(6, OrderItem::find()->count()
);
// $this->assertEquals(7, OrderItem::find()->sum('quantity'))
;
// }
public
function
testFindNullValues
()
{
$customer
=
Customer
::
find
(
2
);
$customer
->
name
=
null
;
$customer
->
save
(
false
);
// public function testFindColumn()
// {
// $this->assertEquals(array('user1', 'user2', 'user3'), Customer::find()->column('name'));
//// TODO $this->assertEquals(array('user3', 'user2', 'user1'), Customer::find()->orderBy(array('name' => Query::SORT_DESC))->column('name'));
// }
$result
=
Customer
::
find
()
->
where
([
'name'
=>
null
])
->
all
();
$this
->
assertEquals
(
1
,
count
(
$result
));
$this
->
assertEquals
(
2
,
reset
(
$result
)
->
primaryKey
);
}
public
function
testFindColumn
()
{
$this
->
assertEquals
(
array
(
'user1'
,
'user2'
,
'user3'
),
Customer
::
find
()
->
column
(
'name'
));
$this
->
assertEquals
(
array
(
'user3'
,
'user2'
,
'user1'
),
Customer
::
find
()
->
orderBy
(
array
(
'name'
=>
SORT_DESC
))
->
column
(
'name'
));
}
public
function
testExists
()
{
...
...
tests/unit/framework/elasticsearch/ElasticSearchConnectionTest.php
View file @
e15860c3
...
...
@@ -16,51 +16,4 @@ class ElasticSearchConnectionTest extends ElasticSearchTestCase
$db
->
open
();
}
/**
* test connection to redis and selection of db
*/
public
function
testConnect
()
{
$db
=
new
Connection
();
$db
->
dsn
=
'redis://localhost:6379'
;
$db
->
open
();
$this
->
assertTrue
(
$db
->
ping
());
$db
->
set
(
'YIITESTKEY'
,
'YIITESTVALUE'
);
$db
->
close
();
$db
=
new
Connection
();
$db
->
dsn
=
'redis://localhost:6379/0'
;
$db
->
open
();
$this
->
assertEquals
(
'YIITESTVALUE'
,
$db
->
get
(
'YIITESTKEY'
));
$db
->
close
();
$db
=
new
Connection
();
$db
->
dsn
=
'redis://localhost:6379/1'
;
$db
->
open
();
$this
->
assertNull
(
$db
->
get
(
'YIITESTKEY'
));
$db
->
close
();
}
public
function
keyValueData
()
{
return
array
(
array
(
123
),
array
(
-
123
),
array
(
0
),
array
(
'test'
),
array
(
"test
\r\n
test"
),
array
(
''
),
);
}
/**
* @dataProvider keyValueData
*/
public
function
testStoreGet
(
$data
)
{
$db
=
$this
->
getConnection
(
true
);
$db
->
set
(
'hi'
,
$data
);
$this
->
assertEquals
(
$data
,
$db
->
get
(
'hi'
));
}
}
\ No newline at end of file
tests/unit/framework/elasticsearch/QueryTest.php
0 → 100644
View file @
e15860c3
<?php
namespace
yiiunit\framework\elasticsearch
;
use
yii\elasticsearch\Query
;
/**
* @group db
* @group mysql
*/
class
QueryTest
extends
ElasticSearchTestCase
{
protected
function
setUp
()
{
parent
::
setUp
();
$command
=
$this
->
getConnection
()
->
createCommand
();
$command
->
deleteAllIndexes
();
$command
->
insert
(
'test'
,
'user'
,
[
'name'
=>
'user1'
,
'email'
=>
'user1@example.com'
,
'status'
=>
1
],
1
);
$command
->
insert
(
'test'
,
'user'
,
[
'name'
=>
'user2'
,
'email'
=>
'user2@example.com'
,
'status'
=>
1
],
2
);
$command
->
insert
(
'test'
,
'user'
,
[
'name'
=>
'user3'
,
'email'
=>
'user3@example.com'
,
'status'
=>
2
],
3
);
$command
->
insert
(
'test'
,
'user'
,
[
'name'
=>
'user4'
,
'email'
=>
'user4@example.com'
,
'status'
=>
1
],
4
);
$command
->
flushIndex
();
}
public
function
testFields
()
{
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$query
->
fields
([
'name'
,
'status'
]);
$this
->
assertEquals
([
'name'
,
'status'
],
$query
->
fields
);
$result
=
$query
->
one
(
$this
->
getConnection
());
$this
->
assertEquals
(
2
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$query
->
fields
([]);
$this
->
assertEquals
([],
$query
->
fields
);
$result
=
$query
->
one
(
$this
->
getConnection
());
$this
->
assertEquals
([],
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$query
->
fields
(
null
);
$this
->
assertNull
(
$query
->
fields
);
$result
=
$query
->
one
(
$this
->
getConnection
());
$this
->
assertEquals
(
3
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'email'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
}
public
function
testOne
()
{
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$result
=
$query
->
one
(
$this
->
getConnection
());
$this
->
assertEquals
(
3
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'email'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$result
=
$query
->
where
([
'name'
=>
'user1'
])
->
one
(
$this
->
getConnection
());
$this
->
assertEquals
(
3
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'email'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$this
->
assertEquals
(
1
,
$result
[
'_id'
]);
$result
=
$query
->
where
([
'name'
=>
'user5'
])
->
one
(
$this
->
getConnection
());
$this
->
assertFalse
(
$result
);
}
public
function
testAll
()
{
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$results
=
$query
->
all
(
$this
->
getConnection
());
$this
->
assertEquals
(
4
,
count
(
$results
));
$result
=
reset
(
$results
);
$this
->
assertEquals
(
3
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'email'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$results
=
$query
->
where
([
'name'
=>
'user1'
])
->
all
(
$this
->
getConnection
());
$this
->
assertEquals
(
1
,
count
(
$results
));
$result
=
reset
(
$results
);
$this
->
assertEquals
(
3
,
count
(
$result
[
'_source'
]));
$this
->
assertArrayHasKey
(
'status'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'email'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'name'
,
$result
[
'_source'
]);
$this
->
assertArrayHasKey
(
'_id'
,
$result
);
$this
->
assertEquals
(
1
,
$result
[
'_id'
]);
// indexBy
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$results
=
$query
->
indexBy
(
'name'
)
->
all
(
$this
->
getConnection
());
$this
->
assertEquals
(
4
,
count
(
$results
));
ksort
(
$results
);
$this
->
assertEquals
([
'user1'
,
'user2'
,
'user3'
,
'user4'
],
array_keys
(
$results
));
}
public
function
testScalar
()
{
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$result
=
$query
->
where
([
'name'
=>
'user1'
])
->
scalar
(
'name'
,
$this
->
getConnection
());
$this
->
assertEquals
(
'user1'
,
$result
);
$result
=
$query
->
where
([
'name'
=>
'user1'
])
->
scalar
(
'noname'
,
$this
->
getConnection
());
$this
->
assertNull
(
$result
);
$result
=
$query
->
where
([
'name'
=>
'user5'
])
->
scalar
(
'name'
,
$this
->
getConnection
());
$this
->
assertNull
(
$result
);
}
public
function
testColumn
()
{
$query
=
new
Query
;
$query
->
from
(
'test'
,
'user'
);
$result
=
$query
->
orderBy
([
'name'
=>
SORT_ASC
])
->
column
(
'name'
,
$this
->
getConnection
());
$this
->
assertEquals
([
'user1'
,
'user2'
,
'user3'
,
'user4'
],
$result
);
$result
=
$query
->
column
(
'noname'
,
$this
->
getConnection
());
$this
->
assertEquals
([
null
,
null
,
null
,
null
],
$result
);
$result
=
$query
->
where
([
'name'
=>
'user5'
])
->
scalar
(
'name'
,
$this
->
getConnection
());
$this
->
assertNull
(
$result
);
}
public
function
testOrder
()
{
$query
=
new
Query
;
$query
->
orderBy
(
'team'
);
$this
->
assertEquals
([
'team'
=>
SORT_ASC
],
$query
->
orderBy
);
$query
->
addOrderBy
(
'company'
);
$this
->
assertEquals
([
'team'
=>
SORT_ASC
,
'company'
=>
SORT_ASC
],
$query
->
orderBy
);
$query
->
addOrderBy
(
'age'
);
$this
->
assertEquals
([
'team'
=>
SORT_ASC
,
'company'
=>
SORT_ASC
,
'age'
=>
SORT_ASC
],
$query
->
orderBy
);
$query
->
addOrderBy
([
'age'
=>
SORT_DESC
]);
$this
->
assertEquals
([
'team'
=>
SORT_ASC
,
'company'
=>
SORT_ASC
,
'age'
=>
SORT_DESC
],
$query
->
orderBy
);
$query
->
addOrderBy
(
'age ASC, company DESC'
);
$this
->
assertEquals
([
'team'
=>
SORT_ASC
,
'company'
=>
SORT_DESC
,
'age'
=>
SORT_ASC
],
$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
testUnion
()
{
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment