1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 05:50:55 +01:00

Allow Almanac services to be searched by substring

Summary: Ref T10246. Build an ngram index for Almanac services, and use it to support improved search.

Test Plan: {F1121725}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10246

Differential Revision: https://secure.phabricator.com/D15321
This commit is contained in:
epriestley 2016-02-21 10:52:19 -08:00
parent 31927476e3
commit 959bb16d0f
8 changed files with 86 additions and 7 deletions

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_almanac.almanac_servicename_ngrams (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectID INT UNSIGNED NOT NULL,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
KEY `key_object` (objectID),
KEY `key_ngram` (ngram, objectID)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,11 @@
<?php
$table = new AlmanacService();
foreach (new LiskMigrationIterator($table) as $service) {
PhabricatorSearchWorker::queueDocumentForIndexing(
$service->getPHID(),
array(
'force' => true,
));
}

View file

@ -89,6 +89,7 @@ phutil_register_library_map(array(
'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php', 'AlmanacServiceEditController' => 'applications/almanac/controller/AlmanacServiceEditController.php',
'AlmanacServiceEditor' => 'applications/almanac/editor/AlmanacServiceEditor.php', 'AlmanacServiceEditor' => 'applications/almanac/editor/AlmanacServiceEditor.php',
'AlmanacServiceListController' => 'applications/almanac/controller/AlmanacServiceListController.php', 'AlmanacServiceListController' => 'applications/almanac/controller/AlmanacServiceListController.php',
'AlmanacServiceNameNgrams' => 'applications/almanac/storage/AlmanacServiceNameNgrams.php',
'AlmanacServicePHIDType' => 'applications/almanac/phid/AlmanacServicePHIDType.php', 'AlmanacServicePHIDType' => 'applications/almanac/phid/AlmanacServicePHIDType.php',
'AlmanacServiceQuery' => 'applications/almanac/query/AlmanacServiceQuery.php', 'AlmanacServiceQuery' => 'applications/almanac/query/AlmanacServiceQuery.php',
'AlmanacServiceSearchEngine' => 'applications/almanac/query/AlmanacServiceSearchEngine.php', 'AlmanacServiceSearchEngine' => 'applications/almanac/query/AlmanacServiceSearchEngine.php',
@ -4082,12 +4083,14 @@ phutil_register_library_map(array(
'PhabricatorProjectInterface', 'PhabricatorProjectInterface',
'AlmanacPropertyInterface', 'AlmanacPropertyInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
'PhabricatorNgramsInterface',
), ),
'AlmanacServiceController' => 'AlmanacController', 'AlmanacServiceController' => 'AlmanacController',
'AlmanacServiceDatasource' => 'PhabricatorTypeaheadDatasource', 'AlmanacServiceDatasource' => 'PhabricatorTypeaheadDatasource',
'AlmanacServiceEditController' => 'AlmanacServiceController', 'AlmanacServiceEditController' => 'AlmanacServiceController',
'AlmanacServiceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacServiceEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacServiceListController' => 'AlmanacServiceController', 'AlmanacServiceListController' => 'AlmanacServiceController',
'AlmanacServiceNameNgrams' => 'PhabricatorSearchNgrams',
'AlmanacServicePHIDType' => 'PhabricatorPHIDType', 'AlmanacServicePHIDType' => 'PhabricatorPHIDType',
'AlmanacServiceQuery' => 'AlmanacQuery', 'AlmanacServiceQuery' => 'AlmanacQuery',
'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacServiceSearchEngine' => 'PhabricatorApplicationSearchEngine',

View file

@ -11,6 +11,10 @@ final class AlmanacServiceEditor
return pht('Almanac Service'); return pht('Almanac Service');
} }
protected function supportsSearch() {
return true;
}
public function getTransactionTypes() { public function getTransactionTypes() {
$types = parent::getTransactionTypes(); $types = parent::getTransactionTypes();

View file

@ -54,6 +54,12 @@ final class AlmanacServiceQuery
return $this; return $this;
} }
public function withNameNgrams($ngrams) {
return $this->withNgramsConstraint(
new AlmanacServiceNameNgrams(),
$ngrams);
}
public function needBindings($need_bindings) { public function needBindings($need_bindings) {
$this->needBindings = $need_bindings; $this->needBindings = $need_bindings;
return $this; return $this;
@ -66,7 +72,7 @@ final class AlmanacServiceQuery
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn); $joins = parent::buildJoinClauseParts($conn);
if ($this->devicePHIDs !== null) { if ($this->shouldJoinBindingTable()) {
$joins[] = qsprintf( $joins[] = qsprintf(
$conn, $conn,
'JOIN %T binding ON service.phid = binding.servicePHID', 'JOIN %T binding ON service.phid = binding.servicePHID',
@ -178,6 +184,18 @@ final class AlmanacServiceQuery
return parent::didFilterPage($services); return parent::didFilterPage($services);
} }
private function shouldJoinBindingTable() {
return ($this->devicePHIDs !== null);
}
protected function shouldGroupQueryResultRows() {
if ($this->shouldJoinBindingTable()) {
return true;
}
return parent::shouldGroupQueryResultRows();
}
protected function getPrimaryTableAlias() { protected function getPrimaryTableAlias() {
return 'service'; return 'service';
} }

View file

@ -16,21 +16,27 @@ final class AlmanacServiceSearchEngine
} }
public function newResultObject() { public function newResultObject() {
// NOTE: We need to attach a service type in order to generate custom return AlmanacService::initializeNewService();
// field definitions.
return AlmanacService::initializeNewService()
->attachServiceType(new AlmanacCustomServiceType());
} }
protected function buildQueryFromParameters(array $map) { protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery(); $query = $this->newQuery();
if ($map['match'] !== null) {
$query->withNameNgrams($map['match']);
}
return $query; return $query;
} }
protected function buildCustomSearchFields() { protected function buildCustomSearchFields() {
return array(); return array(
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('match')
->setDescription(pht('Search for services by name substring.')),
);
} }
protected function getURI($path) { protected function getURI($path) {

View file

@ -8,7 +8,8 @@ final class AlmanacService
PhabricatorApplicationTransactionInterface, PhabricatorApplicationTransactionInterface,
PhabricatorProjectInterface, PhabricatorProjectInterface,
AlmanacPropertyInterface, AlmanacPropertyInterface,
PhabricatorDestructibleInterface { PhabricatorDestructibleInterface,
PhabricatorNgramsInterface {
protected $name; protected $name;
protected $nameIndex; protected $nameIndex;
@ -231,4 +232,15 @@ final class AlmanacService
$this->delete(); $this->delete();
} }
/* -( PhabricatorNgramInterface )------------------------------------------ */
public function newNgrams() {
return array(
id(new AlmanacServiceNameNgrams())
->setValue($this->getName()),
);
}
} }

View file

@ -0,0 +1,18 @@
<?php
final class AlmanacServiceNameNgrams
extends PhabricatorSearchNgrams {
public function getNgramKey() {
return 'servicename';
}
public function getColumnName() {
return 'name';
}
public function getApplicationName() {
return 'almanac';
}
}