1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 00:32:42 +01:00

Add a name token table so on-demand typeaheads can match last names

Summary: See T585. We currently don't match middle/last/nth names in on-demand
tokenizers. Build a table so we can match them.

Test Plan:
Ran upgrade script, verified table looks sensible. Searched for "priestley" in a
tokenizer, got a bunch of test account hits.

  mysql> select * from user_nametoken;
  +-------------------+--------+
  | token             | userID |
  +-------------------+--------+
  | evan              |      1 |
  | priestley         |      1 |
  | epriestley        |      1 |
  | epriestley2       |      2 |
  | ducks             |      4 |
  | epriestley3       |      4 |
  | asdf              |      6 |
  | epriestley99      |      6 |
  ...

Reviewers: bh, nh, jungejason, tuomaspelkonen, aran

Reviewed By: aran

CC: aran

Differential Revision: 1034
This commit is contained in:
epriestley 2011-10-23 13:25:52 -07:00
parent 4156cf6bd9
commit ddce177d81
6 changed files with 103 additions and 5 deletions

View file

@ -0,0 +1,6 @@
CREATE TABLE phabricator_user.user_nametoken (
token VARCHAR(255) NOT NULL,
userID INT UNSIGNED NOT NULL,
KEY (token),
key (userID)
) ENGINE=InnoDB;

View file

@ -0,0 +1,30 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
$conn = $schema_conn;
echo "Indexing username tokens for typeaheads...\n";
$users = id(new PhabricatorUser())->loadAll();
echo count($users)." users to index";
foreach ($users as $user) {
$user->updateNameTokens();
echo ".";
}
echo "\nDone.\n";

View file

@ -19,6 +19,7 @@
class PhabricatorUser extends PhabricatorUserDAO {
const SESSION_TABLE = 'phabricator_session';
const NAMETOKEN_TABLE = 'user_nametoken';
protected $phid;
protected $userName;
@ -91,6 +92,7 @@ class PhabricatorUser extends PhabricatorUserDAO {
}
$result = parent::save();
$this->updateNameTokens();
PhabricatorSearchUserIndexer::indexUser($this);
return $result;
@ -349,4 +351,53 @@ class PhabricatorUser extends PhabricatorUserDAO {
return $preferences;
}
private static function tokenizeName($name) {
if (function_exists('mb_strtolower')) {
$name = mb_strtolower($name, 'UTF-8');
} else {
$name = strtolower($name);
}
$name = trim($name);
if (!strlen($name)) {
return array();
}
return preg_split('/\s+/', $name);
}
/**
* Populate the nametoken table, which used to fetch typeahead results. When
* a user types "linc", we want to match "Abraham Lincoln" from on-demand
* typeahead sources. To do this, we need a separate table of name fragments.
*/
public function updateNameTokens() {
$tokens = array_merge(
self::tokenizeName($this->getRealName()),
self::tokenizeName($this->getUserName()));
$tokens = array_unique($tokens);
$table = self::NAMETOKEN_TABLE;
$conn_w = $this->establishConnection('w');
$sql = array();
foreach ($tokens as $token) {
$sql[] = qsprintf(
$conn_w,
'(%d, %s)',
$this->getID(),
$token);
}
queryfx(
$conn_w,
'DELETE FROM %T WHERE userID = %d',
$table,
$this->getID());
if ($sql) {
queryfx(
$conn_w,
'INSERT INTO %T (userID, token) VALUES %Q',
$table,
implode(', ', $sql));
}
}
}

View file

@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'applications/search/index/indexer/user');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'storage/qsprintf');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phutil', 'filesystem');

View file

@ -85,12 +85,21 @@ class PhabricatorTypeaheadCommonDatasourceController
'realName',
'phid');
if ($query) {
// TODO: We probably need to split last names here. Workaround until
// we get that up and running is to not enable server-side datasources.
$users = id(new PhabricatorUser())->loadColumnsWhere($columns,
'(userName LIKE %> OR realName LIKE %>)',
$query,
$conn_r = id(new PhabricatorUser())->establishConnection('r');
$ids = queryfx_all(
$conn_r,
'SELECT DISTINCT userID FROM %T WHERE token LIKE %>',
PhabricatorUser::NAMETOKEN_TABLE,
$query);
$ids = ipull($ids, 'userID');
if ($ids) {
$users = id(new PhabricatorUser())->loadColumnsWhere(
$columns,
'id IN (%Ld)',
$ids);
} else {
$users = array();
}
} else {
$users = id(new PhabricatorUser())->loadColumns($columns);
}

View file

@ -15,6 +15,7 @@ phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'applications/repository/storage/arcanistproject');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'applications/typeahead/controller/base');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phutil', 'utils');