From 1b6ddae6b2d8a28c45575dddd2e39b26ba055981 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 21 Feb 2016 02:48:10 -0800 Subject: [PATCH] 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 --- .../20160221.almanac.1.devicen.sql | 7 ++ .../20160221.almanac.2.devicei.php | 11 +++ src/__phutil_library_map__.php | 3 + .../customfield/AlmanacCoreCustomField.php | 3 + .../almanac/editor/AlmanacDeviceEditor.php | 6 +- .../almanac/query/AlmanacDeviceQuery.php | 84 +++++++++++++------ .../query/AlmanacDeviceSearchEngine.php | 33 ++++---- .../almanac/storage/AlmanacDevice.php | 14 +++- .../storage/AlmanacDeviceNameNgrams.php | 18 ++++ 9 files changed, 133 insertions(+), 46 deletions(-) create mode 100644 resources/sql/autopatches/20160221.almanac.1.devicen.sql create mode 100644 resources/sql/autopatches/20160221.almanac.2.devicei.php create mode 100644 src/applications/almanac/storage/AlmanacDeviceNameNgrams.php diff --git a/resources/sql/autopatches/20160221.almanac.1.devicen.sql b/resources/sql/autopatches/20160221.almanac.1.devicen.sql new file mode 100644 index 0000000000..c098173f25 --- /dev/null +++ b/resources/sql/autopatches/20160221.almanac.1.devicen.sql @@ -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}; diff --git a/resources/sql/autopatches/20160221.almanac.2.devicei.php b/resources/sql/autopatches/20160221.almanac.2.devicei.php new file mode 100644 index 0000000000..aea17d0ad6 --- /dev/null +++ b/resources/sql/autopatches/20160221.almanac.2.devicei.php @@ -0,0 +1,11 @@ +getPHID(), + array( + 'force' => true, + )); +} diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ae699acf07..2a175303fe 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -38,6 +38,7 @@ phutil_register_library_map(array( 'AlmanacDeviceEditController' => 'applications/almanac/controller/AlmanacDeviceEditController.php', 'AlmanacDeviceEditor' => 'applications/almanac/editor/AlmanacDeviceEditor.php', 'AlmanacDeviceListController' => 'applications/almanac/controller/AlmanacDeviceListController.php', + 'AlmanacDeviceNameNgrams' => 'applications/almanac/storage/AlmanacDeviceNameNgrams.php', 'AlmanacDevicePHIDType' => 'applications/almanac/phid/AlmanacDevicePHIDType.php', 'AlmanacDeviceQuery' => 'applications/almanac/query/AlmanacDeviceQuery.php', 'AlmanacDeviceSearchEngine' => 'applications/almanac/query/AlmanacDeviceSearchEngine.php', @@ -4011,11 +4012,13 @@ phutil_register_library_map(array( 'PhabricatorSSHPublicKeyInterface', 'AlmanacPropertyInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorNgramsInterface', ), 'AlmanacDeviceController' => 'AlmanacController', 'AlmanacDeviceEditController' => 'AlmanacDeviceController', 'AlmanacDeviceEditor' => 'PhabricatorApplicationTransactionEditor', 'AlmanacDeviceListController' => 'AlmanacDeviceController', + 'AlmanacDeviceNameNgrams' => 'PhabricatorSearchNgrams', 'AlmanacDevicePHIDType' => 'PhabricatorPHIDType', 'AlmanacDeviceQuery' => 'AlmanacQuery', 'AlmanacDeviceSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/almanac/customfield/AlmanacCoreCustomField.php b/src/applications/almanac/customfield/AlmanacCoreCustomField.php index c1df52321f..91560f14e6 100644 --- a/src/applications/almanac/customfield/AlmanacCoreCustomField.php +++ b/src/applications/almanac/customfield/AlmanacCoreCustomField.php @@ -17,6 +17,9 @@ final class AlmanacCoreCustomField } public function createFields($object) { + if (!$object->getID()) { + return array(); + } $specs = $object->getAlmanacPropertyFieldSpecifications(); diff --git a/src/applications/almanac/editor/AlmanacDeviceEditor.php b/src/applications/almanac/editor/AlmanacDeviceEditor.php index 3f7817bccc..25d49fb295 100644 --- a/src/applications/almanac/editor/AlmanacDeviceEditor.php +++ b/src/applications/almanac/editor/AlmanacDeviceEditor.php @@ -11,6 +11,10 @@ final class AlmanacDeviceEditor return pht('Almanac Device'); } + protected function supportsSearch() { + return true; + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); @@ -303,6 +307,4 @@ final class AlmanacDeviceEditor return $errors; } - - } diff --git a/src/applications/almanac/query/AlmanacDeviceQuery.php b/src/applications/almanac/query/AlmanacDeviceQuery.php index 287af6c647..29461bfbfd 100644 --- a/src/applications/almanac/query/AlmanacDeviceQuery.php +++ b/src/applications/almanac/query/AlmanacDeviceQuery.php @@ -34,35 +34,34 @@ final class AlmanacDeviceQuery return $this; } - protected function loadPage() { - $table = new AlmanacDevice(); - $conn_r = $table->establishConnection('r'); - - $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); + public function withNameNgrams($ngrams) { + return $this->withNgramsConstraint( + new AlmanacDeviceNameNgrams(), + $ngrams); } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + public function newResultObject() { + return new AlmanacDevice(); + } + + protected function loadPage() { + return $this->loadStandardPage($this->newResultObject()); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, - 'id IN (%Ld)', + $conn, + 'device.id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, - 'phid IN (%Ls)', + $conn, + 'device.phid IN (%Ls)', $this->phids); } @@ -72,28 +71,59 @@ final class AlmanacDeviceQuery $hashes[] = PhabricatorHash::digestForIndex($name); } $where[] = qsprintf( - $conn_r, - 'nameIndex IN (%Ls)', + $conn, + 'device.nameIndex IN (%Ls)', $hashes); } if ($this->namePrefix !== null) { $where[] = qsprintf( - $conn_r, - 'name LIKE %>', + $conn, + 'device.name LIKE %>', $this->namePrefix); } if ($this->nameSuffix !== null) { $where[] = qsprintf( - $conn_r, - 'name LIKE %<', + $conn, + 'device.name LIKE %<', $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() { diff --git a/src/applications/almanac/query/AlmanacDeviceSearchEngine.php b/src/applications/almanac/query/AlmanacDeviceSearchEngine.php index 99e960425c..d9e13fba33 100644 --- a/src/applications/almanac/query/AlmanacDeviceSearchEngine.php +++ b/src/applications/almanac/query/AlmanacDeviceSearchEngine.php @@ -11,22 +11,29 @@ final class AlmanacDeviceSearchEngine return 'PhabricatorAlmanacApplication'; } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - return $saved; + public function newQuery() { + return new AlmanacDeviceQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new AlmanacDeviceQuery()); + protected function buildCustomSearchFields() { + 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; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) {} - protected function getURI($path) { return '/almanac/device/'.$path; } @@ -52,12 +59,6 @@ final class AlmanacDeviceSearchEngine return parent::buildSavedQueryFromBuiltin($query_key); } - protected function getRequiredHandlePHIDsForResultList( - array $devices, - PhabricatorSavedQuery $query) { - return array(); - } - protected function renderResultList( array $devices, PhabricatorSavedQuery $query, diff --git a/src/applications/almanac/storage/AlmanacDevice.php b/src/applications/almanac/storage/AlmanacDevice.php index d0994174b3..09503a31b6 100644 --- a/src/applications/almanac/storage/AlmanacDevice.php +++ b/src/applications/almanac/storage/AlmanacDevice.php @@ -9,7 +9,8 @@ final class AlmanacDevice PhabricatorProjectInterface, PhabricatorSSHPublicKeyInterface, AlmanacPropertyInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorNgramsInterface { protected $name; protected $nameIndex; @@ -250,4 +251,15 @@ final class AlmanacDevice $this->delete(); } + +/* -( PhabricatorNgramInterface )------------------------------------------ */ + + + public function newNgrams() { + return array( + id(new AlmanacDeviceNameNgrams()) + ->setValue($this->getName()), + ); + } + } diff --git a/src/applications/almanac/storage/AlmanacDeviceNameNgrams.php b/src/applications/almanac/storage/AlmanacDeviceNameNgrams.php new file mode 100644 index 0000000000..a0ca1e2810 --- /dev/null +++ b/src/applications/almanac/storage/AlmanacDeviceNameNgrams.php @@ -0,0 +1,18 @@ +