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
e62e8487
Commit
e62e8487
authored
Sep 22, 2013
by
Carsten Brandt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more API methods for redis active query: sum, avg, max, min ...
parent
7817815d
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
173 additions
and
57 deletions
+173
-57
ActiveQuery.php
framework/yii/redis/ActiveQuery.php
+128
-10
ActiveRecord.php
framework/yii/redis/ActiveRecord.php
+0
-2
ActiveRelation.php
framework/yii/redis/ActiveRelation.php
+0
-1
Connection.php
framework/yii/redis/Connection.php
+4
-0
LuaScriptBuilder.php
framework/yii/redis/LuaScriptBuilder.php
+33
-42
ActiveRecordTest.php
tests/unit/framework/redis/ActiveRecordTest.php
+8
-2
No files found.
framework/yii/redis/ActiveQuery.php
View file @
e62e8487
...
...
@@ -56,11 +56,6 @@ class ActiveQuery extends \yii\base\Component
*/
public
$with
;
/**
* @var string the name of the column by which query results should be indexed by.
* This is only used when the query result is returned as an array when calling [[all()]].
*/
public
$indexBy
;
/**
* @var boolean whether to return each record as an array. If false (default), an object
* of [[modelClass]] will be created to represent each record.
*/
...
...
@@ -80,6 +75,18 @@ class ActiveQuery extends \yii\base\Component
* If less than zero it means starting n elements from the end.
*/
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
;
/**
* @var string the name of the column by which query results should be indexed by.
* This is only used when the query result is returned as an array when calling [[all()]].
*/
public
$indexBy
;
/**
* Executes query and returns all results as an array.
...
...
@@ -154,6 +161,21 @@ class ActiveQuery extends \yii\base\Component
}
/**
* Executes the query and returns the first column of the result.
* @param string $column name of the column to select
* @return array the first column of the query result. An empty array is returned if the query results in nothing.
*/
public
function
column
(
$column
)
{
// TODO add support for indexBy and orderBy
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
$script
=
$db
->
luaScriptBuilder
->
buildColumn
(
$this
,
$column
);
return
$db
->
executeCommand
(
'EVAL'
,
array
(
$script
,
0
));
}
/**
* Returns the number of records.
* @param string $q the COUNT expression. Defaults to '*'.
* Make sure you properly quote column names.
...
...
@@ -187,8 +209,54 @@ class ActiveQuery extends \yii\base\Component
}
/**
* Returns the average of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @return integer the average of the specified column values.
*/
public
function
average
(
$column
)
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
$script
=
$db
->
luaScriptBuilder
->
buildAverage
(
$this
,
$column
);
return
$db
->
executeCommand
(
'EVAL'
,
array
(
$script
,
0
));
}
/**
* Returns the minimum of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @return integer the minimum of the specified column values.
*/
public
function
min
(
$column
)
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
$script
=
$db
->
luaScriptBuilder
->
buildMin
(
$this
,
$column
);
return
$db
->
executeCommand
(
'EVAL'
,
array
(
$script
,
0
));
}
/**
* Returns the maximum of the specified column values.
* @param string $column the column name or expression.
* Make sure you properly quote column names in the expression.
* @return integer the maximum of the specified column values.
*/
public
function
max
(
$column
)
{
$modelClass
=
$this
->
modelClass
;
/** @var Connection $db */
$db
=
$modelClass
::
getDb
();
$script
=
$db
->
luaScriptBuilder
->
buildMax
(
$this
,
$column
);
return
$db
->
executeCommand
(
'EVAL'
,
array
(
$script
,
0
));
}
/**
* Returns the query result as a scalar value.
* The value returned will be the first column in the first row of the query results.
* @param string $column name of the column to select
* @return string|boolean the value of the first column in the first row of the query result.
* False is returned if the query result is empty.
*/
...
...
@@ -210,7 +278,6 @@ class ActiveQuery extends \yii\base\Component
/**
* Sets the [[asArray]] property.
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records.
* @return ActiveQuery the query object itself
*/
...
...
@@ -221,8 +288,62 @@ class ActiveQuery extends \yii\base\Component
}
/**
* Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('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 Query the query object itself
* @see addOrderBy()
*/
public
function
orderBy
(
$columns
)
{
$this
->
orderBy
=
$this
->
normalizeOrderBy
(
$columns
);
return
$this
;
}
/**
* Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by.
* Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `array('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 Query the query object itself
* @see orderBy()
*/
public
function
addOrderBy
(
$columns
)
{
$columns
=
$this
->
normalizeOrderBy
(
$columns
);
if
(
$this
->
orderBy
===
null
)
{
$this
->
orderBy
=
$columns
;
}
else
{
$this
->
orderBy
=
array_merge
(
$this
->
orderBy
,
$columns
);
}
return
$this
;
}
protected
function
normalizeOrderBy
(
$columns
)
{
if
(
is_array
(
$columns
))
{
return
$columns
;
}
else
{
$columns
=
preg_split
(
'/\s*,\s*/'
,
trim
(
$columns
),
-
1
,
PREG_SPLIT_NO_EMPTY
);
$result
=
array
();
foreach
(
$columns
as
$column
)
{
if
(
preg_match
(
'/^(.*?)\s+(asc|desc)$/i'
,
$column
,
$matches
))
{
$result
[
$matches
[
1
]]
=
strcasecmp
(
$matches
[
2
],
'desc'
)
?
self
::
SORT_ASC
:
self
::
SORT_DESC
;
}
else
{
$result
[
$column
]
=
self
::
SORT_ASC
;
}
}
return
$result
;
}
}
/**
* Sets the LIMIT part of the query.
* TODO: refactor, it is duplicated from yii/db/Query
* @param integer $limit the limit
* @return ActiveQuery the query object itself
*/
...
...
@@ -234,7 +355,6 @@ class ActiveQuery extends \yii\base\Component
/**
* Sets the OFFSET part of the query.
* TODO: refactor, it is duplicated from yii/db/Query
* @param integer $offset the offset
* @return ActiveQuery the query object itself
*/
...
...
@@ -264,7 +384,6 @@ class ActiveQuery extends \yii\base\Component
* ))->all();
* ~~~
*
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @return ActiveQuery the query object itself
*/
public
function
with
()
...
...
@@ -279,7 +398,6 @@ class ActiveQuery extends \yii\base\Component
/**
* Sets the [[indexBy]] property.
* TODO: refactor, it is duplicated from yii/db/ActiveQuery
* @param string $column the name of the column by which the query results should be indexed by.
* @return ActiveQuery the query object itself
*/
...
...
framework/yii/redis/ActiveRecord.php
View file @
e62e8487
...
...
@@ -20,8 +20,6 @@ use yii\db\TableSchema;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
*
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
...
...
framework/yii/redis/ActiveRelation.php
View file @
e62e8487
...
...
@@ -13,7 +13,6 @@ namespace yii\redis;
/**
* ActiveRecord is the base class for classes representing relational data in terms of objects.
*
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
...
...
framework/yii/redis/Connection.php
View file @
e62e8487
...
...
@@ -22,6 +22,7 @@ use yii\helpers\Inflector;
*
* @property string $driverName Name of the DB driver. This property is read-only.
* @property boolean $isActive Whether the DB connection is established. This property is read-only.
* @property LuaScriptBuilder $luaScriptBuilder This property is read-only.
* @property Transaction $transaction The currently active transaction. Null if no active transaction. This
* property is read-only.
*
...
...
@@ -333,6 +334,9 @@ class Connection extends Component
}
}
/**
* @return LuaScriptBuilder
*/
public
function
getLuaScriptBuilder
()
{
return
new
LuaScriptBuilder
();
...
...
framework/yii/redis/LuaScriptBuilder.php
View file @
e62e8487
...
...
@@ -19,18 +19,28 @@ class LuaScriptBuilder extends \yii\base\Object
{
public
function
buildAll
(
$query
)
{
// TODO add support for orderBy
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"n=n+1 pks[n]
=
redis.call('HGETALL','
$key
:a:' .. pk)"
,
'pks'
);
// TODO quote
return
$this
->
build
(
$query
,
"n=n+1 pks[n]
=
redis.call('HGETALL','
$key
:a:' .. pk)"
,
'pks'
);
// TODO quote
}
public
function
buildOne
(
$query
)
{
// TODO add support for orderBy
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"do return redis.call('HGETALL','
$key
:a:' .. pk) end"
,
'pks'
);
// TODO quote
}
public
function
buildColumn
(
$query
,
$field
)
{
// TODO add support for orderBy and indexBy
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"n=n+1 pks[n]=redis.call('HGET','
$key
:a:' .. pk,'
$field
')"
,
'pks'
);
// TODO quote
}
public
function
buildCount
(
$query
)
{
return
$this
->
build
(
$query
,
'n=n+1'
,
'n'
);
...
...
@@ -43,6 +53,27 @@ class LuaScriptBuilder extends \yii\base\Object
return
$this
->
build
(
$query
,
"n=n+redis.call('HGET','
$key
:a:' .. pk,'
$field
')"
,
'n'
);
// TODO quote
}
public
function
buildAverage
(
$query
,
$field
)
{
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"n=n+1 if v==nil then v=0 end v=v+redis.call('HGET','
$key
:a:' .. pk,'
$field
')"
,
'v/n'
);
// TODO quote
}
public
function
buildMin
(
$query
,
$field
)
{
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"n=redis.call('HGET','
$key
:a:' .. pk,'
$field
') if v==nil or n<v then v=n end"
,
'v'
);
// TODO quote
}
public
function
buildMax
(
$query
,
$field
)
{
$modelClass
=
$query
->
modelClass
;
$key
=
$modelClass
::
tableName
();
return
$this
->
build
(
$query
,
"n=redis.call('HGET','
$key
:a:' .. pk,'
$field
') if v==nil or n>v then v=n end"
,
'v'
);
// TODO quote
}
/**
* @param ActiveQuery $query
*/
...
...
@@ -69,6 +100,7 @@ class LuaScriptBuilder extends \yii\base\Object
local allpks=redis.call('LRANGE','$key',0,-1)
local pks={}
local n=0
local v=nil
local i=0
for k,pk in ipairs(allpks) do
$loadColumnValues
...
...
@@ -100,47 +132,6 @@ EOF;
}
/**
* @param array $columns
* @return string the GROUP BY clause
*/
public
function
buildGroupBy
(
$columns
)
{
return
empty
(
$columns
)
?
''
:
'GROUP BY '
.
$this
->
buildColumns
(
$columns
);
}
/**
* @param string|array $condition
* @param array $params the binding parameters to be populated
* @return string the HAVING clause built from [[query]].
*/
public
function
buildHaving
(
$condition
,
&
$params
)
{
$having
=
$this
->
buildCondition
(
$condition
,
$params
);
return
$having
===
''
?
''
:
'HAVING '
.
$having
;
}
/**
* @param array $columns
* @return string the ORDER BY clause built from [[query]].
*/
public
function
buildOrderBy
(
$columns
)
{
if
(
empty
(
$columns
))
{
return
''
;
}
$orders
=
array
();
foreach
(
$columns
as
$name
=>
$direction
)
{
if
(
is_object
(
$direction
))
{
$orders
[]
=
(
string
)
$direction
;
}
else
{
$orders
[]
=
$this
->
db
->
quoteColumnName
(
$name
)
.
(
$direction
===
Query
::
SORT_DESC
?
' DESC'
:
''
);
}
}
return
'ORDER BY '
.
implode
(
', '
,
$orders
);
}
/**
* 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.
...
...
tests/unit/framework/redis/ActiveRecordTest.php
View file @
e62e8487
...
...
@@ -2,6 +2,7 @@
namespace
yiiunit\framework\redis
;
use
yii\db\Query
;
use
yii\redis\ActiveQuery
;
use
yiiunit\data\ar\redis\ActiveRecord
;
use
yiiunit\data\ar\redis\Customer
;
...
...
@@ -134,11 +135,10 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertEquals
(
2
,
$customer
->
id
);
// find count, sum, average, min, max, scalar
/*
$this->assertEquals(6, Customer::find()->sum('id'));
$this
->
assertEquals
(
6
,
Customer
::
find
()
->
sum
(
'id'
));
$this
->
assertEquals
(
2
,
Customer
::
find
()
->
average
(
'id'
));
$this
->
assertEquals
(
1
,
Customer
::
find
()
->
min
(
'id'
));
$this
->
assertEquals
(
3
,
Customer
::
find
()
->
max
(
'id'
));
$this->assertEquals(3, Customer::find()->select('COUNT(*)')->scalar());*/
// scope
// $this->assertEquals(2, Customer::find()->active()->count());
...
...
@@ -227,6 +227,12 @@ class ActiveRecordTest extends RedisTestCase
$this
->
assertEquals
(
7
,
OrderItem
::
find
()
->
sum
(
'quantity'
));
}
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'));
}
public
function
testExists
()
{
$this
->
assertTrue
(
Customer
::
find
()
->
where
(
array
(
'id'
=>
2
))
->
exists
());
...
...
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