Commit e2b4708b by Carsten Brandt

added support for updateCounters to elasticsearch

issue #1313
parent 8ce2f170
......@@ -340,10 +340,9 @@ class ActiveRecord extends BaseActiveRecord
* @param array $attributes attribute values (name-value pairs) to be saved into the table
* @param array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[ActiveQuery::where()]] on how to specify this parameter.
* @param array $params this parameter is ignored in elasticsearch implementation.
* @return integer the number of rows updated
*/
public static function updateAll($attributes, $condition = [], $params = [])
public static function updateAll($attributes, $condition = [])
{
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) {
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME];
......@@ -362,9 +361,9 @@ class ActiveRecord extends BaseActiveRecord
"_index" => static::index(),
],
]);
$data = Json::encode(array(
$data = Json::encode([
"doc" => $attributes
));
]);
$bulk .= $action . "\n" . $data . "\n";
}
......@@ -380,6 +379,62 @@ class ActiveRecord extends BaseActiveRecord
return $n;
}
/**
* Updates all matching records using the provided counter changes and conditions.
* For example, to increment all customers' age by 1,
*
* ~~~
* Customer::updateAllCounters(['age' => 1]);
* ~~~
*
* @param array $counters the counters to be updated (attribute name => increment value).
* Use negative values if you want to decrement the counters.
* @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @return integer the number of rows updated
*/
public static function updateAllCounters($counters, $condition = [])
{
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) {
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME];
} else {
$primaryKeys = static::find()->where($condition)->column(ActiveRecord::PRIMARY_KEY_NAME);
}
if (empty($primaryKeys) || empty($counters)) {
return 0;
}
$bulk = '';
foreach((array) $primaryKeys as $pk) {
$action = Json::encode([
"update" => [
"_id" => $pk,
"_type" => static::type(),
"_index" => static::index(),
],
]);
$script = '';
foreach($counters as $counter => $value) {
$script .= "ctx._source.$counter += $counter;\n";
}
$data = Json::encode([
"script" => $script,
"params" => $counters
]);
$bulk .= $action . "\n" . $data . "\n";
}
// TODO do this via command
$url = [static::index(), static::type(), '_bulk'];
$response = static::getDb()->post($url, [], $bulk);
$n=0;
foreach($response['items'] as $item) {
if ($item['update']['ok']) {
$n++;
}
}
return $n;
}
/**
* Deletes rows in the table using the provided conditions.
......@@ -393,10 +448,9 @@ class ActiveRecord extends BaseActiveRecord
*
* @param array $condition the conditions that will be put in the WHERE part of the DELETE SQL.
* Please refer to [[ActiveQuery::where()]] on how to specify this parameter.
* @param array $params this parameter is ignored in elasticsearch implementation.
* @return integer the number of rows deleted
*/
public static function deleteAll($condition = [], $params = [])
public static function deleteAll($condition = [])
{
if (count($condition) == 1 && isset($condition[ActiveRecord::PRIMARY_KEY_NAME])) {
$primaryKeys = (array) $condition[ActiveRecord::PRIMARY_KEY_NAME];
......
......@@ -150,10 +150,9 @@ class ActiveRecord extends BaseActiveRecord
* @param array $attributes attribute values (name-value pairs) to be saved into the table
* @param array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[ActiveQuery::where()]] on how to specify this parameter.
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows updated
*/
public static function updateAll($attributes, $condition = null, $params = [])
public static function updateAll($attributes, $condition = null)
{
if (empty($attributes)) {
return 0;
......@@ -203,10 +202,9 @@ class ActiveRecord extends BaseActiveRecord
* Use negative values if you want to decrement the counters.
* @param array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[ActiveQuery::where()]] on how to specify this parameter.
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows updated
*/
public static function updateAllCounters($counters, $condition = null, $params = [])
public static function updateAllCounters($counters, $condition = null)
{
if (empty($counters)) {
return 0;
......@@ -235,10 +233,9 @@ class ActiveRecord extends BaseActiveRecord
*
* @param array $condition the conditions that will be put in the WHERE part of the DELETE SQL.
* Please refer to [[ActiveQuery::where()]] on how to specify this parameter.
* @param array $params this parameter is ignored in redis implementation.
* @return integer the number of rows deleted
*/
public static function deleteAll($condition = null, $params = [])
public static function deleteAll($condition = null)
{
$db = static::getDb();
$attributeKeys = [];
......
......@@ -158,8 +158,6 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* Use negative values if you want to decrement the counters.
* @param string|array $condition the conditions that will be put in the WHERE part of the UPDATE SQL.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* Do not name the parameters as `:bp0`, `:bp1`, etc., because they are used internally by this method.
* @return integer the number of rows updated
*/
public static function updateAllCounters($counters, $condition = '')
......
......@@ -313,13 +313,6 @@ class ActiveRecordTest extends ElasticSearchTestCase
$this->assertEquals([], $order->items);
}
public function testUpdateCounters()
{
// Update Counters is not supported by elasticsearch
// $this->setExpectedException('yii\base\NotSupportedException');
// ActiveRecordTestTrait::testUpdateCounters();
}
/**
* Some PDO implementations(e.g. cubrid) do not support boolean values.
* Make sure this does not affect AR layer.
......
......@@ -670,7 +670,7 @@ trait ActiveRecordTestTrait
$this->assertEquals(1, $orderItem->quantity);
$ret = $orderItem->updateCounters(['quantity' => -1]);
$this->afterSave();
$this->assertTrue($ret);
$this->assertEquals(1, $ret);
$this->assertEquals(0, $orderItem->quantity);
$orderItem = $this->callOrderItemFind($pk);
$this->assertEquals(0, $orderItem->quantity);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment