mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 15:06:06 +00:00
orm refactor match expr
This commit is contained in:
@@ -136,13 +136,6 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
'MOD' => '%',
|
||||
];
|
||||
|
||||
/** @var array<string, string> */
|
||||
protected array $matchFunctionMap = [
|
||||
'MATCH_BOOLEAN' => 'IN BOOLEAN MODE',
|
||||
'MATCH_NATURAL_LANGUAGE' => 'IN NATURAL LANGUAGE MODE',
|
||||
'MATCH_QUERY_EXPANSION' => 'WITH QUERY EXPANSION',
|
||||
];
|
||||
|
||||
protected const SELECT_METHOD = 'SELECT';
|
||||
protected const DELETE_METHOD = 'DELETE';
|
||||
protected const UPDATE_METHOD = 'UPDATE';
|
||||
@@ -952,6 +945,19 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
throw new RuntimeException("ORM Query: Not allowed function '{$function}'.");
|
||||
}
|
||||
|
||||
if (in_array($function, ['MATCH_BOOLEAN', 'MATCH_NATURAL_LANGUAGE'])) {
|
||||
if (count($argumentPartList) < 2) {
|
||||
throw new RuntimeException("Not enough arguments for MATCH function.");
|
||||
}
|
||||
|
||||
$queryPart = end($argumentPartList);
|
||||
$columnsPart = implode(', ', array_splice($argumentPartList, 0, -1));
|
||||
$modePart = $function === 'MATCH_BOOLEAN' ?
|
||||
'IN BOOLEAN MODE' : 'IN NATURAL LANGUAGE MODE';
|
||||
|
||||
return "MATCH ({$columnsPart}) AGAINST ({$queryPart} {$modePart})";
|
||||
}
|
||||
|
||||
if (str_starts_with($function, 'YEAR_') && $function !== 'YEAR_NUMBER') {
|
||||
$fiscalShift = substr($function, 5);
|
||||
|
||||
@@ -989,7 +995,7 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
|
||||
if (in_array($function, Functions::COMPARISON_FUNCTION_LIST)) {
|
||||
if (count($argumentPartList) < 2) {
|
||||
throw new RuntimeException("ORM Query: Not enough arguments for function '{$function}'.");
|
||||
throw new RuntimeException("Not enough arguments for function '{$function}'.");
|
||||
}
|
||||
|
||||
$operator = $this->comparisonFunctionOperatorMap[$function];
|
||||
@@ -1181,68 +1187,6 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
return "CONVERT_TZ(". $argumentPartList[0]. ", '+00:00', " . $this->quote($offsetString) . ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
protected function convertMatchExpression(Entity $entity, string $expression, array $params): string
|
||||
{
|
||||
$delimiterPosition = strpos($expression, ':');
|
||||
|
||||
if ($delimiterPosition === false) {
|
||||
throw new RuntimeException("ORM Query: Bad MATCH usage.");
|
||||
}
|
||||
|
||||
$function = substr($expression, 0, $delimiterPosition);
|
||||
$rest = substr($expression, $delimiterPosition + 1);
|
||||
|
||||
if (empty($rest)) {
|
||||
throw new RuntimeException("ORM Query: Empty MATCH parameters.");
|
||||
}
|
||||
|
||||
if (str_starts_with($rest, '(') && str_ends_with($rest, ')')) {
|
||||
$rest = substr($rest, 1, -1);
|
||||
|
||||
$argumentList = Util::parseArgumentListFromFunctionContent($rest);
|
||||
|
||||
if (count($argumentList) < 2) {
|
||||
throw new RuntimeException("ORM Query: Bad MATCH usage.");
|
||||
}
|
||||
|
||||
$columnList = [];
|
||||
|
||||
for ($i = 0; $i < count($argumentList) - 1; $i++) {
|
||||
$columnList[] = $argumentList[$i];
|
||||
}
|
||||
|
||||
$query = $argumentList[count($argumentList) - 1];
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("ORM Query: Bad MATCH usage.");
|
||||
}
|
||||
|
||||
$fromAlias = $this->getFromAlias($params, $entity->getEntityType());
|
||||
|
||||
foreach ($columnList as $i => $column) {
|
||||
$columnList[$i] = $this->quoteColumn($fromAlias . '.' . $this->sanitize($this->toDb($column)));
|
||||
}
|
||||
|
||||
if (!Util::isArgumentString($query)) {
|
||||
throw new RuntimeException("ORM Query: Bad MATCH usage. The last argument should be a string.");
|
||||
}
|
||||
|
||||
$query = mb_substr($query, 1, -1);
|
||||
|
||||
$query = $this->quote($query);
|
||||
|
||||
if (!in_array($function, Functions::MATCH_FUNCTION_LIST)) {
|
||||
throw new RuntimeException("ORM Query: Not allowed MATCH usage.");
|
||||
}
|
||||
|
||||
$modePart = ' ' . $this->matchFunctionMap[$function];
|
||||
|
||||
return "MATCH (" . implode(',', $columnList) . ") AGAINST (" . $query . $modePart . ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
@@ -1265,11 +1209,6 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
/** @var int $delimiterPosition */
|
||||
$delimiterPosition = strpos($attribute, ':');
|
||||
$function = substr($attribute, 0, $delimiterPosition);
|
||||
|
||||
if (in_array($function, Functions::MATCH_FUNCTION_LIST)) {
|
||||
return $this->convertMatchExpression($entity, $attribute, $params);
|
||||
}
|
||||
|
||||
$attribute = substr($attribute, $delimiterPosition + 1);
|
||||
|
||||
if (str_starts_with($attribute, '(') && str_ends_with($attribute, ')')) {
|
||||
@@ -2530,7 +2469,7 @@ abstract class BaseQueryComposer implements QueryComposer
|
||||
): ?string {
|
||||
|
||||
if (is_int($leftKey) && is_string($value)) {
|
||||
return $this->convertMatchExpression($entity, $value, $params);
|
||||
return $this->convertComplexExpression($entity, $value, false, $params);
|
||||
}
|
||||
|
||||
$field = $leftKey;
|
||||
|
||||
@@ -130,6 +130,8 @@ class Functions
|
||||
'TIMESTAMPDIFF_MINUTE',
|
||||
'TIMESTAMPDIFF_SECOND',
|
||||
'POSITION_IN_LIST',
|
||||
'MATCH_BOOLEAN',
|
||||
'MATCH_NATURAL_LANGUAGE',
|
||||
];
|
||||
|
||||
public const COMPARISON_FUNCTION_LIST = [
|
||||
@@ -150,10 +152,4 @@ class Functions
|
||||
'DIV',
|
||||
'MOD',
|
||||
];
|
||||
|
||||
public const MATCH_FUNCTION_LIST = [
|
||||
'MATCH_BOOLEAN',
|
||||
'MATCH_NATURAL_LANGUAGE',
|
||||
'MATCH_QUERY_EXPANSION',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1306,7 +1306,7 @@ class MysqlQueryComposerTest extends \PHPUnit\Framework\TestCase
|
||||
$expectedSql =
|
||||
"SELECT DISTINCT article.id AS `id`, article.name AS `name`, article.description AS `description` " .
|
||||
"FROM `article` WHERE article.deleted = 0 ".
|
||||
"ORDER BY MATCH (article.name,article.description) AGAINST ('test' IN BOOLEAN MODE) DESC";
|
||||
"ORDER BY MATCH (article.name, article.description) AGAINST ('test' IN BOOLEAN MODE) DESC";
|
||||
|
||||
$sql = $this->query->compose($select);
|
||||
|
||||
@@ -1326,7 +1326,7 @@ class MysqlQueryComposerTest extends \PHPUnit\Framework\TestCase
|
||||
$expectedSql =
|
||||
"SELECT DISTINCT article.id AS `id`, article.name AS `name`, article.description AS `description` " .
|
||||
"FROM `article` WHERE article.deleted = 0 ".
|
||||
"ORDER BY MATCH (article.name,article.description) AGAINST ('test' IN BOOLEAN MODE) DESC";
|
||||
"ORDER BY MATCH (article.name, article.description) AGAINST ('test' IN BOOLEAN MODE) DESC";
|
||||
|
||||
$sql = $this->query->compose($select);
|
||||
|
||||
@@ -1801,7 +1801,7 @@ class MysqlQueryComposerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$expectedSql =
|
||||
"SELECT article.id AS `id`, article.name AS `name` FROM `article` " .
|
||||
"WHERE MATCH (article.name,article.description) AGAINST " .
|
||||
"WHERE MATCH (article.name, article.description) AGAINST " .
|
||||
"('test +hello' IN BOOLEAN MODE) AND article.id IS NOT NULL AND article.deleted = 0";
|
||||
|
||||
$this->assertEquals($expectedSql, $sql);
|
||||
|
||||
Reference in New Issue
Block a user