diff --git a/src/applications/search/compiler/PhutilSearchQueryCompiler.php b/src/applications/search/compiler/PhutilSearchQueryCompiler.php --- a/src/applications/search/compiler/PhutilSearchQueryCompiler.php +++ b/src/applications/search/compiler/PhutilSearchQueryCompiler.php @@ -12,6 +12,8 @@ const OPERATOR_AND = 'and'; const OPERATOR_SUBSTRING = 'sub'; const OPERATOR_EXACT = 'exact'; + const OPERATOR_ABSENT = 'absent'; + const OPERATOR_PRESENT = 'present'; public function setOperators($operators) { $this->operators = $operators; @@ -300,6 +302,22 @@ $require_value = $is_quoted; switch ($operator) { + case self::OPERATOR_NOT: + if ($enable_functions && ($token['function'] !== null)) { + $operator = self::OPERATOR_ABSENT; + $value = null; + } else { + $require_value = true; + } + break; + case self::OPERATOR_SUBSTRING: + if ($enable_functions && ($token['function'] !== null)) { + $operator = self::OPERATOR_PRESENT; + $value = null; + } else { + $require_value = true; + } + break; default: $require_value = true; break; diff --git a/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php b/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php --- a/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php +++ b/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php @@ -97,6 +97,8 @@ $op_and = PhutilSearchQueryCompiler::OPERATOR_AND; $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; $op_exact = PhutilSearchQueryCompiler::OPERATOR_EXACT; + $op_present = PhutilSearchQueryCompiler::OPERATOR_PRESENT; + $op_absent = PhutilSearchQueryCompiler::OPERATOR_ABSENT; $mao = "\xE7\x8C\xAB"; @@ -142,6 +144,18 @@ 'title:' => false, 'title:+' => false, 'title:+""' => false, + 'title:""' => false, + + 'title:~' => array( + array('title', $op_present, null), + ), + + 'title:-' => array( + array('title', $op_absent, null), + ), + + '~' => false, + '-' => false, ); $this->assertCompileFunctionQueries($function_tests);