orm refactor match expr

This commit is contained in:
Yuri Kuznetsov
2023-02-12 15:13:43 +02:00
parent 9c47341fc1
commit d8bd2f451f
3 changed files with 20 additions and 85 deletions

View File

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

View File

@@ -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',
];
}

View File

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