Give projects a proper on-demand datasource

Summary:
Fixes T5614. Ref T4420. Other than the "users" datasource and a couple of others, many datasources ignore what the user typed and just return all results, then rely on the client to filter them.

This works fine for rarely used ("legalpad documents") or always small ("task priorities", "applications") datasets, but is something we should graudally move away from as datasets get larger.

Add a token table to projects, populate it, and use it to drive the datasource query. Additionally, expose it on the applicationsearch UI.

Test Plan:
  - Ran migration.
  - Manually checked the table.
  - Searched for projects by name from ApplicationSearch.
  - Searched for projects by name from typeahead.
  - Manually checked the typeahead response.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5614, T4420

Differential Revision: https://secure.phabricator.com/D9896
This commit is contained in:
epriestley
2014-07-17 16:35:54 -07:00
parent f2fee5a84e
commit a115810912
9 changed files with 145 additions and 23 deletions

View File

@@ -9,6 +9,7 @@ final class PhabricatorProjectQuery
private $slugs;
private $phrictionSlugs;
private $names;
private $datasourceQuery;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
@@ -57,6 +58,11 @@ final class PhabricatorProjectQuery
return $this;
}
public function withDatasourceQuery($string) {
$this->datasourceQuery = $string;
return $this;
}
public function needMembers($need_members) {
$this->needMembers = $need_members;
return $this;
@@ -286,7 +292,7 @@ final class PhabricatorProjectQuery
}
private function buildGroupClause($conn_r) {
if ($this->memberPHIDs) {
if ($this->memberPHIDs || $this->datasourceQuery) {
return 'GROUP BY p.id';
} else {
return $this->buildApplicationSearchGroupClause($conn_r);
@@ -296,7 +302,7 @@ final class PhabricatorProjectQuery
private function buildJoinClause($conn_r) {
$joins = array();
if (!$this->needMembers) {
if (!$this->needMembers !== null) {
$joins[] = qsprintf(
$conn_r,
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
@@ -305,7 +311,7 @@ final class PhabricatorProjectQuery
$this->getViewer()->getPHID());
}
if ($this->memberPHIDs) {
if ($this->memberPHIDs !== null) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T e ON e.src = p.phid AND e.type = %d',
@@ -313,13 +319,32 @@ final class PhabricatorProjectQuery
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER);
}
if ($this->slugs) {
if ($this->slugs !== null) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T slug on slug.projectPHID = p.phid',
id(new PhabricatorProjectSlug())->getTableName());
}
if ($this->datasourceQuery !== null) {
$tokens = PhabricatorTypeaheadDatasource::tokenizeString(
$this->datasourceQuery);
if (!$tokens) {
throw new PhabricatorEmptyQueryException();
}
$likes = array();
foreach ($tokens as $token) {
$likes[] = qsprintf($conn_r, 'token.token LIKE %>', $token);
}
$joins[] = qsprintf(
$conn_r,
'JOIN %T token ON token.projectID = p.id AND (%Q)',
PhabricatorProject::TABLE_DATASOURCE_TOKEN,
'('.implode(') OR (', $likes).')');
}
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
return implode(' ', $joins);