Differential D18484 Diff 44406 src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
| Show All 21 Lines | abstract class PhabricatorCursorPagedPolicyAwareQuery | ||||
| private $orderVector; | private $orderVector; | ||||
| private $groupVector; | private $groupVector; | ||||
| private $builtinOrder; | private $builtinOrder; | ||||
| private $edgeLogicConstraints = array(); | private $edgeLogicConstraints = array(); | ||||
| private $edgeLogicConstraintsAreValid = false; | private $edgeLogicConstraintsAreValid = false; | ||||
| private $spacePHIDs; | private $spacePHIDs; | ||||
| private $spaceIsArchived; | private $spaceIsArchived; | ||||
| private $ngrams = array(); | private $ngrams = array(); | ||||
| private $ferretEngine; | |||||
| private $ferretConstraints; | |||||
| protected function getPageCursors(array $page) { | protected function getPageCursors(array $page) { | ||||
| return array( | return array( | ||||
| $this->getResultCursor(head($page)), | $this->getResultCursor(head($page)), | ||||
| $this->getResultCursor(last($page)), | $this->getResultCursor(last($page)), | ||||
| ); | ); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | /* -( Building Query Clauses )--------------------------------------------- */ | ||||
| /** | /** | ||||
| * @task clauses | * @task clauses | ||||
| */ | */ | ||||
| protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { | protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { | ||||
| $joins = array(); | $joins = array(); | ||||
| $joins[] = $this->buildEdgeLogicJoinClause($conn); | $joins[] = $this->buildEdgeLogicJoinClause($conn); | ||||
| $joins[] = $this->buildApplicationSearchJoinClause($conn); | $joins[] = $this->buildApplicationSearchJoinClause($conn); | ||||
| $joins[] = $this->buildNgramsJoinClause($conn); | $joins[] = $this->buildNgramsJoinClause($conn); | ||||
| $joins[] = $this->buildFerretJoinClause($conn); | |||||
| return $joins; | return $joins; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task clauses | * @task clauses | ||||
| */ | */ | ||||
| protected function buildWhereClause(AphrontDatabaseConnection $conn) { | protected function buildWhereClause(AphrontDatabaseConnection $conn) { | ||||
| $where = $this->buildWhereClauseParts($conn); | $where = $this->buildWhereClauseParts($conn); | ||||
| return $this->formatWhereClause($where); | return $this->formatWhereClause($where); | ||||
| } | } | ||||
| /** | /** | ||||
| * @task clauses | * @task clauses | ||||
| */ | */ | ||||
| protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { | protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { | ||||
| $where = array(); | $where = array(); | ||||
| $where[] = $this->buildPagingClause($conn); | $where[] = $this->buildPagingClause($conn); | ||||
| $where[] = $this->buildEdgeLogicWhereClause($conn); | $where[] = $this->buildEdgeLogicWhereClause($conn); | ||||
| $where[] = $this->buildSpacesWhereClause($conn); | $where[] = $this->buildSpacesWhereClause($conn); | ||||
| $where[] = $this->buildNgramsWhereClause($conn); | $where[] = $this->buildNgramsWhereClause($conn); | ||||
| $where[] = $this->buildFerretWhereClause($conn); | |||||
| return $where; | return $where; | ||||
| } | } | ||||
| /** | /** | ||||
| * @task clauses | * @task clauses | ||||
| */ | */ | ||||
| protected function buildHavingClause(AphrontDatabaseConnection $conn) { | protected function buildHavingClause(AphrontDatabaseConnection $conn) { | ||||
| Show All 38 Lines | protected function shouldGroupQueryResultRows() { | ||||
| if ($this->getApplicationSearchMayJoinMultipleRows()) { | if ($this->getApplicationSearchMayJoinMultipleRows()) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if ($this->shouldGroupNgramResultRows()) { | if ($this->shouldGroupNgramResultRows()) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if ($this->shouldGroupFerretResultRows()) { | |||||
| return true; | |||||
| } | |||||
| return false; | return false; | ||||
| } | } | ||||
| /* -( Paging )------------------------------------------------------------- */ | /* -( Paging )------------------------------------------------------------- */ | ||||
| ▲ Show 20 Lines • Show All 1,011 Lines • ▼ Show 20 Lines | /* -( Integration with CustomField )--------------------------------------- */ | ||||
| * @task customfield | * @task customfield | ||||
| */ | */ | ||||
| protected function isCustomFieldOrderKey($key) { | protected function isCustomFieldOrderKey($key) { | ||||
| $prefix = 'custom:'; | $prefix = 'custom:'; | ||||
| return !strncmp($key, $prefix, strlen($prefix)); | return !strncmp($key, $prefix, strlen($prefix)); | ||||
| } | } | ||||
| /* -( Ferret )------------------------------------------------------------- */ | |||||
| public function withFerretConstraint( | |||||
| PhabricatorFerretEngine $engine, | |||||
| $raw_query) { | |||||
| if ($this->ferretEngine) { | |||||
| throw new Exception( | |||||
| pht( | |||||
| 'Query may not have multiple fulltext constraints.')); | |||||
| } | |||||
| if (!strlen($raw_query)) { | |||||
| return $this; | |||||
| } | |||||
| $this->ferretEngine = $engine; | |||||
| $this->ferretConstraints = preg_split('/\s+/', $raw_query); | |||||
| return $this; | |||||
| } | |||||
| protected function buildFerretJoinClause(AphrontDatabaseConnection $conn) { | |||||
| if (!$this->ferretEngine) { | |||||
| return array(); | |||||
| } | |||||
| $engine = $this->ferretEngine; | |||||
| $ngram_engine = new PhabricatorNgramEngine(); | |||||
| $ngram_table = $engine->newNgramsObject(); | |||||
| $ngram_table_name = $ngram_table->getTableName(); | |||||
| $flat = array(); | |||||
| foreach ($this->ferretConstraints as $term) { | |||||
| $value = $term; | |||||
| $length = count(phutil_utf8v($term)); | |||||
| if ($length >= 3) { | |||||
| $ngrams = $ngram_engine->getNgramsFromString($value, 'query'); | |||||
| $prefix = false; | |||||
| } else if ($length == 2) { | |||||
| $ngrams = $ngram_engine->getNgramsFromString($value, 'prefix'); | |||||
| $prefix = false; | |||||
| } else { | |||||
| $ngrams = array(' '.$value); | |||||
| $prefix = true; | |||||
| } | |||||
| foreach ($ngrams as $ngram) { | |||||
| $flat[] = array( | |||||
| 'table' => $ngram_table_name, | |||||
| 'ngram' => $ngram, | |||||
| 'prefix' => $prefix, | |||||
| ); | |||||
| } | |||||
| } | |||||
| // MySQL only allows us to join a maximum of 61 tables per query. Each | |||||
| // ngram is going to cost us a join toward that limit, so if the user | |||||
| // specified a very long query string, just pick 16 of the ngrams | |||||
| // at random. | |||||
| if (count($flat) > 16) { | |||||
| shuffle($flat); | |||||
| $flat = array_slice($flat, 0, 16); | |||||
| } | |||||
| $alias = $this->getPrimaryTableAlias(); | |||||
| if ($alias) { | |||||
| $phid_column = qsprintf($conn, '%T.%T', $alias, 'phid'); | |||||
| } else { | |||||
| $phid_column = qsprintf($conn, '%T', 'phid'); | |||||
| } | |||||
| $document_table = $engine->newDocumentObject(); | |||||
| $field_table = $engine->newFieldObject(); | |||||
| $joins = array(); | |||||
| $joins[] = qsprintf( | |||||
| $conn, | |||||
| 'JOIN %T ftdoc ON ftdoc.objectPHID = %Q', | |||||
| $document_table->getTableName(), | |||||
| $phid_column); | |||||
| $idx = 1; | |||||
| foreach ($flat as $spec) { | |||||
| $table = $spec['table']; | |||||
| $ngram = $spec['ngram']; | |||||
| $prefix = $spec['prefix']; | |||||
| $alias = 'ft'.$idx++; | |||||
| if ($prefix) { | |||||
| $joins[] = qsprintf( | |||||
| $conn, | |||||
| 'JOIN %T %T ON %T.documentID = ftdoc.id AND %T.ngram LIKE %>', | |||||
| $table, | |||||
| $alias, | |||||
| $alias, | |||||
| $alias, | |||||
| $ngram); | |||||
| } else { | |||||
| $joins[] = qsprintf( | |||||
| $conn, | |||||
| 'JOIN %T %T ON %T.documentID = ftdoc.id AND %T.ngram = %s', | |||||
| $table, | |||||
| $alias, | |||||
| $alias, | |||||
| $alias, | |||||
| $ngram); | |||||
| } | |||||
| } | |||||
| $joins[] = qsprintf( | |||||
| $conn, | |||||
| 'JOIN %T ftfield ON ftdoc.id = ftfield.documentID', | |||||
| $field_table->getTableName()); | |||||
| return $joins; | |||||
| } | |||||
| protected function buildFerretWhereClause(AphrontDatabaseConnection $conn) { | |||||
| if (!$this->ferretEngine) { | |||||
| return array(); | |||||
| } | |||||
| $where = array(); | |||||
| foreach ($this->ferretConstraints as $constraint) { | |||||
| $where[] = qsprintf( | |||||
| $conn, | |||||
| '(ftfield.rawCorpus LIKE %~ OR ftfield.normalCorpus LIKE %~)', | |||||
| $constraint, | |||||
| $constraint); | |||||
| } | |||||
| return $where; | |||||
| } | |||||
| protected function shouldGroupFerretResultRows() { | |||||
| return (bool)$this->ferretConstraints; | |||||
| } | |||||
| /* -( Ngrams )------------------------------------------------------------- */ | /* -( Ngrams )------------------------------------------------------------- */ | ||||
| protected function withNgramsConstraint( | protected function withNgramsConstraint( | ||||
| PhabricatorSearchNgrams $index, | PhabricatorSearchNgrams $index, | ||||
| $value) { | $value) { | ||||
| if (strlen($value)) { | if (strlen($value)) { | ||||
| ▲ Show 20 Lines • Show All 744 Lines • Show Last 20 Lines | |||||