Добавление LET, Traversal. рефакторинг
This commit is contained in:
parent
5faa656ede
commit
bf44832914
|
@ -20,7 +20,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||||
parent::__construct($config);
|
parent::__construct($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildQuery($query = null, $params = [])
|
protected function genQuery($query = null, $params = [])
|
||||||
{
|
{
|
||||||
if ($this->primaryModel !== null) {
|
if ($this->primaryModel !== null) {
|
||||||
// lazy loading
|
// lazy loading
|
||||||
|
@ -46,7 +46,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::buildQuery($query, $params);
|
return parent::genQuery($query, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createModels($rows)
|
private function createModels($rows)
|
||||||
|
@ -104,6 +104,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||||
{
|
{
|
||||||
$statement = $this->createCommand($db);
|
$statement = $this->createCommand($db);
|
||||||
$token = $this->getRawAql($statement);
|
$token = $this->getRawAql($statement);
|
||||||
|
|
||||||
Yii::info($token, 'mirzaev\yii2\arangodb\Query::query');
|
Yii::info($token, 'mirzaev\yii2\arangodb\Query::query');
|
||||||
try {
|
try {
|
||||||
Yii::beginProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
Yii::beginProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
||||||
|
@ -114,6 +115,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface
|
||||||
Yii::endProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
Yii::endProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
||||||
throw new \Exception($ex->getMessage(), (int) $ex->getCode(), $ex);
|
throw new \Exception($ex->getMessage(), (int) $ex->getCode(), $ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($rows)) {
|
if (!empty($rows)) {
|
||||||
$models = $this->createModels($rows);
|
$models = $this->createModels($rows);
|
||||||
if (!empty($this->with)) {
|
if (!empty($this->with)) {
|
||||||
|
|
|
@ -107,8 +107,8 @@ abstract class ActiveRecord extends BaseActiveRecord
|
||||||
public static function find()
|
public static function find()
|
||||||
{
|
{
|
||||||
/** @var ActiveQuery $query */
|
/** @var ActiveQuery $query */
|
||||||
$query = \Yii::createObject(ActiveQuery::className(), [get_called_class()]);
|
$query = Yii::createObject(ActiveQuery::class, [get_called_class()]);
|
||||||
$query->from(static::collectionName())->select(static::collectionName());
|
$query->collection(static::collectionName())->select(static::collectionName());
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,14 @@ abstract class ActiveRecord extends BaseActiveRecord
|
||||||
$row = $row->getAll();
|
$row = $row->getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_iterable($row)) {
|
||||||
|
// Если нельзя обработать полученные данные
|
||||||
|
// Например, если прочитан NULL, то далее будет ошибка при обработке в foreach
|
||||||
|
|
||||||
|
// Реинициализация
|
||||||
|
$row = [];
|
||||||
|
}
|
||||||
|
|
||||||
parent::populateRecord($record, $row);
|
parent::populateRecord($record, $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace mirzaev\yii2\arangodb;
|
namespace mirzaev\yii2\arangodb;
|
||||||
|
|
||||||
use yii\base\Object;
|
use yii\base\BaseObject;
|
||||||
|
|
||||||
class AqlExpression extends Object
|
class AqlExpression extends BaseObject
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var string the AQL expression represented by this object
|
* @var string the AQL expression represented by this object
|
||||||
|
|
|
@ -19,16 +19,17 @@ use Exception;
|
||||||
class Query extends Component implements QueryInterface
|
class Query extends Component implements QueryInterface
|
||||||
{
|
{
|
||||||
const PARAM_PREFIX = 'qp';
|
const PARAM_PREFIX = 'qp';
|
||||||
|
const DEBUG = true;
|
||||||
|
|
||||||
public $separator = " ";
|
public $separator = " ";
|
||||||
|
|
||||||
protected $conditionBuilders = [
|
protected $conditionBuilders = [
|
||||||
'NOT' => 'buildNotCondition',
|
'NOT' => 'genNotCondition',
|
||||||
'AND' => 'buildAndCondition',
|
'AND' => 'genAndCondition',
|
||||||
'OR' => 'buildAndCondition',
|
'OR' => 'genAndCondition',
|
||||||
'IN' => 'buildInCondition',
|
'IN' => 'genInCondition',
|
||||||
'LIKE' => 'buildLikeCondition',
|
'LIKE' => 'genLikeCondition',
|
||||||
'BETWEEN' => 'buildBetweenCondition',
|
'BETWEEN' => 'genBetweenCondition'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $conditionMap = [
|
protected $conditionMap = [
|
||||||
|
@ -41,9 +42,26 @@ class Query extends Component implements QueryInterface
|
||||||
|
|
||||||
public $select = [];
|
public $select = [];
|
||||||
|
|
||||||
public $from;
|
public string|array $for;
|
||||||
|
|
||||||
public $where;
|
public string|array $in;
|
||||||
|
|
||||||
|
public string $collection;
|
||||||
|
|
||||||
|
public array $vars = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Массив коллекций вершин и направлений для их обхода
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* ["INBOUND" => "collection1"],
|
||||||
|
* ["OUTBOUND" => "collection2"],
|
||||||
|
* ["ANY" => "collection2"]
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
public array $traversals = [];
|
||||||
|
|
||||||
|
public $where = [];
|
||||||
|
|
||||||
public $limit;
|
public $limit;
|
||||||
|
|
||||||
|
@ -103,7 +121,7 @@ class Query extends Component implements QueryInterface
|
||||||
*/
|
*/
|
||||||
public function createCommand($db = null, $options = [])
|
public function createCommand($db = null, $options = [])
|
||||||
{
|
{
|
||||||
list($aql, $params) = $this->buildQuery($this);
|
list($aql, $params) = $this->genQuery($this);
|
||||||
|
|
||||||
$options = ArrayHelper::merge(
|
$options = ArrayHelper::merge(
|
||||||
$options,
|
$options,
|
||||||
|
@ -162,28 +180,120 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $collection
|
* @param $collection
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function from($collection)
|
public function collection(string $collection)
|
||||||
{
|
{
|
||||||
$this->from = $collection;
|
$this->collection = $collection;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $collection
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
protected function buildFrom($collection)
|
public function for(string|array $for)
|
||||||
{
|
{
|
||||||
$collection = trim($collection);
|
$this->for = $for;
|
||||||
return $collection ? "FOR $collection IN $collection" : '';
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $name
|
*/
|
||||||
|
public function in(string|array $in)
|
||||||
|
{
|
||||||
|
$this->in = $in;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обойти коллекцию вершин по направлению
|
||||||
|
*
|
||||||
|
* Генерация AQL выражения
|
||||||
|
*
|
||||||
|
* @see https://www.arangodb.com/docs/3.7/aql/operations-let.html
|
||||||
|
*
|
||||||
|
* @param mixed $vertex Коллекция вершин из которой требуется обход
|
||||||
|
* @param string $direction Направление ('INBOUND', 'OUTBOUND', 'ANY')
|
||||||
|
*/
|
||||||
|
public function traversal(string $vertex, string $direction = 'INBOUND'): static
|
||||||
|
{
|
||||||
|
$this->traversals[] = [
|
||||||
|
match ($direction) {
|
||||||
|
'INBOUND', 'OUTBOUND', 'ANY' => $direction,
|
||||||
|
default => null
|
||||||
|
}
|
||||||
|
=> $vertex
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация AQL конструкции "FOR"
|
||||||
|
*
|
||||||
|
* Примеры:
|
||||||
|
* 1. "FOR account"
|
||||||
|
* 2. "FOR account, account_edge_supply"
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected static function genFor(string|array $for): string
|
||||||
|
{
|
||||||
|
if (is_array($for)) {
|
||||||
|
// Если передан массив, то конвертировать в строку
|
||||||
|
|
||||||
|
// Очистка элементов через trim()
|
||||||
|
array_walk($for, 'trim');
|
||||||
|
|
||||||
|
// Конвертация
|
||||||
|
$for = implode(", ", $for);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерация
|
||||||
|
return "FOR $for";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Генерация AQL конструкции "IN"
|
||||||
|
*
|
||||||
|
* Примеры:
|
||||||
|
* 1. "IN account"
|
||||||
|
* 2. "IN INBOUND supply account_edge_supply"
|
||||||
|
*/
|
||||||
|
protected static function genIn(string|array|null $in, array $traversals = null): string
|
||||||
|
{
|
||||||
|
if (is_array($in)) {
|
||||||
|
// Если передан массив, то конвертировать в строку
|
||||||
|
|
||||||
|
// Очистка элементов через trim()
|
||||||
|
array_walk($in, 'trim');
|
||||||
|
|
||||||
|
// Конвертация
|
||||||
|
$in = implode(", ", $in);
|
||||||
|
}
|
||||||
|
|
||||||
|
$expression = '';
|
||||||
|
foreach ($traversals as $traversal) {
|
||||||
|
foreach ($traversal as $direction => $vertex) {
|
||||||
|
if ($aql = static::genTraversal($direction, $vertex)) {
|
||||||
|
$expression .= $aql . ', ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$expression = trim($expression, ', ');
|
||||||
|
|
||||||
|
// Если сгенерированное выражение не пустое, то добавить пробел
|
||||||
|
$expression = !empty($expression) ? $expression . ' ' : null;
|
||||||
|
|
||||||
|
// Генерация
|
||||||
|
return "IN $expression" . $in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array $name Название
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function quoteCollectionName($name)
|
public static function quoteCollectionName(string|array $name): string
|
||||||
{
|
{
|
||||||
if (strpos($name, '(') !== false || strpos($name, '{{') !== false) {
|
if (strpos($name, '(') !== false || strpos($name, '{{') !== false) {
|
||||||
return $name;
|
return $name;
|
||||||
|
@ -203,7 +313,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $name
|
* @param $name
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function quoteColumnName($name)
|
public function quoteColumnName(string $name)
|
||||||
{
|
{
|
||||||
if (strpos($name, '(') !== false || strpos($name, '[[') !== false || strpos($name, '{{') !== false) {
|
if (strpos($name, '(') !== false || strpos($name, '[[') !== false || strpos($name, '{{') !== false) {
|
||||||
return $name;
|
return $name;
|
||||||
|
@ -213,7 +323,7 @@ class Query extends Component implements QueryInterface
|
||||||
$prefix = $this->quoteCollectionName($prefix) . '.';
|
$prefix = $this->quoteCollectionName($prefix) . '.';
|
||||||
$name = substr($name, $pos + 1);
|
$name = substr($name, $pos + 1);
|
||||||
} else {
|
} else {
|
||||||
$prefix = $this->quoteCollectionName($this->from) . '.';
|
$prefix = $this->quoteCollectionName($this->collection) . '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $prefix . $name;
|
return $prefix . $name;
|
||||||
|
@ -224,19 +334,21 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildWhere($condition, &$params)
|
protected function genWhere($condition, &$params)
|
||||||
{
|
{
|
||||||
$where = $this->buildCondition($condition, $params);
|
$where = $this->genCondition($condition, $params);
|
||||||
|
|
||||||
return $where === '' ? '' : 'FILTER ' . $where;
|
return $where ? 'FILTER ' . $where : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $condition
|
* @param $condition
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
|
* @todo Разобраться с этим говном
|
||||||
*/
|
*/
|
||||||
protected function buildCondition($condition, &$params)
|
protected function genCondition($condition, &$params)
|
||||||
{
|
{
|
||||||
if (!is_array($condition)) {
|
if (!is_array($condition)) {
|
||||||
return (string) $condition;
|
return (string) $condition;
|
||||||
|
@ -254,7 +366,7 @@ class Query extends Component implements QueryInterface
|
||||||
throw new InvalidParamException('Found unknown operator in query: ' . $operator);
|
throw new InvalidParamException('Found unknown operator in query: ' . $operator);
|
||||||
}
|
}
|
||||||
} else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ...
|
} else { // hash format: 'column1' => 'value1', 'column2' => 'value2', ...
|
||||||
return $this->buildHashCondition($condition, $params);
|
return $this->genHashCondition($condition, $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,13 +376,13 @@ class Query extends Component implements QueryInterface
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function buildHashCondition($condition, &$params)
|
protected function genHashCondition($condition, &$params)
|
||||||
{
|
{
|
||||||
$parts = [];
|
$parts = [];
|
||||||
foreach ($condition as $column => $value) {
|
foreach ($condition as $column => $value) {
|
||||||
if (is_array($value) || $value instanceof Query) {
|
if (is_array($value) || $value instanceof Query) {
|
||||||
// IN condition
|
// IN condition
|
||||||
$parts[] = $this->buildInCondition('IN', [$column, $value], $params);
|
$parts[] = $this->genInCondition('IN', [$column, $value], $params);
|
||||||
} else {
|
} else {
|
||||||
if (strpos($column, '(') === false) {
|
if (strpos($column, '(') === false) {
|
||||||
$column = $this->quoteColumnName($column);
|
$column = $this->quoteColumnName($column);
|
||||||
|
@ -293,12 +405,12 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildAndCondition($operator, $operands, &$params)
|
protected function genAndCondition($operator, $operands, &$params)
|
||||||
{
|
{
|
||||||
$parts = [];
|
$parts = [];
|
||||||
foreach ($operands as $operand) {
|
foreach ($operands as $operand) {
|
||||||
if (is_array($operand)) {
|
if (is_array($operand)) {
|
||||||
$operand = $this->buildCondition($operand, $params);
|
$operand = $this->genCondition($operand, $params);
|
||||||
}
|
}
|
||||||
if ($operand !== '') {
|
if ($operand !== '') {
|
||||||
$parts[] = $operand;
|
$parts[] = $operand;
|
||||||
|
@ -317,7 +429,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildNotCondition($operator, $operands, &$params)
|
protected function genNotCondition($operator, $operands, &$params)
|
||||||
{
|
{
|
||||||
if (count($operands) != 1) {
|
if (count($operands) != 1) {
|
||||||
throw new InvalidParamException("Operator '$operator' requires exactly one operand.");
|
throw new InvalidParamException("Operator '$operator' requires exactly one operand.");
|
||||||
|
@ -325,7 +437,7 @@ class Query extends Component implements QueryInterface
|
||||||
|
|
||||||
$operand = reset($operands);
|
$operand = reset($operands);
|
||||||
if (is_array($operand)) {
|
if (is_array($operand)) {
|
||||||
$operand = $this->buildCondition($operand, $params);
|
$operand = $this->genCondition($operand, $params);
|
||||||
}
|
}
|
||||||
if ($operand === '') {
|
if ($operand === '') {
|
||||||
return '';
|
return '';
|
||||||
|
@ -341,7 +453,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function buildInCondition($operator, $operands, &$params)
|
protected function genInCondition($operator, $operands, &$params)
|
||||||
{
|
{
|
||||||
if (!isset($operands[0], $operands[1])) {
|
if (!isset($operands[0], $operands[1])) {
|
||||||
throw new Exception("Operator '$operator' requires two operands.");
|
throw new Exception("Operator '$operator' requires two operands.");
|
||||||
|
@ -355,7 +467,7 @@ class Query extends Component implements QueryInterface
|
||||||
|
|
||||||
if ($values instanceof Query) {
|
if ($values instanceof Query) {
|
||||||
// sub-query
|
// sub-query
|
||||||
list($sql, $params) = $this->buildQuery($values, $params);
|
list($sql, $params) = $this->genQuery($values, $params);
|
||||||
$column = (array)$column;
|
$column = (array)$column;
|
||||||
if (is_array($column)) {
|
if (is_array($column)) {
|
||||||
foreach ($column as $i => $col) {
|
foreach ($column as $i => $col) {
|
||||||
|
@ -375,7 +487,7 @@ class Query extends Component implements QueryInterface
|
||||||
$values = (array) $values;
|
$values = (array) $values;
|
||||||
|
|
||||||
if (count($column) > 1) {
|
if (count($column) > 1) {
|
||||||
return $this->buildCompositeInCondition($operator, $column, $values, $params);
|
return $this->genCompositeInCondition($operator, $column, $values, $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($column)) {
|
if (is_array($column)) {
|
||||||
|
@ -412,7 +524,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildCompositeInCondition($operator, $columns, $values, &$params)
|
protected function genCompositeInCondition($operator, $columns, $values, &$params)
|
||||||
{
|
{
|
||||||
$vss = [];
|
$vss = [];
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
|
@ -446,7 +558,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @return string the generated AQL expression
|
* @return string the generated AQL expression
|
||||||
* @throws InvalidParamException if wrong number of operands have been given.
|
* @throws InvalidParamException if wrong number of operands have been given.
|
||||||
*/
|
*/
|
||||||
public function buildBetweenCondition($operator, $operands, &$params)
|
public function genBetweenCondition($operator, $operands, &$params)
|
||||||
{
|
{
|
||||||
if (!isset($operands[0], $operands[1], $operands[2])) {
|
if (!isset($operands[0], $operands[1], $operands[2])) {
|
||||||
throw new InvalidParamException("Operator '$operator' requires three operands.");
|
throw new InvalidParamException("Operator '$operator' requires three operands.");
|
||||||
|
@ -471,7 +583,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildLikeCondition($operator, $condition, &$params)
|
protected function genLikeCondition($operator, $condition, &$params)
|
||||||
{
|
{
|
||||||
if (!(isset($condition[0]) && isset($condition[1]))) {
|
if (!(isset($condition[0]) && isset($condition[1]))) {
|
||||||
throw new InvalidParamException("You must set 'column' and 'pattern' params");
|
throw new InvalidParamException("You must set 'column' and 'pattern' params");
|
||||||
|
@ -491,7 +603,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $columns
|
* @param $columns
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildOrderBy($columns)
|
protected function genOrderBy($columns)
|
||||||
{
|
{
|
||||||
if (empty($columns)) {
|
if (empty($columns)) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -527,7 +639,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $offset
|
* @param $offset
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildLimit($limit, $offset)
|
protected function genLimit($limit, $offset)
|
||||||
{
|
{
|
||||||
$aql = '';
|
$aql = '';
|
||||||
if ($this->hasLimit($limit)) {
|
if ($this->hasLimit($limit)) {
|
||||||
|
@ -542,22 +654,17 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $params
|
* @param $params
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildSelect($columns, &$params) // А нахуй здесь params ещё и ссылкой? Потом проверить
|
protected function genSelect($columns, &$params) // А нахуй здесь params ещё и ссылкой? Потом проверить
|
||||||
{
|
{
|
||||||
if ($columns === null || empty($columns)) {
|
if ($columns === null || empty($columns)) {
|
||||||
return 'RETURN ' . $this->from;
|
return 'RETURN ' . $this->collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array($columns)) {
|
if (!is_array($columns)) {
|
||||||
return 'RETURN ' . $columns;
|
return 'RETURN ' . $columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
$names = '';
|
return 'RETURN ' . self::convertArray2Aql($columns, $this->collection);
|
||||||
foreach ($columns as $name => $column) {
|
|
||||||
$names .= "\"$name\": $this->from.$column, ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'RETURN {' . trim($names, ', ') . '}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -565,24 +672,20 @@ class Query extends Component implements QueryInterface
|
||||||
* @param array $params
|
* @param array $params
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function buildQuery($query = null, $params = [])
|
protected function genQuery($query = null, $params = [])
|
||||||
{
|
{
|
||||||
$query = isset($query) ? $query : $this;
|
$query = isset($query) ? $query : $this;
|
||||||
|
|
||||||
if ($query->where === null) {
|
|
||||||
$where = [];
|
|
||||||
} else {
|
|
||||||
$where = $query->where;
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = empty($params) ? $query->params : array_merge($params, $query->params);
|
$params = empty($params) ? $query->params : array_merge($params, $query->params);
|
||||||
|
|
||||||
$clauses = [
|
$clauses = [
|
||||||
$this->buildFrom($query->from),
|
static::genFor($query->for ?? $query->collection),
|
||||||
$this->buildWhere($where, $params),
|
static::genIn($query->in ?? $query->collection, $query->traversals),
|
||||||
$this->buildOrderBy($query->orderBy, $params),
|
static::genLet($query->vars),
|
||||||
$this->buildLimit($query->limit, $query->offset, $params),
|
$this->genWhere($query->where, $params),
|
||||||
$this->buildSelect($query->select, $params),
|
$this->genOrderBy($query->orderBy, $params),
|
||||||
|
$this->genLimit($query->limit, $query->offset, $params),
|
||||||
|
$this->genSelect($query->select, $params),
|
||||||
];
|
];
|
||||||
|
|
||||||
$aql = implode($query->separator, array_filter($clauses));
|
$aql = implode($query->separator, array_filter($clauses));
|
||||||
|
@ -622,6 +725,7 @@ class Query extends Component implements QueryInterface
|
||||||
{
|
{
|
||||||
$statement = $this->createCommand($db);
|
$statement = $this->createCommand($db);
|
||||||
$token = $this->getRawAql($statement);
|
$token = $this->getRawAql($statement);
|
||||||
|
|
||||||
Yii::info($token, 'mirzaev\yii2\arangodb\Query::query');
|
Yii::info($token, 'mirzaev\yii2\arangodb\Query::query');
|
||||||
try {
|
try {
|
||||||
Yii::beginProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
Yii::beginProfile($token, 'mirzaev\yii2\arangodb\Query::query');
|
||||||
|
@ -671,7 +775,7 @@ class Query extends Component implements QueryInterface
|
||||||
|
|
||||||
$clauses = [
|
$clauses = [
|
||||||
"INSERT $doc IN {$this->quoteCollectionName($collection)}",
|
"INSERT $doc IN {$this->quoteCollectionName($collection)}",
|
||||||
$this->buildOptions(),
|
$this->genOptions(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$aql = implode($this->separator, array_filter($clauses));
|
$aql = implode($this->separator, array_filter($clauses));
|
||||||
|
@ -708,12 +812,13 @@ class Query extends Component implements QueryInterface
|
||||||
*/
|
*/
|
||||||
public function update($collection, $columns, $condition = [], $params = [], $db = null)
|
public function update($collection, $columns, $condition = [], $params = [], $db = null)
|
||||||
{
|
{
|
||||||
$this->from($collection);
|
$this->collection = $collection;
|
||||||
$clauses = [
|
$clauses = [
|
||||||
$this->buildFrom($collection),
|
$this->genFor($collection),
|
||||||
$this->buildWhere($condition, $params),
|
$this->genIn($collection),
|
||||||
$this->buildUpdate($collection, $columns),
|
$this->genWhere($condition, $params),
|
||||||
$this->buildOptions(),
|
$this->genUpdate($collection, $columns),
|
||||||
|
$this->genOptions(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$aql = implode($this->separator, array_filter($clauses));
|
$aql = implode($this->separator, array_filter($clauses));
|
||||||
|
@ -744,31 +849,33 @@ class Query extends Component implements QueryInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $collection
|
* Представление
|
||||||
* @param $columns
|
*
|
||||||
* @param array $condition
|
* Работа с представлениями
|
||||||
|
*
|
||||||
|
* @see https://www.arangodb.com/docs/3.7/http/views.html
|
||||||
|
*
|
||||||
|
* @param string $collection
|
||||||
|
* @param string|array $vars
|
||||||
|
* @param array $expression
|
||||||
|
* @param string $type
|
||||||
* @param array $params
|
* @param array $params
|
||||||
* @param null $db
|
* @param Connection $db
|
||||||
* @return bool
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public function search(string|array $collection, string|array $vars, array $expression, int $type = 0, $params = [], $db = null): array
|
public function view(string $collection, string|array|null $vars = null, array $expression = null, string $type = null, array $params = [], $db = null): array
|
||||||
{
|
{
|
||||||
$this->from($collection);
|
$this->collection = $collection;
|
||||||
$clauses = [
|
$clauses = [
|
||||||
$this->buildFrom($collection),
|
$this->genFor($collection),
|
||||||
$this->buildSearch($expression, $type),
|
$this->genIn($collection),
|
||||||
$this->buildLimit($this->limit, 0),
|
$this->genSearch($expression, $type),
|
||||||
$this->buildOptions(),
|
$this->genLimit($this->limit, 0),
|
||||||
$this->buildSelect($vars, $params)
|
$this->genOptions(),
|
||||||
|
$this->genSelect($vars, $params)
|
||||||
];
|
];
|
||||||
|
|
||||||
$aql = implode($this->separator, array_filter($clauses));
|
$aql = implode($this->separator, array_filter($clauses));
|
||||||
|
|
||||||
$fp = fopen('debug.txt', 'a');
|
|
||||||
fwrite($fp, print_r($aql, true) . PHP_EOL);
|
|
||||||
fclose($fp);
|
|
||||||
|
|
||||||
$params = ArrayHelper::merge(
|
$params = ArrayHelper::merge(
|
||||||
$params,
|
$params,
|
||||||
[
|
[
|
||||||
|
@ -791,6 +898,25 @@ class Query extends Component implements QueryInterface
|
||||||
return $this->prepareResult($cursor->getAll());
|
return $this->prepareResult($cursor->getAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Поиск ребра
|
||||||
|
*
|
||||||
|
* Работа с представлениями
|
||||||
|
*/
|
||||||
|
// public function searchEdge(string $collection, string $_from, string $_to, string|array|null $vars = null, string $direction = 'INBOUND', array $expression = null, array $params = [], $db = null)
|
||||||
|
// {
|
||||||
|
// $this->collection = $collection;
|
||||||
|
// $clauses = [
|
||||||
|
// $this->genFor($_from),
|
||||||
|
// $this->genLet($collection, $this->genFor([$_from, $collection], [$_to, $collection], $direction), $params),
|
||||||
|
// $this->genLimit($this->limit, 0),
|
||||||
|
// $this->genOptions(),
|
||||||
|
// $this->genSelect($vars, $params)
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $aql = implode($this->separator, array_filter($clauses));
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $collection
|
* @param $collection
|
||||||
* @param array $condition
|
* @param array $condition
|
||||||
|
@ -801,12 +927,13 @@ class Query extends Component implements QueryInterface
|
||||||
*/
|
*/
|
||||||
public function remove($collection, $condition = [], $params = [], $db = null)
|
public function remove($collection, $condition = [], $params = [], $db = null)
|
||||||
{
|
{
|
||||||
$this->from($collection);
|
$this->collection = $collection;
|
||||||
$clauses = [
|
$clauses = [
|
||||||
$this->buildFrom($collection),
|
$this->genFor($collection),
|
||||||
$this->buildWhere($condition, $params),
|
$this->genIn($collection),
|
||||||
$this->buildRemove($collection),
|
$this->genWhere($condition, $params),
|
||||||
$this->buildOptions(),
|
$this->genRemove($collection),
|
||||||
|
$this->genOptions(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$aql = implode($this->separator, array_filter($clauses));
|
$aql = implode($this->separator, array_filter($clauses));
|
||||||
|
@ -841,7 +968,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $columns
|
* @param $columns
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildUpdate($collection, $columns)
|
protected function genUpdate($collection, $columns)
|
||||||
{
|
{
|
||||||
return 'UPDATE ' . $collection . ' WITH '
|
return 'UPDATE ' . $collection . ' WITH '
|
||||||
. Serializer::encode($columns) . ' IN '
|
. Serializer::encode($columns) . ' IN '
|
||||||
|
@ -852,7 +979,7 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $collection
|
* @param $collection
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildRemove($collection)
|
protected function genRemove($collection)
|
||||||
{
|
{
|
||||||
return 'REMOVE ' . $collection . ' IN ' . $collection;
|
return 'REMOVE ' . $collection . ' IN ' . $collection;
|
||||||
}
|
}
|
||||||
|
@ -862,24 +989,108 @@ class Query extends Component implements QueryInterface
|
||||||
* @param $columns
|
* @param $columns
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildSearch(array $expression, int $type = 0): string
|
protected function genSearch(array $expression, string $type = 'START'): string
|
||||||
{
|
{
|
||||||
$query = 'SEARCH ';
|
$query = 'SEARCH ';
|
||||||
|
|
||||||
return match ($type) {
|
return match (strtoupper($type)) {
|
||||||
1 => $query . $this->filterStartsWith($expression),
|
'START', 'STARTS', 'STARTS_WITH' => $query . $this->filterStartsWith($expression),
|
||||||
|
'CONTAINS', 'LIKE' => $query . $this->filterContains($expression),
|
||||||
default => $query . Serializer::encode($expression)
|
default => $query . Serializer::encode($expression)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Присвоение переменной значения
|
||||||
|
*
|
||||||
|
* Генерация AQL выражения
|
||||||
|
*
|
||||||
|
* @see https://www.arangodb.com/docs/3.7/aql/operations-let.html
|
||||||
|
*
|
||||||
|
* @param array $vars Ключ - переменная, значение - её значение
|
||||||
|
*/
|
||||||
|
protected static function genLet(array $vars): ?string
|
||||||
|
{
|
||||||
|
// Инициализация
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
// Конвертация
|
||||||
|
foreach ($vars as $name => $value) {
|
||||||
|
if (
|
||||||
|
$value[0] === '('
|
||||||
|
|| $value[0] === '"' && substr($value, -1) === '"'
|
||||||
|
|| $value[0] === "'" && substr($value, -1) === "'"
|
||||||
|
) {
|
||||||
|
$condition = $value;
|
||||||
|
} else {
|
||||||
|
$condition = '"' . $value . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$result .= 'LET ' . $name . ' = ' . $condition . ', ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($result, ', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обойти коллекцию вершин по направлению
|
||||||
|
*
|
||||||
|
* Генерация AQL выражения
|
||||||
|
*
|
||||||
|
* @see https://www.arangodb.com/docs/3.7/aql/operations-let.html
|
||||||
|
*
|
||||||
|
* @param string $direction Направление
|
||||||
|
* @param mixed $vertex Коллекция вершин из которой требуется обход
|
||||||
|
*/
|
||||||
|
protected static function genTraversal(string $direction, string $vertex): ?string
|
||||||
|
{
|
||||||
|
return $direction . ' ' . $vertex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildOptions()
|
protected function genOptions()
|
||||||
{
|
{
|
||||||
return empty($this->options) ? '' : ' OPTIONS ' . Json::encode($this->options);
|
return empty($this->options) ? '' : ' OPTIONS ' . Json::encode($this->options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конвертер Array -> AQL (string)
|
||||||
|
*
|
||||||
|
* Примеры:
|
||||||
|
* 1. {"id": product_search._key, "catn": product_search.catn}
|
||||||
|
* 2. {"name": login, "phone": number}
|
||||||
|
* 3. {"users": users}
|
||||||
|
* 4. {}
|
||||||
|
*
|
||||||
|
* @param array $target Массив для конвертации
|
||||||
|
* @param string|null Название коллекции к которой привязывать значения массива
|
||||||
|
*/
|
||||||
|
protected static function convertArray2Aql(array $target, string|null $collection = null): string
|
||||||
|
{
|
||||||
|
// Инициализация
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
// Конвертация
|
||||||
|
foreach ($target as $name => $value) {
|
||||||
|
$result .= "\"$name\": ";
|
||||||
|
|
||||||
|
if (is_null($collection)) {
|
||||||
|
// Коллекция не отправлена
|
||||||
|
|
||||||
|
$result .= "$value, ";
|
||||||
|
} else {
|
||||||
|
// Коллекция отправлена
|
||||||
|
|
||||||
|
$result .= "$collection.$value, ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '{' . trim($result, ', ') . '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Document[] $rows
|
* @param Document[] $rows
|
||||||
* @return array
|
* @return array
|
||||||
|
@ -955,6 +1166,7 @@ class Query extends Component implements QueryInterface
|
||||||
public function indexBy($column)
|
public function indexBy($column)
|
||||||
{
|
{
|
||||||
$this->indexBy = $column;
|
$this->indexBy = $column;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,10 +1175,19 @@ class Query extends Component implements QueryInterface
|
||||||
* @param array $params
|
* @param array $params
|
||||||
* @return $this|static
|
* @return $this|static
|
||||||
*/
|
*/
|
||||||
public function where($condition, $params = [])
|
public function where($condition)
|
||||||
{
|
{
|
||||||
$this->where = $condition;
|
$this->where = $condition;
|
||||||
$this->addParams($params);
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public function let(string $name, mixed $value): static
|
||||||
|
{
|
||||||
|
$this->vars[$name] = $value;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,7 +1228,7 @@ class Query extends Component implements QueryInterface
|
||||||
*
|
*
|
||||||
* This method is similar to [[where()]]. The main difference is that this method will
|
* This method is similar to [[where()]]. The main difference is that this method will
|
||||||
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
||||||
* for building query conditions based on filter values entered by users.
|
* for gening query conditions based on filter values entered by users.
|
||||||
*
|
*
|
||||||
* The following code shows the difference between this method and [[where()]]:
|
* The following code shows the difference between this method and [[where()]]:
|
||||||
*
|
*
|
||||||
|
@ -1046,9 +1267,26 @@ class Query extends Component implements QueryInterface
|
||||||
// Генерация
|
// Генерация
|
||||||
foreach ($expression as $key => $value) {
|
foreach ($expression as $key => $value) {
|
||||||
if ($return) {
|
if ($return) {
|
||||||
$return .= ' OR STARTS_WITH(' . $this->quoteCollectionName($this->from) . ".$key, \"$value\")";
|
$return .= ' OR STARTS_WITH(' . $this->quoteCollectionName($this->collection) . ".$key, \"$value\")";
|
||||||
} else {
|
} else {
|
||||||
$return = 'STARTS_WITH(' . $this->quoteCollectionName($this->from) . ".$key, \"$value\")";
|
$return = 'STARTS_WITH(' . $this->quoteCollectionName($this->collection) . ".$key, \"$value\")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filterContains(array $expression): string
|
||||||
|
{
|
||||||
|
// Инициализация
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
// Генерация
|
||||||
|
foreach ($expression as $key => $value) {
|
||||||
|
if ($return) {
|
||||||
|
$return .= ' OR LIKE(' . $this->quoteCollectionName($this->collection) . ".$key, \"%$value%\")";
|
||||||
|
} else {
|
||||||
|
$return = 'LIKE(' . $this->quoteCollectionName($this->collection) . ".$key, \"%$value%\")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,7 +1299,7 @@ class Query extends Component implements QueryInterface
|
||||||
*
|
*
|
||||||
* This method is similar to [[andWhere()]]. The main difference is that this method will
|
* This method is similar to [[andWhere()]]. The main difference is that this method will
|
||||||
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
||||||
* for building query conditions based on filter values entered by users.
|
* for gening query conditions based on filter values entered by users.
|
||||||
*
|
*
|
||||||
* @param array $condition the new WHERE condition. Please refer to [[where()]]
|
* @param array $condition the new WHERE condition. Please refer to [[where()]]
|
||||||
* on how to specify this parameter.
|
* on how to specify this parameter.
|
||||||
|
@ -1084,7 +1322,7 @@ class Query extends Component implements QueryInterface
|
||||||
*
|
*
|
||||||
* This method is similar to [[orWhere()]]. The main difference is that this method will
|
* This method is similar to [[orWhere()]]. The main difference is that this method will
|
||||||
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
* remove [[isEmpty()|empty query operands]]. As a result, this method is best suited
|
||||||
* for building query conditions based on filter values entered by users.
|
* for gening query conditions based on filter values entered by users.
|
||||||
*
|
*
|
||||||
* @param array $condition the new WHERE condition. Please refer to [[where()]]
|
* @param array $condition the new WHERE condition. Please refer to [[where()]]
|
||||||
* on how to specify this parameter.
|
* on how to specify this parameter.
|
||||||
|
@ -1287,6 +1525,7 @@ class Query extends Component implements QueryInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue