Добавление LET, Traversal. рефакторинг

This commit is contained in:
RedHood 2021-01-31 11:36:27 +10:00
parent 5faa656ede
commit bf44832914
4 changed files with 355 additions and 106 deletions

View File

@ -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)) {

View File

@ -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);
} }

View File

@ -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

View File

@ -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;
} }