Commit 983b2286 by Carsten Brandt

elasticsearch AR relations + null values

parent 58b1538b
......@@ -129,4 +129,38 @@ class ActiveQuery extends Query implements ActiveQueryInterface
}
return $model;
}
/**
* @inheritDocs
*/
public function scalar($field, $db = null)
{
$record = parent::one($db);
if ($record !== false) {
if ($field == 'primaryKey') {
return $record['_id'];
} elseif (isset($record['_source'][$field])) {
return $record['_source'][$field];
}
}
return null;
}
/**
* @inheritDocs
*/
public function column($field, $db = null)
{
if ($field == 'primaryKey') {
$command = $this->createCommand($db);
$command->queryParts['fields'] = [];
$rows = $command->queryAll()['hits'];
$result = [];
foreach ($rows as $row) {
$result[] = $row['_id'];
}
return $result;
}
return parent::column($field, $db);
}
}
......@@ -312,16 +312,21 @@ class ActiveRecord extends \yii\db\ActiveRecord
* @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.
* @param array $params this parameter is ignored in elasticsearch implementation.
* @return integer the number of rows updated
*/
public static function updateAll($attributes, $condition = [], $params = [])
{
if (empty($condition)) {
if (count($condition) == 1 && isset($condition['primaryKey'])) {
$primaryKeys = (array) $condition['primaryKey'];
} else {
$primaryKeys = static::find()->where($condition)->column('primaryKey');
}
if (empty($primaryKeys)) {
return 0;
}
$bulk = '';
foreach((array) $condition as $pk) {
foreach((array) $primaryKeys as $pk) {
$action = Json::encode([
"update" => [
"_id" => $pk,
......@@ -362,16 +367,21 @@ class ActiveRecord extends \yii\db\ActiveRecord
*
* @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.
* @param array $params this parameter is ignored in elasticsearch implementation.
* @return integer the number of rows deleted
*/
public static function deleteAll($condition = [], $params = [])
{
if (empty($condition)) {
if (count($condition) == 1 && isset($condition['primaryKey'])) {
$primaryKeys = (array) $condition['primaryKey'];
} else {
$primaryKeys = static::find()->where($condition)->column('primaryKey');
}
if (empty($primaryKeys)) {
return 0;
}
$bulk = '';
foreach((array) $condition as $pk) {
foreach((array) $primaryKeys as $pk) {
$bulk .= Json::encode([
"delete" => [
"_id" => $pk,
......
......@@ -152,6 +152,13 @@ class QueryBuilder extends \yii\base\Object
{
$parts = [];
foreach($condition as $attribute => $value) {
if ($attribute == 'primaryKey') {
if ($value == null) { // there is no null pk
$parts[] = ['script' => ['script' => '0==1']];
} else {
$parts[] = ['ids' => ['values' => is_array($value) ? $value : [$value]]];
}
} else {
if (is_array($value)) { // IN condition
$parts[] = ['in' => [$attribute => $value]];
} else {
......@@ -162,6 +169,7 @@ class QueryBuilder extends \yii\base\Object
}
}
}
}
return count($parts) === 1 ? $parts[0] : ['and' => $parts];
}
......@@ -190,6 +198,9 @@ class QueryBuilder extends \yii\base\Object
}
list($column, $value1, $value2) = $operands;
if ($column == 'primaryKey') {
throw new NotSupportedException('Between condition is not supported for primaryKey.');
}
$filter = ['range' => [$column => ['gte' => $value1, 'lte' => $value2]]];
if ($operator == 'not between') {
$filter = ['not' => $filter];
......@@ -197,7 +208,7 @@ class QueryBuilder extends \yii\base\Object
return $filter;
}
private function buildInCondition($operator, $operands, &$params)
private function buildInCondition($operator, $operands)
{
if (!isset($operands[0], $operands[1])) {
throw new InvalidParamException("Operator '$operator' requires two operands.");
......@@ -208,7 +219,7 @@ class QueryBuilder extends \yii\base\Object
$values = (array)$values;
if (empty($values) || $column === []) {
return $operator === 'in' ? ['script' => ['script' => '0=1']] : [];
return $operator === 'in' ? ['script' => ['script' => '0==1']] : [];
}
if (count($column) > 1) {
......@@ -226,21 +237,32 @@ class QueryBuilder extends \yii\base\Object
unset($values[$i]);
}
}
if ($column == 'primaryKey') {
if (empty($values) && $canBeNull) { // there is no null pk
$filter = ['script' => ['script' => '0==1']];
} else {
$filter = ['ids' => ['values' => array_values($values)]];
if ($canBeNull) {
$filter = ['or' => [$filter, ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]]]];
}
}
} else {
if (empty($values) && $canBeNull) {
return ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]];
$filter = ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]];
} else {
$filter = ['in' => [$column => $values]];
$filter = ['in' => [$column => array_values($values)]];
if ($canBeNull) {
$filter = ['or' => [$filter, ['missing' => ['field' => $column, 'existence' => true, 'null_value' => true]]]];
}
}
}
if ($operator == 'not in') {
$filter = ['not' => $filter];
}
return $filter;
}
}
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
protected function buildCompositeInCondition($operator, $columns, $values)
{
throw new NotSupportedException('composite in is not supported by elasticsearch.');
$vss = array();
......@@ -265,8 +287,9 @@ class QueryBuilder extends \yii\base\Object
return '(' . implode(', ', $columns) . ") $operator (" . implode(', ', $vss) . ')';
}
private function buildLikeCondition($operator, $operands, &$params)
private function buildLikeCondition($operator, $operands)
{
throw new NotSupportedException('like conditions is not supported by elasticsearch.');
if (!isset($operands[0], $operands[1])) {
throw new Exception("Operator '$operator' requires two operands.");
}
......@@ -276,7 +299,7 @@ class QueryBuilder extends \yii\base\Object
$values = (array)$values;
if (empty($values)) {
return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0=1' : '';
return $operator === 'LIKE' || $operator === 'OR LIKE' ? '0==1' : '';
}
if ($operator === 'LIKE' || $operator === 'NOT LIKE') {
......
......@@ -24,7 +24,7 @@ class Customer extends ActiveRecord
public function getOrders()
{
return $this->hasMany('Order', array('customer_id' => 'id'))->orderBy('id');
return $this->hasMany(Order::className(), array('customer_id' => 'primaryKey'))->orderBy('create_time');
}
public static function active($query)
......
......@@ -19,33 +19,31 @@ class Order extends ActiveRecord
public function getCustomer()
{
return $this->hasOne('Customer', ['id' => 'customer_id']);
return $this->hasOne(Customer::className(), ['primaryKey' => 'customer_id']);
}
public function getOrderItems()
{
return $this->hasMany('OrderItem', ['order_id' => 'id']);
return $this->hasMany(OrderItem::className(), ['order_id' => 'primaryKey']);
}
public function getItems()
{
return $this->hasMany('Item', ['id' => 'item_id'])
->via('orderItems', function ($q) {
// additional query configuration
})->orderBy('id');
return $this->hasMany(Item::className(), ['primaryKey' => 'item_id'])
->via('orderItems')->orderBy('name');
}
public function getBooks()
{
return $this->hasMany('Item', ['id' => 'item_id'])
->viaTable('tbl_order_item', ['order_id' => 'id'])
->where(['category_id' => 1]);
}
// public function getBooks()
// {
// return $this->hasMany('Item', ['primaryKey' => 'item_id'])
// ->viaTable('tbl_order_item', ['order_id' => 'primaryKey'])
// ->where(['category_id' => 1]);
// }
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
$this->create_time = time();
// $this->create_time = time();
return true;
} else {
return false;
......
......@@ -19,11 +19,11 @@ class OrderItem extends ActiveRecord
public function getOrder()
{
return $this->hasOne('Order', ['id' => 'order_id']);
return $this->hasOne(Order::className(), ['primaryKey' => 'order_id']);
}
public function getItem()
{
return $this->hasOne('Item', ['id' => 'item_id']);
return $this->hasOne(Item::className(), ['primaryKey' => 'item_id']);
}
}
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