mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 06:56:05 +00:00
orm: all/any operators
This commit is contained in:
@@ -52,6 +52,16 @@ class Comparison implements WhereItem
|
||||
private const OPERATOR_NOT_LIKE = '!*';
|
||||
private const OPERATOR_IN_SUB_QUERY = '=s';
|
||||
private const OPERATOR_NOT_IN_SUB_QUERY = '!=s';
|
||||
private const OPERATOR_NOT_EQUAL_ANY = '!=any';
|
||||
private const OPERATOR_GREATER_ANY = '>any';
|
||||
private const OPERATOR_GREATER_OR_EQUAL_ANY = '>=any';
|
||||
private const OPERATOR_LESS_ANY = '<any';
|
||||
private const OPERATOR_LESS_OR_EQUAL_ANY = '<=any';
|
||||
private const OPERATOR_EQUAL_ALL = '=all';
|
||||
private const OPERATOR_GREATER_ALL = '>all';
|
||||
private const OPERATOR_GREATER_OR_EQUAL_ALL = '>=all';
|
||||
private const OPERATOR_LESS_ALL = '<all';
|
||||
private const OPERATOR_LESS_OR_EQUAL_ALL = '<=all';
|
||||
|
||||
private string $rawKey;
|
||||
private mixed $rawValue;
|
||||
@@ -211,6 +221,126 @@ class Comparison implements WhereItem
|
||||
return self::createInOrNotInArray(self::OPERATOR_NOT_EQUAL, $subject, $set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '!= ANY' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function notEqualAny(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_NOT_EQUAL_ANY, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '> ANY' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function greaterAny(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_GREATER_ANY, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '< ANY' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function lessAny(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_LESS_ANY, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '>= ANY' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function greaterOrEqualAny(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_GREATER_OR_EQUAL_ANY, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '<= ANY' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function lessOrEqualAny(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_LESS_OR_EQUAL_ANY, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '= ALL' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function equalAll(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_EQUAL_ALL, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '> ALL' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function greaterAll(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_GREATER_ALL, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '< ALL' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function lessAll(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_LESS_ALL, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '>= ALL' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function greaterOrEqualAll(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_GREATER_OR_EQUAL_ALL, $argument, $subQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create '<= ALL' comparison.
|
||||
*
|
||||
* @param Expression $argument An expression.
|
||||
* @param Select $subQuery A sub-query.
|
||||
* @return self
|
||||
*/
|
||||
public static function lessOrEqualAll(Expression $argument, Select $subQuery): self
|
||||
{
|
||||
return self::createComparison(self::OPERATOR_LESS_OR_EQUAL_ALL, $argument, $subQuery);
|
||||
}
|
||||
|
||||
private static function createComparison(
|
||||
string $operator,
|
||||
Expression|string $argument1,
|
||||
|
||||
@@ -108,6 +108,18 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
'>',
|
||||
'<',
|
||||
'=',
|
||||
'>=any',
|
||||
'<=any',
|
||||
'>any',
|
||||
'<any',
|
||||
'!=any',
|
||||
'=any',
|
||||
'>=all',
|
||||
'<=all',
|
||||
'>all',
|
||||
'<all',
|
||||
'!=all',
|
||||
'=all',
|
||||
];
|
||||
|
||||
/** @var array<string, string> */
|
||||
@@ -117,6 +129,18 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
'!=' => '<>',
|
||||
'!*' => 'NOT LIKE',
|
||||
'*' => 'LIKE',
|
||||
'>=any' => '>= ANY',
|
||||
'<=any' => '<= ANY',
|
||||
'>any' => '> ANY',
|
||||
'<any' => '< ANY',
|
||||
'!=any' => '<> ANY',
|
||||
'=any' => '= ANY',
|
||||
'>=all' => '>= ALL',
|
||||
'<=all' => '<= ALL',
|
||||
'>all' => '> ALL',
|
||||
'<all' => '< ALL',
|
||||
'!=all' => '<> ALL',
|
||||
'=all' => '= ALL',
|
||||
];
|
||||
|
||||
/** @var array<string, string> */
|
||||
@@ -2424,13 +2448,13 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
}
|
||||
|
||||
if ($field === self::EXISTS_OPERATOR) {
|
||||
if ($value instanceof Select) {
|
||||
$subQueryPart = $this->composeSelect($value);
|
||||
}
|
||||
else {
|
||||
if (!$value instanceof Select) {
|
||||
throw new RuntimeException("Bad EXISTS usage in where-clause.");
|
||||
|
||||
}
|
||||
|
||||
$subQueryPart = $this->composeSelect($value);
|
||||
|
||||
return "EXISTS ({$subQueryPart})";
|
||||
}
|
||||
|
||||
@@ -2482,7 +2506,6 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
return $this->quote(false);
|
||||
}
|
||||
|
||||
// @todo Operators (<s, >s, <=s, =>s) producing 'operator ANY (sub-query)'.
|
||||
if ($operatorOrm === '=s' || $operatorOrm === '!=s') {
|
||||
if ($value instanceof Select) {
|
||||
$subSql = $this->composeSelect($value);
|
||||
@@ -2525,6 +2548,10 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
return "{$leftPart} {$operator} ({$subQueryPart})";
|
||||
}
|
||||
|
||||
if (str_ends_with($operatorOrm, 'any') || str_ends_with($operatorOrm, 'all')) {
|
||||
throw new RuntimeException("ANY/ALL operators can be used only with sub-query.");
|
||||
}
|
||||
|
||||
if ($value instanceof Expression) {
|
||||
$isNotValue = true;
|
||||
|
||||
|
||||
@@ -55,6 +55,18 @@ class PostgresqlQueryComposer extends BaseQueryComposer
|
||||
'!=' => '<>',
|
||||
'!*' => 'NOT ILIKE',
|
||||
'*' => 'ILIKE',
|
||||
'>=any' => '>= ANY',
|
||||
'<=any' => '<= ANY',
|
||||
'>any' => '> ANY',
|
||||
'<any' => '< ANY',
|
||||
'!=any' => '<> ANY',
|
||||
'=any' => '= ANY',
|
||||
'>=all' => '>= ALL',
|
||||
'<=all' => '<= ALL',
|
||||
'>all' => '> ALL',
|
||||
'<all' => '< ALL',
|
||||
'!=all' => '<> ALL',
|
||||
'=all' => '= ALL',
|
||||
];
|
||||
|
||||
/** @var array<string, string> */
|
||||
|
||||
@@ -1210,6 +1210,58 @@ class MysqlQueryComposerTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
public function testSelectWithSubquery7()
|
||||
{
|
||||
$subQuery = SelectBuilder::create()
|
||||
->from('Post')
|
||||
->select('id')
|
||||
->where(['name' => 'test'])
|
||||
->build();
|
||||
|
||||
$sql = $this->query->composeSelect(
|
||||
SelectBuilder::create()
|
||||
->from('Post')
|
||||
->select('id')
|
||||
->where(
|
||||
Comparison::greaterOrEqualAny(Expression::value('1'), $subQuery)
|
||||
)
|
||||
->build()
|
||||
);
|
||||
|
||||
$expectedSql =
|
||||
"SELECT post.id AS `id` FROM `post` ".
|
||||
"WHERE '1' >= ANY (SELECT post.id AS `id` FROM `post` ".
|
||||
"WHERE post.name = 'test' AND post.deleted = 0) AND post.deleted = 0";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
public function testSelectWithSubquery8()
|
||||
{
|
||||
$subQuery = SelectBuilder::create()
|
||||
->from('Post')
|
||||
->select('id')
|
||||
->where(['name' => 'test'])
|
||||
->build();
|
||||
|
||||
$sql = $this->query->composeSelect(
|
||||
SelectBuilder::create()
|
||||
->from('Post')
|
||||
->select('id')
|
||||
->where(
|
||||
Comparison::greaterOrEqualAll(Expression::value('1'), $subQuery)
|
||||
)
|
||||
->build()
|
||||
);
|
||||
|
||||
$expectedSql =
|
||||
"SELECT post.id AS `id` FROM `post` ".
|
||||
"WHERE '1' >= ALL (SELECT post.id AS `id` FROM `post` ".
|
||||
"WHERE post.name = 'test' AND post.deleted = 0) AND post.deleted = 0";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
}
|
||||
|
||||
public function testSelectExists1(): void
|
||||
{
|
||||
$expectedSql =
|
||||
|
||||
Reference in New Issue
Block a user