1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 19:40:55 +01:00

Allow Almanac devices to be queried and sorted by name

Summary:
Ref T10205. Ref T10246. This is general modernization, but also supports fixing the interface datasource in T10205.

  - Update Query.
  - Update SearchEngine.
  - Use an ngrams index for searching names efficiently.

Test Plan:
  - Ran migrations.
  - Searched Almanac devices by name.
  - Created a new device, searched for it by name.

{F1121303}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10205, T10246

Differential Revision: https://secure.phabricator.com/D15319
This commit is contained in:
epriestley 2016-02-21 02:48:10 -08:00
parent a4db6f387d
commit 1b6ddae6b2
9 changed files with 133 additions and 46 deletions

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_almanac.almanac_devicename_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 AlmanacDevice();
foreach (new LiskMigrationIterator($table) as $device) {
PhabricatorSearchWorker::queueDocumentForIndexing(
$device->getPHID(),
array(
'force' => true,
));
}

View file

@ -38,6 +38,7 @@ phutil_register_library_map(array(
'AlmanacDeviceEditController' => 'applications/almanac/controller/AlmanacDeviceEditController.php', 'AlmanacDeviceEditController' => 'applications/almanac/controller/AlmanacDeviceEditController.php',
'AlmanacDeviceEditor' => 'applications/almanac/editor/AlmanacDeviceEditor.php', 'AlmanacDeviceEditor' => 'applications/almanac/editor/AlmanacDeviceEditor.php',
'AlmanacDeviceListController' => 'applications/almanac/controller/AlmanacDeviceListController.php', 'AlmanacDeviceListController' => 'applications/almanac/controller/AlmanacDeviceListController.php',
'AlmanacDeviceNameNgrams' => 'applications/almanac/storage/AlmanacDeviceNameNgrams.php',
'AlmanacDevicePHIDType' => 'applications/almanac/phid/AlmanacDevicePHIDType.php', 'AlmanacDevicePHIDType' => 'applications/almanac/phid/AlmanacDevicePHIDType.php',
'AlmanacDeviceQuery' => 'applications/almanac/query/AlmanacDeviceQuery.php', 'AlmanacDeviceQuery' => 'applications/almanac/query/AlmanacDeviceQuery.php',
'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php', 'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php',
@ -4011,11 +4012,13 @@ phutil_register_library_map(array(
'PhabricatorSSHPublicKeyInterface', 'PhabricatorSSHPublicKeyInterface',
'AlmanacPropertyInterface', 'AlmanacPropertyInterface',
'PhabricatorDestructibleInterface', 'PhabricatorDestructibleInterface',
'PhabricatorNgramsInterface',
), ),
'AlmanacDeviceController' => 'AlmanacController', 'AlmanacDeviceController' => 'AlmanacController',
'AlmanacDeviceEditController' => 'AlmanacDeviceController', 'AlmanacDeviceEditController' => 'AlmanacDeviceController',
'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor',
'AlmanacDeviceListController' => 'AlmanacDeviceController', 'AlmanacDeviceListController' => 'AlmanacDeviceController',
'AlmanacDeviceNameNgrams' => 'PhabricatorSearchNgrams',
'AlmanacDevicePHIDType' => 'PhabricatorPHIDType', 'AlmanacDevicePHIDType' => 'PhabricatorPHIDType',
'AlmanacDeviceQuery' => 'AlmanacQuery', 'AlmanacDeviceQuery' => 'AlmanacQuery',
'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine',

View file

@ -17,6 +17,9 @@ final class AlmanacCoreCustomField
} }
public function createFields($object) { public function createFields($object) {
if (!$object->getID()) {
return array();
}
$specs = $object->getAlmanacPropertyFieldSpecifications(); $specs = $object->getAlmanacPropertyFieldSpecifications();

View file

@ -11,6 +11,10 @@ final class AlmanacDeviceEditor
return pht('Almanac Device'); return pht('Almanac Device');
} }
protected function supportsSearch() {
return true;
}
public function getTransactionTypes() { public function getTransactionTypes() {
$types = parent::getTransactionTypes(); $types = parent::getTransactionTypes();
@ -303,6 +307,4 @@ final class AlmanacDeviceEditor
return $errors; return $errors;
} }
} }

View file

