mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Tighten query compiler rules around spaces inside and after operators
Summary: Ref T13509. Since `title:- cat` is now ambiguous, forbid spaces after operators. Also, forbid spaces inside operators, although this has no effect today. Test Plan: Added unit tests, ran unit tests. Maniphest Tasks: T13509 Differential Revision: https://secure.phabricator.com/D21109
This commit is contained in:
parent
8fa8d0e648
commit
143f86d60b
2 changed files with 73 additions and 10 deletions
|
@ -172,8 +172,10 @@ final class PhutilSearchQueryCompiler
|
|||
}
|
||||
|
||||
if ($mode == 'operator') {
|
||||
if (preg_match('/^\s\z/u', $character)) {
|
||||
continue;
|
||||
if (!$current_operator) {
|
||||
if (preg_match('/^\s\z/u', $character)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/^'.$operator_characters.'\z/', $character)) {
|
||||
|
@ -337,6 +339,7 @@ final class PhutilSearchQueryCompiler
|
|||
'operator' => $operator,
|
||||
'quoted' => $is_quoted,
|
||||
'value' => $value,
|
||||
'raw' => $this->getDisplayToken($token),
|
||||
);
|
||||
|
||||
if ($enable_functions) {
|
||||
|
@ -355,16 +358,58 @@ final class PhutilSearchQueryCompiler
|
|||
|
||||
$result['function'] = $function;
|
||||
|
||||
if ($result['quoted']) {
|
||||
$last_function = null;
|
||||
} else {
|
||||
$is_sticky = !$result['quoted'];
|
||||
switch ($operator) {
|
||||
case self::OPERATOR_ABSENT:
|
||||
case self::OPERATOR_PRESENT:
|
||||
$is_sticky = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($is_sticky) {
|
||||
$last_function = $function;
|
||||
} else {
|
||||
$last_function = null;
|
||||
}
|
||||
}
|
||||
|
||||
$results[] = $result;
|
||||
}
|
||||
|
||||
if ($enable_functions) {
|
||||
// If any function is required to be "absent", there must be no other
|
||||
// terms which make assertions about it.
|
||||
|
||||
$present_tokens = array();
|
||||
$absent_tokens = array();
|
||||
foreach ($results as $result) {
|
||||
$function = $result['function'];
|
||||
|
||||
if ($result['operator'] === self::OPERATOR_ABSENT) {
|
||||
$absent_tokens[$function][] = $result;
|
||||
} else {
|
||||
$present_tokens[$function][] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($absent_tokens as $function => $tokens) {
|
||||
$absent_token = head($tokens);
|
||||
|
||||
if (empty($present_tokens[$function])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$present_token = head($present_tokens[$function]);
|
||||
|
||||
throw new PhutilSearchQueryCompilerSyntaxException(
|
||||
pht(
|
||||
'Query field must be absent ("%s") and present ("%s"). This '.
|
||||
'is impossible, so the query is not valid.',
|
||||
$absent_token['raw'],
|
||||
$present_token['raw']));
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,6 @@ final class PhutilSearchQueryCompilerTestCase
|
|||
'cat -dog' => '+"cat" -"dog"',
|
||||
'cat-dog' => '+"cat-dog"',
|
||||
|
||||
// If there are spaces after an operator, the operator applies to the
|
||||
// next search term.
|
||||
'cat - dog' => '+"cat" -"dog"',
|
||||
|
||||
// Double quotes serve as delimiters even if there is no whitespace
|
||||
// between terms.
|
||||
'"cat"dog' => '+"cat" +"dog"',
|
||||
|
@ -40,9 +36,16 @@ final class PhutilSearchQueryCompilerTestCase
|
|||
// Trailing whitespace should be discarded.
|
||||
'a b ' => '+"a" +"b"',
|
||||
|
||||
// Functions must have search text.
|
||||
// Tokens must have search text.
|
||||
'""' => false,
|
||||
'-' => false,
|
||||
|
||||
// Previously, we permitted spaces to appear inside or after operators.
|
||||
|
||||
// Now that "title:-" is now a valid construction meaning "title is
|
||||
// absent", this had to be tightened. We want "title:- duck" to mean
|
||||
// "title is absent, and any other field matches 'duck'".
|
||||
'cat - dog' => false,
|
||||
);
|
||||
|
||||
$this->assertCompileQueries($tests);
|
||||
|
@ -171,6 +174,21 @@ final class PhutilSearchQueryCompilerTestCase
|
|||
array('title', $op_and, 'x'),
|
||||
array(null, $op_and, 'y'),
|
||||
),
|
||||
|
||||
// The "present" and "absent" functions are not sticky.
|
||||
'title:~ x' => array(
|
||||
array('title', $op_present, null),
|
||||
array(null, $op_and, 'x'),
|
||||
),
|
||||
'title:- x' => array(
|
||||
array('title', $op_absent, null),
|
||||
array(null, $op_and, 'x'),
|
||||
),
|
||||
|
||||
// These queries require a field be both present and absent, which is
|
||||
// impossible.
|
||||
'title:- title:x' => false,
|
||||
'title:- title:~' => false,
|
||||
);
|
||||
|
||||
$this->assertCompileFunctionQueries($function_tests);
|
||||
|
|
Loading…
Reference in a new issue