1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-10 23:01:04 +01:00

Add "title:..." support to the Ferret engine

Summary:
Ref T12819. Adds (hacky, hard-coded) field support (for now, only for "title").

I've written this so `title:quick ferret` is the same as `title:quick title:ferret`. I think this is what users probably mean.

You can do the other thing as `ferret title:quick`, or `title:quick all:ferret`.

Test Plan: Searched for `title:x`, `title:"x"`, `title:~"x"`, etc. Searched for "garbage:y", got an exception since that's not a recognized function. Searched for `title:x y`, saw both do title search.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T12819

Differential Revision: https://secure.phabricator.com/D18503
This commit is contained in:
epriestley 2017-08-30 10:09:20 -07:00
parent 048aa36c23
commit 3b43a70773

View file

@ -29,6 +29,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
private $ngrams = array(); private $ngrams = array();
private $ferretEngine; private $ferretEngine;
private $ferretTokens; private $ferretTokens;
private $ferretTables;
protected function getPageCursors(array $page) { protected function getPageCursors(array $page) {
return array( return array(
@ -1401,6 +1402,43 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$this->ferretEngine = $engine; $this->ferretEngine = $engine;
$this->ferretTokens = $fulltext_tokens; $this->ferretTokens = $fulltext_tokens;
$function_map = array(
'all' => PhabricatorSearchDocumentFieldType::FIELD_ALL,
'title' => PhabricatorSearchDocumentFieldType::FIELD_TITLE,
);
$current_function = 'all';
$table_map = array();
$idx = 1;
foreach ($this->ferretTokens as $fulltext_token) {
$raw_token = $fulltext_token->getToken();
$function = $raw_token->getFunction();
if ($function === null) {
$function = $current_function;
}
if (!isset($function_map[$function])) {
throw new PhutilSearchQueryCompilerSyntaxException(
pht(
'Unknown search function "%s".',
$function));
}
if (!isset($table_map[$function])) {
$alias = 'ftfield'.$idx++;
$table_map[$function] = array(
'alias' => $alias,
'key' => $function_map[$function],
);
}
$current_function = $function;
}
$this->ferretTables = $table_map;
return $this; return $this;
} }
@ -1525,10 +1563,19 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$ngram); $ngram);
} }
$joins[] = qsprintf( foreach ($this->ferretTables as $table) {
$conn, $alias = $table['alias'];
'JOIN %T ftfield ON ftdoc.id = ftfield.documentID',
$field_table->getTableName()); $joins[] = qsprintf(
$conn,
'JOIN %T %T ON ftdoc.id = %T.documentID
AND %T.fieldKey = %s',
$field_table->getTableName(),
$alias,
$alias,
$alias,
$table['key']);
}
return $joins; return $joins;
} }
@ -1540,15 +1587,25 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$ngram_engine = new PhabricatorNgramEngine(); $ngram_engine = new PhabricatorNgramEngine();
$stemmer = new PhutilSearchStemmer(); $stemmer = new PhutilSearchStemmer();
$table_map = $this->ferretTables;
$op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING;
$op_not = PhutilSearchQueryCompiler::OPERATOR_NOT; $op_not = PhutilSearchQueryCompiler::OPERATOR_NOT;
$where = array(); $where = array();
$current_function = 'all';
foreach ($this->ferretTokens as $fulltext_token) { foreach ($this->ferretTokens as $fulltext_token) {
$raw_token = $fulltext_token->getToken(); $raw_token = $fulltext_token->getToken();
$value = $raw_token->getValue(); $value = $raw_token->getValue();
$function = $raw_token->getFunction();
if ($function === null) {
$function = $current_function;
}
$current_function = $function;
$table_alias = $table_map[$function]['alias'];
$is_not = ($raw_token->getOperator() == $op_not); $is_not = ($raw_token->getOperator() == $op_not);
if ($raw_token->getOperator() == $op_sub) { if ($raw_token->getOperator() == $op_sub) {
@ -1563,12 +1620,14 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
if ($is_not) { if ($is_not) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'(ftfield.rawCorpus NOT LIKE %~)', '(%T.rawCorpus NOT LIKE %~)',
$table_alias,
$value); $value);
} else { } else {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'(ftfield.rawCorpus LIKE %~)', '(%T.rawCorpus LIKE %~)',
$table_alias,
$value); $value);
} }
continue; continue;
@ -1596,12 +1655,14 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
if ($is_not) { if ($is_not) {
$term_constraints[] = qsprintf( $term_constraints[] = qsprintf(
$conn, $conn,
'(ftfield.termCorpus NOT LIKE %~)', '(%T.termCorpus NOT LIKE %~)',
$table_alias,
$term_value); $term_value);
} else { } else {
$term_constraints[] = qsprintf( $term_constraints[] = qsprintf(
$conn, $conn,
'(ftfield.termCorpus LIKE %~)', '(%T.termCorpus LIKE %~)',
$table_alias,
$term_value); $term_value);
} }
@ -1612,7 +1673,8 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$term_constraints[] = qsprintf( $term_constraints[] = qsprintf(
$conn, $conn,
'(ftfield.normalCorpus LIKE %~)', '(%T.normalCorpus LIKE %~)',
$table_alias,
$stem_value); $stem_value);
} }
@ -1624,7 +1686,8 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
} else if ($is_quoted) { } else if ($is_quoted) {
$where[] = qsprintf( $where[] = qsprintf(
$conn, $conn,
'(ftfield.rawCorpus LIKE %~ AND (%Q))', '(%T.rawCorpus LIKE %~ AND (%Q))',
$table_alias,
$value, $value,
implode(' OR ', $term_constraints)); implode(' OR ', $term_constraints));
} else { } else {