@ -34,35 +34,34 @@ final class AlmanacDeviceQuery
return $this; return $this;
} }
protected function loadPage() { public function withNameNgrams($ngrams) {
$table = new AlmanacDevice(); return $this->withNgramsConstraint(
$conn_r = $table->establishConnection('r'); new AlmanacDeviceNameNgrams(),
$ngrams);
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
} }
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { public function newResultObject() {
$where = array(); return new AlmanacDevice();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) { if ($this->ids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'id IN (%Ld)', 'device.id IN (%Ld)',
$this->ids); $this->ids);
} }
if ($this->phids !== null) { if ($this->phids !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'phid IN (%Ls)', 'device.phid IN (%Ls)',
$this->phids); $this->phids);
} }
@ -72,28 +71,59 @@ final class AlmanacDeviceQuery
$hashes[] = PhabricatorHash::digestForIndex($name); $hashes[] = PhabricatorHash::digestForIndex($name);
} }
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'nameIndex IN (%Ls)', 'device.nameIndex IN (%Ls)',
$hashes); $hashes);
} }
if ($this->namePrefix !== null) { if ($this->namePrefix !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'name LIKE %>', 'device.name LIKE %>',
$this->namePrefix); $this->namePrefix);
} }
if ($this->nameSuffix !== null) { if ($this->nameSuffix !== null) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn,
'name LIKE %<', 'device.name LIKE %<',
$this->nameSuffix); $this->nameSuffix);
} }
$where[] = $this->buildPagingClause($conn_r); return $where;
}
return $this->formatWhereClause($where); protected function getPrimaryTableAlias() {
return 'device';
}
public function getOrderableColumns() {
return parent::getOrderableColumns() + array(
'name' => array(
'table' => $this->getPrimaryTableAlias(),
'column' => 'name',
'type' => 'string',
'unique' => true,
'reverse' => true,
),
);
}
protected function getPagingValueMap($cursor, array $keys) {
$device = $this->loadCursorObject($cursor);
return array(
'id' => $device->getID(),
'name' => $device->getName(),
);
}
public function getBuiltinOrders() {
return array(
'name' => array(
'vector' => array('name'),
'name' => pht('Device Name'),
),
) + parent::getBuiltinOrders();
} }
public function getQueryApplicationClass() { public function getQueryApplicationClass() {

View file

@ -11,22 +11,29 @@ final class AlmanacDeviceSearchEngine
return 'PhabricatorAlmanacApplication'; return 'PhabricatorAlmanacApplication';
} }
public function buildSavedQueryFromRequest(AphrontRequest $request) { public function newQuery() {
$saved = new PhabricatorSavedQuery(); return new AlmanacDeviceQuery();
return $saved;
} }
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { protected function buildCustomSearchFields() {
$query = id(new AlmanacDeviceQuery()); return array(
id(new PhabricatorSearchTextField())
->setLabel(pht('Name Contains'))
->setKey('match')
->setDescription(pht('Search for devices by name substring.')),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['match'] !== null) {
$query->withNameNgrams($map['match']);
}
return $query; return $query;
} }
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {}
protected function getURI($path) { protected function getURI($path) {
return '/almanac/device/'.$path; return '/almanac/device/'.$path;
} }
@ -52,12 +59,6 @@ final class AlmanacDeviceSearchEngine
return parent::buildSavedQueryFromBuiltin($query_key); return parent::buildSavedQueryFromBuiltin($query_key);
} }
protected function getRequiredHandlePHIDsForResultList(
array $devices,
PhabricatorSavedQuery $query) {
return array();
}
protected function renderResultList( protected function renderResultList(
array $devices, array $devices,
PhabricatorSavedQuery $query, PhabricatorSavedQuery $query,

View file

@ -9,7 +9,8 @@ final class AlmanacDevice
PhabricatorProjectInterface, PhabricatorProjectInterface,
PhabricatorSSHPublicKeyInterface, PhabricatorSSHPublicKeyInterface,
AlmanacPropertyInterface, AlmanacPropertyInterface,
PhabricatorDestructibleInterface { PhabricatorDestructibleInterface,
PhabricatorNgramsInterface {
protected $name; protected $name;
protected $nameIndex; protected $nameIndex;
@ -250,4 +251,15 @@ final class AlmanacDevice
$this->delete(); $this->delete();
} }
/* -( PhabricatorNgramInterface )------------------------------------------ */
public function newNgrams() {
return array(
id(new AlmanacDeviceNameNgrams())
->setValue($this->getName()),
);
}
} }

View file

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