This commit is contained in:
Yurii
2026-06-01 15:35:06 +03:00
parent 33ebfc6504
commit d5b9c5d77f
3 changed files with 54 additions and 123 deletions

View File

@@ -51,7 +51,6 @@ use Espo\ORM\Query\Insert;
use Espo\ORM\Query\Delete;
use Espo\ORM\Query\Union;
use Espo\ORM\QueryComposer\Part\FunctionConverterFactory;
use Espo\ORM\Type\AttributeType;
use PDO;
use RuntimeException;
@@ -71,7 +70,7 @@ abstract class BaseQueryComposer implements QueryComposer
* @var string[]
* @todo Remove.
*/
protected const PARAM_LIST = [
protected const array PARAM_LIST = [
'select',
'whereClause',
'offset',
@@ -101,12 +100,12 @@ abstract class BaseQueryComposer implements QueryComposer
];
/** @var string[] */
protected const SQL_OPERATORS = [
protected const array SQL_OPERATORS = [
'OR',
'AND',
];
protected const EXISTS_OPERATOR = 'EXISTS';
protected const string EXISTS_OPERATOR = 'EXISTS';
/** @var array<string, string> */
protected array $comparisonOperatorMap = [
@@ -154,10 +153,9 @@ abstract class BaseQueryComposer implements QueryComposer
'MOD' => '%',
];
protected const SELECT_METHOD = 'SELECT';
protected const DELETE_METHOD = 'DELETE';
protected const UPDATE_METHOD = 'UPDATE';
protected const INSERT_METHOD = 'INSERT';
private const string SELECT_METHOD = 'SELECT';
private const string DELETE_METHOD = 'DELETE';
private const string UPDATE_METHOD = 'UPDATE';
protected string $identifierQuoteCharacter = '`';
@@ -166,10 +164,6 @@ abstract class BaseQueryComposer implements QueryComposer
protected bool $indexHints = true;
protected bool $skipForeignIfForUpdate = false;
protected EntityFactory $entityFactory;
protected PDO $pdo;
protected Metadata $metadata;
protected ?FunctionConverterFactory $functionConverterFactory;
protected Helper $helper;
/** @var array<string, string> */
@@ -180,16 +174,12 @@ abstract class BaseQueryComposer implements QueryComposer
protected $seedCache = [];
public function __construct(
PDO $pdo,
EntityFactory $entityFactory,
Metadata $metadata,
?FunctionConverterFactory $functionConverterFactory = null,
?EventDispatcher $eventDispatcher = null
protected PDO $pdo,
protected EntityFactory $entityFactory,
protected Metadata $metadata,
protected ?FunctionConverterFactory $functionConverterFactory = null,
?EventDispatcher $eventDispatcher = null,
) {
$this->entityFactory = $entityFactory;
$this->pdo = $pdo;
$this->metadata = $metadata;
$this->functionConverterFactory = $functionConverterFactory;
$this->helper = new Helper($metadata);
@@ -241,19 +231,16 @@ abstract class BaseQueryComposer implements QueryComposer
public function composeCreateSavepoint(string $savepointName): string
{
/** @noinspection PhpDeprecationInspection */
return 'SAVEPOINT ' . $this->sanitize($savepointName);
}
public function composeReleaseSavepoint(string $savepointName): string
{
/** @noinspection PhpDeprecationInspection */
return 'RELEASE SAVEPOINT ' . $this->sanitize($savepointName);
}
public function composeRollbackToSavepoint(string $savepointName): string
{
/** @noinspection PhpDeprecationInspection */
return 'ROLLBACK TO SAVEPOINT ' . $this->sanitize($savepointName);
}
@@ -325,17 +312,16 @@ abstract class BaseQueryComposer implements QueryComposer
$aliasPart = null;
if ($alias) {
/** @noinspection PhpDeprecationInspection */
$aliasPart = $this->sanitize($alias);
}
return $this->composeDeleteQuery(
$this->toDb($entityType),
$aliasPart,
$wherePart,
$joinsPart,
$orderPart,
$params['limit']
table: $this->toDb($entityType),
alias: $aliasPart,
where: $wherePart,
joins: $joinsPart,
order: $orderPart,
limit: $params['limit'],
);
}
@@ -359,12 +345,12 @@ abstract class BaseQueryComposer implements QueryComposer
$setPart = $this->getSetPart($entity, $values, $params);
return $this->composeUpdateQuery(
$this->toDb($entityType),
$setPart,
$wherePart,
$joinsPart,
$orderPart,
$params['limit']
table: $this->toDb($entityType),
set: $setPart,
where: $wherePart,
joins: $joinsPart,
order: $orderPart,
limit: $params['limit'],
);
}
@@ -470,7 +456,7 @@ abstract class BaseQueryComposer implements QueryComposer
}
/**
* @param array<string|mixed[]> $orderBy
* @param array<string|array<int, mixed>> $orderBy
*/
protected function getUnionOrderPart(array $orderBy): string
{
@@ -486,10 +472,7 @@ abstract class BaseQueryComposer implements QueryComposer
if (is_int($item[0])) {
$by = (string) $item[0];
} else {
/** @noinspection PhpDeprecationInspection */
$by = $this->quoteIdentifier(
$this->sanitizeSelectAlias($item[0])
);
$by = $this->quoteIdentifier($this->sanitizeSelectAlias($item[0]));
}
$orderByParts[] = $by . ' ' . $direction;
@@ -544,11 +527,11 @@ abstract class BaseQueryComposer implements QueryComposer
} else {
foreach ($values as $valuesItem) {
foreach ($columns as $item) {
if (!array_key_exists($item, $valuesItem)) {
throw new RuntimeException(
"ORM Query: 'values' should contain all items listed in 'columns'."
);
if (array_key_exists($item, $valuesItem)) {
continue;
}
throw new RuntimeException("ORM Query: 'values' should contain all items listed in 'columns'.");
}
}
}
@@ -654,7 +637,6 @@ abstract class BaseQueryComposer implements QueryComposer
$indexKeyList = $entityType ?
$this->getIndexKeyList($entityType, $params) : null;
/** @noinspection PhpDeprecationInspection */
$fromAlias = $fromAlias ?
$this->sanitize($fromAlias) : null;
@@ -849,14 +831,6 @@ abstract class BaseQueryComposer implements QueryComposer
}
}
/*if (!empty($params['additionalSelectColumns']) && is_array($params['additionalSelectColumns'])) {
foreach ($params['additionalSelectColumns'] as $column => $field) {
$itemAlias = $this->sanitizeSelectAlias($field);
$selectPart .= ", " . $column . " AS " . $this->quoteIdentifier($itemAlias);
}
}*/
if ($selectPart === '') {
return null;
}
@@ -1193,13 +1167,11 @@ abstract class BaseQueryComposer implements QueryComposer
}
if (!empty($function)) {
/** @noinspection PhpDeprecationInspection */
$function = strtoupper($this->sanitize($function));
}
if (!$function) {
return $this->getFunctionArgumentPart($entity, $attribute, $distinct, $params);
}
$argumentList = Util::parseArgumentListFromFunctionContent($attribute);
@@ -1213,24 +1185,15 @@ abstract class BaseQueryComposer implements QueryComposer
$part = implode(', ', $argumentPartList);
return $this->getFunctionPart(
$function,
$part,
$params,
$entityType,
$distinct,
$argumentPartList
function: $function,
part: $part,
params: $params,
entityType: $entityType,
distinct: $distinct,
argumentPartList: $argumentPartList,
);
}
/**
* @deprecated As of v6.0. Use `Util::getAllAttributesFromComplexExpression`.
* @return string[]
*/
public static function getAllAttributesFromComplexExpression(string $expression): array
{
return Util::getAllAttributesFromComplexExpression($expression);
}
/**
* @param array<string, mixed> $params
*/
@@ -1238,7 +1201,7 @@ abstract class BaseQueryComposer implements QueryComposer
Entity $entity,
string $attribute,
bool $distinct,
array &$params
array &$params,
): string {
$argument = $attribute;
@@ -1346,7 +1309,6 @@ abstract class BaseQueryComposer implements QueryComposer
$alias = $params['fromAlias'] ?? null;
if ($alias) {
/** @noinspection PhpDeprecationInspection */
return $this->sanitize($alias);
}
@@ -1427,7 +1389,6 @@ abstract class BaseQueryComposer implements QueryComposer
return $part;
}
/** @noinspection PhpDeprecationInspection */
$part = $this->getFromAlias($params, $entity->getEntityType()) . '.' .
$this->toDb($this->sanitize($attribute));
@@ -1492,7 +1453,6 @@ abstract class BaseQueryComposer implements QueryComposer
$fromAlias = $this->getFromAlias($params, $entity->getEntityType());
/** @noinspection PhpDeprecationInspection */
$path = $fromAlias . '.' . $this->toDb($this->sanitize($attribute));
return $this->quoteColumn($path);
@@ -1668,13 +1628,9 @@ abstract class BaseQueryComposer implements QueryComposer
$expression = explode(':', $expression)[1];
}
/** @noinspection PhpDeprecationInspection */
$attributeList = self::getAllAttributesFromComplexExpression($expression);
$attributeList = Util::getAllAttributesFromComplexExpression($expression);
$list = array_merge(
$list,
$attributeList
);
$list = array_merge($list, $attributeList);
}
return $list;
@@ -1785,7 +1741,6 @@ abstract class BaseQueryComposer implements QueryComposer
continue;
}
/** @noinspection PhpDeprecationInspection */
$alias = $this->sanitizeSelectAlias($item[1]);
if ($alias === '') {
@@ -1989,10 +1944,9 @@ abstract class BaseQueryComposer implements QueryComposer
$key = $keySet['key'];
$foreignKey = $keySet['foreignKey'];
/** @noinspection PhpDeprecationInspection */
$alias = !$alias ?
$this->getAlias($entity, $relationName) :
$this->sanitizeSelectAlias($alias);
$alias = $alias ?
$this->sanitizeSelectAlias($alias) :
$this->getAlias($entity, $relationName);
if (!$alias) {
return null;
@@ -2462,7 +2416,6 @@ abstract class BaseQueryComposer implements QueryComposer
$alias = $this->getFromAlias($params, $entityType);
/** @noinspection PhpDeprecationInspection */
$path = $alias . '.' . $this->toDb($this->sanitize($attribute));
return $this->quoteColumn($path);
@@ -2776,7 +2729,7 @@ abstract class BaseQueryComposer implements QueryComposer
}
$fromAlias = $this->getFromAlias($params, $entity->getEntityType());
/** @noinspection PhpDeprecationInspection */
$column = $fromAlias . '.' . $this->toDb($this->sanitize($attribute));
return $this->quoteColumn($column);
@@ -3036,8 +2989,8 @@ abstract class BaseQueryComposer implements QueryComposer
/**
* @param array<string|int, mixed> $joinConditions
* @param array<string, mixed[]> $joins
* @param array<string, mixed> $params
* @param array<string, array<int, mixed>> $joins
* @param array<string, array<int, mixed>> $params
*/
protected function getJoinsTypePart(
Entity $entity,
@@ -3114,7 +3067,6 @@ abstract class BaseQueryComposer implements QueryComposer
/**
* @param array<string, mixed> $params
* @noinspection PhpDeprecationInspection
*/
protected function buildJoinConditionStatement(
Entity $entity,
@@ -3240,16 +3192,13 @@ abstract class BaseQueryComposer implements QueryComposer
throw new LogicException();
}
/** @noinspection PhpDeprecationInspection */
$alias = $this->sanitizeSelectAlias($alias);
} else {
/** @noinspection PhpDeprecationInspection */
$alias = $alias === null ?
$this->sanitize($target) :
$this->sanitizeSelectAlias($alias);
}
/** @noinspection PhpDeprecationInspection */
$targetPart = is_string($target) ?
$this->quoteIdentifier($this->toDb($this->sanitize($target))) :
'(' . $this->composeSelecting($target) . ')';
@@ -3296,7 +3245,6 @@ abstract class BaseQueryComposer implements QueryComposer
$alias = $relationName;
}
/** @noinspection PhpDeprecationInspection */
$alias = $this->sanitize($alias);
$relationConditions = $this->getRelationParam($entity, $relationName, RelationParam::CONDITIONS);
@@ -3635,7 +3583,7 @@ abstract class BaseQueryComposer implements QueryComposer
string $table,
string $columns,
string $values,
?string $update = null
?string $update = null,
): string {
$sql = "INSERT INTO " . $this->quoteIdentifier($table) . " ($columns) $values";
@@ -3670,15 +3618,12 @@ abstract class BaseQueryComposer implements QueryComposer
if (strpos($attribute, '.') > 0) {
[$alias, $attribute] = explode('.', $attribute);
/** @noinspection PhpDeprecationInspection */
$alias = $this->sanitize($alias);
/** @noinspection PhpDeprecationInspection */
$column = $this->toDb($this->sanitize($attribute));
$left = $this->quoteColumn("$alias.$column");
} else {
$table = $this->toDb($entity->getEntityType());
/** @noinspection PhpDeprecationInspection */
$column = $this->toDb($this->sanitize($attribute));
$left = $this->quoteColumn("$table.$column");
@@ -3702,12 +3647,7 @@ abstract class BaseQueryComposer implements QueryComposer
$list = [];
foreach ($columnList as $column) {
/** @noinspection PhpDeprecationInspection */
$list[] = $this->quoteIdentifier(
$this->toDb(
$this->sanitize($column)
)
);
$list[] = $this->quoteIdentifier($this->toDb($this->sanitize($column)));
}
return implode(', ', $list);
@@ -3736,12 +3676,9 @@ abstract class BaseQueryComposer implements QueryComposer
$list = [];
foreach ($values as $column => $value) {
/** @noinspection PhpDeprecationInspection */
$list[] = $this->quoteIdentifier(
$this->toDb(
$this->sanitize($column)
)
) . " = " . $this->quote($value);
$leftPart = $this->quoteIdentifier($this->toDb($this->sanitize($column)));
$list[] = $leftPart . " = " . $this->quote($value);
}
return implode(', ', $list);

View File

@@ -35,7 +35,6 @@ use Espo\ORM\Query\Delete as DeleteQuery;
use Espo\ORM\Query\DeleteBuilder;
use Espo\ORM\Query\Insert as InsertQuery;
use Espo\ORM\Query\LockTable as LockTableQuery;
use Espo\ORM\Query\Part\Condition as Cond;
use Espo\ORM\Query\SelectBuilder;
use Espo\ORM\Query\Update as UpdateQuery;
@@ -531,11 +530,11 @@ class PostgresqlQueryComposer extends BaseQueryComposer
$alias = $this->sanitize($alias);
$column = $this->toDb($this->sanitize($attribute));
$left = $this->quoteColumn("{$alias}.{$column}");
$left = $this->quoteColumn("$alias.$column");
} else {
$column = $this->toDb($this->sanitize($attribute));
$left = $this->quoteColumn("{$column}"); // Diff.
$left = $this->quoteColumn("$column"); // Diff.
}
$right = $isNotValue ?
@@ -584,17 +583,12 @@ class PostgresqlQueryComposer extends BaseQueryComposer
protected function limit(string $sql, ?int $offset = null, ?int $limit = null): string
{
if (!is_null($offset) && !is_null($limit)) {
$offset = intval($offset);
$limit = intval($limit);
$sql .= " LIMIT $limit OFFSET $offset";
return $sql;
}
if (!is_null($limit)) {
$limit = intval($limit);
$sql .= " LIMIT $limit";
return $sql;

View File

@@ -2385,7 +2385,7 @@ class MysqlQueryComposerTest extends TestCase
{
$expression = "CONCAT:(MONTH:comment.created_at,' ',CONCAT:(comment.name,'+'))";
$list = $this->query::getAllAttributesFromComplexExpression($expression);
$list = Util::getAllAttributesFromComplexExpression($expression);
$this->assertTrue(in_array('comment.created_at', $list));
$this->assertTrue(in_array('comment.name', $list));
@@ -2394,14 +2394,14 @@ class MysqlQueryComposerTest extends TestCase
public function testGetAllAttributesFromComplexExpression1()
{
$expression = "test";
$list = $this->query::getAllAttributesFromComplexExpression($expression);
$list = Util::getAllAttributesFromComplexExpression($expression);
$this->assertTrue(in_array('test', $list));
}
public function testGetAllAttributesFromComplexExpression2()
{
$expression = "comment.test";
$list = $this->query::getAllAttributesFromComplexExpression($expression);
$list = Util::getAllAttributesFromComplexExpression($expression);
$this->assertTrue(in_array('comment.test', $list));
}