Use fuse.js for regular contact search

This commit is contained in:
Fedor Indutny 2022-04-07 11:47:12 -07:00 committed by GitHub
parent 085a698a73
commit e1e1cfb892
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 26 additions and 50 deletions

View file

@ -207,7 +207,6 @@ const dataInterface: ClientInterface = {
getAllConversationIds, getAllConversationIds,
getAllGroupsInvolvingUuid, getAllGroupsInvolvingUuid,
searchConversations,
searchMessages, searchMessages,
searchMessagesInConversation, searchMessagesInConversation,
@ -1031,12 +1030,6 @@ async function getAllGroupsInvolvingUuid(uuid: UUIDStringType) {
return channels.getAllGroupsInvolvingUuid(uuid); return channels.getAllGroupsInvolvingUuid(uuid);
} }
async function searchConversations(query: string) {
const conversations = await channels.searchConversations(query);
return conversations;
}
function handleSearchMessageJSON( function handleSearchMessageJSON(
messages: Array<ServerSearchResultMessageType> messages: Array<ServerSearchResultMessageType>
): Array<ClientSearchResultMessageType> { ): Array<ClientSearchResultMessageType> {

View file

@ -363,10 +363,6 @@ export type DataInterface = {
id: UUIDStringType id: UUIDStringType
) => Promise<Array<ConversationType>>; ) => Promise<Array<ConversationType>>;
searchConversations: (
query: string,
options?: { limit?: number }
) => Promise<Array<ConversationType>>;
// searchMessages is JSON on server, full message on Client // searchMessages is JSON on server, full message on Client
// searchMessagesInConversation is JSON on server, full message on Client // searchMessagesInConversation is JSON on server, full message on Client

View file

@ -203,7 +203,6 @@ const dataInterface: ServerInterface = {
getAllConversationIds, getAllConversationIds,
getAllGroupsInvolvingUuid, getAllGroupsInvolvingUuid,
searchConversations,
searchMessages, searchMessages,
searchMessagesInConversation, searchMessagesInConversation,
@ -1526,33 +1525,6 @@ async function getAllGroupsInvolvingUuid(
return rows.map(row => rowToConversation(row)); return rows.map(row => rowToConversation(row));
} }
async function searchConversations(
query: string,
{ limit }: { limit?: number } = {}
): Promise<Array<ConversationType>> {
const db = getInstance();
const rows: ConversationRows = db
.prepare<Query>(
`
SELECT json, profileLastFetchedAt
FROM conversations WHERE
(
e164 LIKE $query OR
name LIKE $query OR
profileFullName LIKE $query
)
ORDER BY active_at DESC
LIMIT $limit
`
)
.all({
query: `%${query}%`,
limit: limit || 100,
});
return rows.map(row => rowToConversation(row));
}
async function searchMessages( async function searchMessages(
query: string, query: string,
params: { limit?: number; conversationId?: string } = {} params: { limit?: number; conversationId?: string } = {}

View file

@ -6,6 +6,7 @@ import { debounce, omit, reject } from 'lodash';
import type { StateType as RootStateType } from '../reducer'; import type { StateType as RootStateType } from '../reducer';
import { cleanSearchTerm } from '../../util/cleanSearchTerm'; import { cleanSearchTerm } from '../../util/cleanSearchTerm';
import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations';
import type { import type {
ClientSearchResultMessageType, ClientSearchResultMessageType,
ClientInterface, ClientInterface,
@ -14,8 +15,8 @@ import dataInterface from '../../sql/Client';
import { makeLookup } from '../../util/makeLookup'; import { makeLookup } from '../../util/makeLookup';
import type { import type {
ConversationType,
ConversationUnloadedActionType, ConversationUnloadedActionType,
DBConversationType,
MessageDeletedActionType, MessageDeletedActionType,
MessageType, MessageType,
RemoveAllConversationsActionType, RemoveAllConversationsActionType,
@ -23,11 +24,15 @@ import type {
ShowArchivedConversationsActionType, ShowArchivedConversationsActionType,
} from './conversations'; } from './conversations';
import { getQuery, getSearchConversation } from '../selectors/search'; import { getQuery, getSearchConversation } from '../selectors/search';
import { getIntl, getUserConversationId } from '../selectors/user'; import { getAllConversations } from '../selectors/conversations';
import {
getIntl,
getRegionCode,
getUserConversationId,
} from '../selectors/user';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
const { const {
searchConversations: dataSearchConversations,
searchMessages: dataSearchMessages, searchMessages: dataSearchMessages,
searchMessagesInConversation, searchMessagesInConversation,
}: ClientInterface = dataInterface; }: ClientInterface = dataInterface;
@ -166,6 +171,8 @@ function updateSearchTerm(
doSearch({ doSearch({
dispatch, dispatch,
allConversations: getAllConversations(state),
regionCode: getRegionCode(state),
noteToSelf: getIntl(state)('noteToSelf').toLowerCase(), noteToSelf: getIntl(state)('noteToSelf').toLowerCase(),
ourConversationId, ourConversationId,
query: getQuery(state), query: getQuery(state),
@ -177,6 +184,8 @@ function updateSearchTerm(
const doSearch = debounce( const doSearch = debounce(
({ ({
dispatch, dispatch,
allConversations,
regionCode,
noteToSelf, noteToSelf,
ourConversationId, ourConversationId,
query, query,
@ -188,7 +197,9 @@ const doSearch = debounce(
| SearchMessagesResultsFulfilledActionType | SearchMessagesResultsFulfilledActionType
| SearchDiscussionsResultsFulfilledActionType | SearchDiscussionsResultsFulfilledActionType
>; >;
allConversations: ReadonlyArray<ConversationType>;
noteToSelf: string; noteToSelf: string;
regionCode: string | undefined;
ourConversationId: string; ourConversationId: string;
query: string; query: string;
searchConversationId: undefined | string; searchConversationId: undefined | string;
@ -213,6 +224,8 @@ const doSearch = debounce(
await queryConversationsAndContacts(query, { await queryConversationsAndContacts(query, {
ourConversationId, ourConversationId,
noteToSelf, noteToSelf,
regionCode,
allConversations,
}); });
dispatch({ dispatch({
@ -250,20 +263,22 @@ async function queryMessages(
} }
async function queryConversationsAndContacts( async function queryConversationsAndContacts(
providedQuery: string, query: string,
options: { options: {
ourConversationId: string; ourConversationId: string;
noteToSelf: string; noteToSelf: string;
regionCode: string | undefined;
allConversations: ReadonlyArray<ConversationType>;
} }
): Promise<{ ): Promise<{
contactIds: Array<string>; contactIds: Array<string>;
conversationIds: Array<string>; conversationIds: Array<string>;
}> { }> {
const { ourConversationId, noteToSelf } = options; const { ourConversationId, noteToSelf, regionCode, allConversations } =
const query = providedQuery.replace(/[+.()]*/g, ''); options;
const searchResults: Array<DBConversationType> = const searchResults: Array<ConversationType> =
await dataSearchConversations(query); filterAndSortConversationsByRecent(allConversations, query, regionCode);
// Split into two groups - active conversations and items just from address book // Split into two groups - active conversations and items just from address book
let conversationIds: Array<string> = []; let conversationIds: Array<string> = [];
@ -272,7 +287,7 @@ async function queryConversationsAndContacts(
for (let i = 0; i < max; i += 1) { for (let i = 0; i < max; i += 1) {
const conversation = searchResults[i]; const conversation = searchResults[i];
if (conversation.type === 'private' && !conversation.lastMessage) { if (conversation.type === 'direct' && !conversation.lastMessage) {
contactIds.push(conversation.id); contactIds.push(conversation.id);
} else { } else {
conversationIds.push(conversation.id); conversationIds.push(conversation.id);
@ -280,7 +295,7 @@ async function queryConversationsAndContacts(
} }
// Inject synthetic Note to Self entry if query matches localized 'Note to Self' // Inject synthetic Note to Self entry if query matches localized 'Note to Self'
if (noteToSelf.indexOf(providedQuery.toLowerCase()) !== -1) { if (noteToSelf.indexOf(query.toLowerCase()) !== -1) {
// ensure that we don't have duplicates in our results // ensure that we don't have duplicates in our results
contactIds = contactIds.filter(id => id !== ourConversationId); contactIds = contactIds.filter(id => id !== ourConversationId);
conversationIds = conversationIds.filter(id => id !== ourConversationId); conversationIds = conversationIds.filter(id => id !== ourConversationId);

View file

@ -121,7 +121,7 @@ export const getConversationsByUsername = createSelector(
} }
); );
const getAllConversations = createSelector( export const getAllConversations = createSelector(
getConversationLookup, getConversationLookup,
(lookup): Array<ConversationType> => Object.values(lookup) (lookup): Array<ConversationType> => Object.values(lookup)
); );