@@ -81,6 +81,18 @@ class Query extends Component implements QueryInterface
*/
*/
public string $searchType = 'START' ;
public string $searchType = 'START' ;
/**
* Поиск
*
* [свойство => е г о значение]
*/
public array $filter ;
/**
* Тип поиска
*/
public string $filterType = 'START' ;
public $orderBy ;
public $orderBy ;
public $indexBy ;
public $indexBy ;
@@ -229,14 +241,21 @@ class Query extends Component implements QueryInterface
return $this ;
return $this ;
}
}
/**
*/
public function filter ( array $text , string $type = 'START' ) : self
{
$this -> filter = $text ;
$this -> filterType = $type ;
return $this ;
}
/**
/**
* Обойти коллекцию вершин по направлению
* Обойти коллекцию вершин по направлению
*
*
* Генерация AQL выражения
* Генерация AQL выражения
*
*
* @see https://www.arangodb.com/docs/3.7/aql/operations-let.html
*
* @param mixed $vertex Коллекция вершин из которой требуется обход
* @param mixed $vertex Коллекция вершин из которой требуется обход
* @param string $direction Направление ('INBOUND', 'OUTBOUND', 'ANY')
* @param string $direction Направление ('INBOUND', 'OUTBOUND', 'ANY')
*/
*/
@@ -253,24 +272,43 @@ class Query extends Component implements QueryInterface
return $this ;
return $this ;
}
}
/**
* Проверка типа и конвертация
*/
protected static function checkArrayAndConvert ( string | array $text ) : string
{
if ( is_array ( $text )) {
return self :: convertArrayToString ( $text );
}
return $text ;
}
/**
* Конвертация в строку
*/
protected static function convertArrayToString ( array $text ) : string
{
// Очистка
array_walk ( $text , 'trim' );
// Конвертация
return implode ( " , " , $text );
}
/**
/**
* Генерация AQL конструкции "FOR"
* Генерация AQL конструкции "FOR"
*
*
* Примеры:
* Примеры:
* 1. "FOR account"
* 1. "FOR account"
* 2. "FOR account, account_edge_supply"
* 2. "FOR account, account_edge_supply"
*
*/
*/
protected static function genFor ( string | array $for ) : string
protected static function genFor ( string | array $for ) : string
{
{
if ( is_array ( $for )) {
if ( is_array ( $for )) {
// Если передан массив, то конвертировать в строку
// Если передан массив, то конвертировать в строку
// Очистка элементов через trim()
$for = self :: convertArrayToString ( $for );
array_walk ( $for , 'trim' );
// Конвертация
$for = implode ( " , " , $for );
}
}
// Генерация
// Генерация
@@ -368,19 +406,17 @@ class Query extends Component implements QueryInterface
foreach ( $conditions as $condition ) {
foreach ( $conditions as $condition ) {
// Перебор выражений
// Перебор выражений
genForeach_recursion :
foreach ( $condition as $FOR => $IN ) {
foreach ( $condition as $FOR => $IN ) {
// Инициализация операндов
// Инициализация операндов
if ( is_int ( $FOR ) && is_array ( $IN )) {
if ( is_int ( $FOR ) && is_array ( $IN )) {
// Вложенный массив (неожиданные входные данные)
// Вложенный массив (неожиданные входные данные)
// Реинициализация
// !!! Вход в рекурсию !!!
$condition = $IN ;
// Обработка вложенного массива
$aql .= ' ' . $this -> genForeach ([ $IN ]);
// Перебор вложенного массива
continue ;
goto genForeach_recursion ;
}
}
$aql .= " FOR $FOR IN $IN " ;
$aql .= " FOR $FOR IN $IN " ;
@@ -819,23 +855,24 @@ class Query extends Component implements QueryInterface
protected function genQuery ( $query = null , array $params = [])
protected function genQuery ( $query = null , array $params = [])
{
{
// Инициализация
// Инициализация
isset ( $query ) ? $query : $query = $this ;
$query ? ? $query = $this ;
$this -> in ? ? ( isset ( $this -> collection ) ? $this -> in = $this -> collection : throw new Exception ( 'Н е найдена коллекция' )) ;
$query -> in ? ? $query -> in = $query -> collection ? ? throw new Exception ( 'Н е найдена коллекция' );
$this -> for ? ? $this -> for = $this -> in ;
$query -> for ? ? $query -> for = $query -> in ;
$this -> collection ? ? $this -> collection = $this -> in ;
$query -> collection ? ? $query -> collection = self :: checkArrayAndConvert ( $query -> for ) ;
$params = array_merge ( $params , $query -> params );
$params = array_merge ( $params , $query -> params );
$clauses = [
$clauses = [
static :: genFor ( $query -> for ? ? $query -> collection ),
$query :: genFor ( $query -> for ),
static :: genIn ( $query -> in ? ? $query -> collection , $query -> traversals ),
$query :: genIn ( $query -> in , $query -> traversals ),
static :: genLet ( $query -> lets ),
$query :: genLet ( $query -> lets ),
$this -> genForeach ( $query -> foreach ),
$query -> genForeach ( $query -> foreach ),
$this -> genWhere ( $query -> where , $params ),
$query -> genWhere ( $query -> where , $params ),
isset ( $this -> search ) ? $this -> genSearch ( $this -> search , $this -> searchType ) : null ,
isset ( $query -> search ) ? $query -> genSearch ( $query -> search , $query -> searchType ) : null ,
$this -> genOrderBy ( $query -> orderBy , $params ) ,
isset ( $query -> filter ) ? $query -> genFilter ( $query -> filter , $query -> filterType ) : null ,
$this -> genLimit ( $query -> limit , $query -> offset , $params ),
$query -> genOrderBy ( $query -> orderBy , $params ),
$this -> genSelect ( $query -> selec t, $params ),
$query -> genLimit ( $query -> limit , $query -> offse t, $params ),
$query -> genSelect ( $query -> select , $params ),
];
];
$aql = implode ( $query -> separator , array_filter ( $clauses ));
$aql = implode ( $query -> separator , array_filter ( $clauses ));
@@ -874,9 +911,11 @@ class Query extends Component implements QueryInterface
public function all( $db = null)
public function all( $db = null)
{
{
$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');
$cursor = $statement->execute ();
$cursor = $statement->execute ();
@@ -885,6 +924,7 @@ class Query extends Component implements QueryInterface
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 );
}
}
return $this->prepareResult ( $cursor->getAll ());
return $this->prepareResult ( $cursor->getAll ());
}
}
@@ -894,10 +934,13 @@ class Query extends Component implements QueryInterface
public function one( $db = null)
public function one( $db = null)
{
{
$this->limit (1);
$this->limit (1);
$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');
$cursor = $statement->execute ();
$cursor = $statement->execute ();
@@ -922,13 +965,13 @@ class Query extends Component implements QueryInterface
public function insert( $columns , $params = [], $db = null)
public function insert( $columns , $params = [], $db = null)
{
{
// Инициализация
// Инициализация
$this->in ?? (isset( $this->collection ) ? $this->in = $this->collection : throw new Exception('Н е найдена коллекция')) ;
$this->in ?? $this->in = $this->collection ?? throw new Exception('Н е найдена коллекция');
$this->collection ?? $this->collection = $this->in ;
$this->collection ?? $this->collection = $this->in ;
$data = Serializer::encode( $columns );
$data = Serializer::encode( $columns );
$clauses = [
$clauses = [
" INSERT $data IN { $this -> quoteCollectionName ( $this -> in ? ? $this -> collection)} " ,
" INSERT $data IN { $this -> quoteCollectionName ( $this -> collection )} " ,
$this->genOptions (),
$this->genOptions (),
];
];
@@ -968,15 +1011,15 @@ class Query extends Component implements QueryInterface
public function update( $columns , $params = [], $db = null)
public function update( $columns , $params = [], $db = null)
{
{
// Инициализация
// Инициализация
$this->in ?? (isset( $this->collection ) ? $this->in = $this->collection : throw new Exception('Н е найдена коллекция')) ;
$this->in ?? $this->in = $this->collection ?? throw new Exception('Н е найдена коллекция');
$this->for ?? $this->for = $this->in ;
$this->for ?? $this->for = $this->in ;
$this->collection ?? $this->collection = $this->in ;
$this->collection ?? $this->collection = self::checkArrayAndConvert( $this->for ) ;
$clauses = [
$clauses = [
static::genFor( $this->for ?? $this->collection ),
static::genFor( $this->for ),
static::genIn( $this->in ?? $this->collection , $this->traversals ),
static::genIn( $this->in , $this->traversals ),
$this->genWhere ( $this->where , $params ),
$this->genWhere ( $this->where , $params ),
$this->genUpdate ( $this->collectio n , $columns ),
$this->genUpdate ( $this->i n , $columns ),
$this->genOptions (),
$this->genOptions (),
];
];
@@ -1020,15 +1063,15 @@ class Query extends Component implements QueryInterface
public function remove( $params = [], $db = null)
public function remove( $params = [], $db = null)
{
{
// Инициализация
// Инициализация
$this->in ?? (isset( $this->collection ) ? $this->in = $this->collection : throw new Exception('Н е найдена коллекция')) ;
$this->in ?? $this->in = $this->collection ?? throw new Exception('Н е найдена коллекция');
$this->for ?? $this->for = $this->in ;
$this->for ?? $this->for = $this->in ;
$this->collection ?? $this->collection = $this->in ;
$this->collection ?? $this->collection = self::checkArrayAndConvert( $this->for ) ;
$clauses = [
$clauses = [
static::genFor( $this->for ?? $this->collection ),
static::genFor( $this->for ),
static::genIn( $this->in ?? $this->collection , $this->traversals ),
static::genIn( $this->in , $this->traversals ),
$this->genWhere ( $this->where , $params ),
$this->genWhere ( $this->where , $params ),
$this->genRemove ( $this->in ?? $this->collection ),
$this->genRemove ( $this->in ),
$this->genOptions (),
$this->genOptions (),
];
];
@@ -1091,6 +1134,24 @@ class Query extends Component implements QueryInterface
return match (strtoupper( $type )) {
return match (strtoupper( $type )) {
'START', 'STARTS', 'STARTS_WITH' => $query . $this->filterStartsWith ( $expression ),
'START', 'STARTS', 'STARTS_WITH' => $query . $this->filterStartsWith ( $expression ),
'START_SENSETIVE' => $query . $this->filterStartsWith ( $expression , sensetive: true),
'CONTAINS', 'LIKE' => $query . $this->filterContains ( $expression ),
default => $query . Serializer::encode( $expression )
};
}
/**
* @param $collection
* @param $columns
* @return string
*/
protected function genFilter(array $expression , string $type = 'START'): string
{
$query = 'FILTER ';
return match (strtoupper( $type )) {
'START', 'STARTS', 'STARTS_WITH' => $query . $this->filterStartsWith ( $expression ),
'START_SENSETIVE' => $query . $this->filterStartsWith ( $expression , sensetive: true),
'CONTAINS', 'LIKE' => $query . $this->filterContains ( $expression ),
'CONTAINS', 'LIKE' => $query . $this->filterContains ( $expression ),
default => $query . Serializer::encode( $expression )
default => $query . Serializer::encode( $expression )
};
};
@@ -1133,8 +1194,6 @@ class Query extends Component implements QueryInterface
*
*
* Генерация AQL выражения
* Генерация AQL выражения
*
*
* @see https://www.arangodb.com/docs/3.7/aql/operations-let.html
*
* @param string $direction Направление
* @param string $direction Направление
* @param mixed $vertex Коллекция вершин из которой требуется обход
* @param mixed $vertex Коллекция вершин из которой требуется обход
*/
*/
@@ -1279,7 +1338,7 @@ class Query extends Component implements QueryInterface
{
{
$this->foreach = match (true) {
$this->foreach = match (true) {
empty( $this->foreach ) => [ $expression ],
empty( $this->foreach ) => [ $expression ],
default => $this->foreach []= [$expression ]
default => $this->foreach [] = [ $expression ]
};
};
return $this ;
return $this ;
@@ -1375,20 +1434,38 @@ class Query extends Component implements QueryInterface
return $this ;
return $this ;
}
}
public function filterStartsWith(array $expression ): string
public function filterStartsWith(array $expression , bool $sensetive = false ): string
{
{
// Генерация
// Генерация
foreach ( $expression as $key => $value ) {
foreach ( $expression as $key => $value ) {
if ( $sensetive ) {
if (isset( $return )) {
$return .= ' OR STARTS_WITH(' . $this->filterLower ( $this->quoteCollectionName ( $this->collection ) . " . $key " ) . " , " . $this->filterLower ( " \ " $value\ " " ) . " ) " ;
} else {
$return = 'STARTS_WITH(' . $this->filterLower ( $this->quoteCollectionName ( $this->collection ) . " . $key " ) . " , " . $this->filterLower ( " \ " $value\ " " ) . " ) " ;
}
} else {
if (isset( $return )) {
if (isset( $return )) {
$return .= ' OR STARTS_WITH(' . $this->quoteCollectionName ( $this->collection ) . " . $key , \ " $value\ " ) " ;
$return .= ' OR STARTS_WITH(' . $this->quoteCollectionName ( $this->collection ) . " . $key , \ " $value\ " ) " ;
} else {
} else {
$return = 'STARTS_WITH(' . $this->quoteCollectionName ( $this->collection ) . " . $key , \ " $value\ " ) " ;
$return = 'STARTS_WITH(' . $this->quoteCollectionName ( $this->collection ) . " . $key , \ " $value\ " ) " ;
}
}
}
}
}
return $return ;
return $return ;
}
}
public function filterUpper(string $target ): string
{
return " UPPER ( $target ) " ;
}
public function filterLower(string $target ): string
{
return " LOWER ( $target ) " ;
}
public function filterContains(array $expression ): string
public function filterContains(array $expression ): string
{
{
// Инициализация
// Инициализация