Merge branch 'charlesmchen/searchImprovements'

This commit is contained in:
Matthew Chen 2020-07-06 14:32:10 -03:00
commit b2063352d5
5 changed files with 108 additions and 19 deletions

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -257,7 +257,8 @@ public class FullTextSearcher: NSObject {
maxResults: UInt = kDefaultMaxResults,
transaction: SDSAnyReadTransaction) -> ComposeScreenSearchResultSet {
var signalContacts: [ContactSearchResult] = []
var signalContactMap = [SignalServiceAddress: ContactSearchResult]()
var signalRecipentResults: [ContactSearchResult] = []
var groups: [GroupSearchResult] = []
var count: UInt = 0
@ -272,7 +273,16 @@ public class FullTextSearcher: NSObject {
switch match {
case let signalAccount as SignalAccount:
let searchResult = ContactSearchResult(signalAccount: signalAccount, transaction: transaction)
signalContacts.append(searchResult)
assert(signalContactMap[signalAccount.recipientAddress] == nil)
signalContactMap[signalAccount.recipientAddress] = searchResult
case let signalRecipient as SignalRecipient:
guard signalRecipient.devices.count > 0 else {
// Ignore unregistered recipients.
return
}
let signalAccount = SignalAccount(signalRecipient: signalRecipient, contact: nil, multipleAccountLabelText: nil)
let searchResult = ContactSearchResult(signalAccount: signalAccount, transaction: transaction)
signalRecipentResults.append(searchResult)
case let groupThread as TSGroupThread:
let sortKey = ConversationSortKey(isContactThread: false,
creationDate: groupThread.creationDate,
@ -291,19 +301,28 @@ public class FullTextSearcher: NSObject {
}
}
if matchesNoteToSelf(searchText: searchText, transaction: transaction) {
if !signalContacts.contains(where: { $0.signalAccount.recipientAddress.isLocalAddress }) {
if let localAddress = TSAccountManager.localAddress {
let localAccount = SignalAccount(address: localAddress)
let localResult = ContactSearchResult(signalAccount: localAccount, transaction: transaction)
signalContacts.append(localResult)
} else {
owsFailDebug("localAddress was unexpectedly nil")
}
// Fill in user matches from SignalRecipients, but only if
// we don't already have a SignalAccount for the same user.
for signalRecipentResult in signalRecipentResults {
if signalContactMap[signalRecipentResult.recipientAddress] == nil {
signalContactMap[signalRecipentResult.recipientAddress] = signalRecipentResult
}
}
if let localAddress = TSAccountManager.localAddress {
if matchesNoteToSelf(searchText: searchText, transaction: transaction) {
if signalContactMap[localAddress] == nil {
let localAccount = SignalAccount(address: localAddress)
let localResult = ContactSearchResult(signalAccount: localAccount, transaction: transaction)
signalContactMap[localAddress] = localResult
}
}
} else {
owsFailDebug("localAddress was unexpectedly nil")
}
// Order contact results by display name.
var signalContacts: [ContactSearchResult] = Array(signalContactMap.values)
signalContacts.sort()
// Order the conversation and message results in reverse chronological order.

View File

@ -486,6 +486,11 @@ const NSUInteger SignalRecipientSchemaVersion = 1;
[self.signalRecipientReadCache didRemoveSignalRecipient:self transaction:transaction];
}
+ (BOOL)shouldBeIndexedForFTS
{
return YES;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -79,6 +79,7 @@ public class GRDBSchemaMigrator: NSObject {
case addMarkedUnreadIndexToThread
case fixIncorrectIndexes
case resetThreadVisibility
case indexSignalRecipients
// NOTE: Every time we add a migration id, consider
// incrementing grdbSchemaVersionLatest.
@ -302,8 +303,9 @@ public class GRDBSchemaMigrator: NSObject {
do {
try autoreleasepool {
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
try dedupeSignalRecipients(transaction: transaction.asAnyWrite)
transaction.finalizeTransaction()
}
try db.drop(index: "index_signal_recipients_on_recipientPhoneNumber")
@ -600,9 +602,10 @@ public class GRDBSchemaMigrator: NSObject {
try db.drop(table: "model_OWSLinkedDeviceReadReceipt")
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
let viewOnceStore = SDSKeyValueStore(collection: "viewOnceMessages")
viewOnceStore.removeAll(transaction: transaction.asAnyWrite)
transaction.finalizeTransaction()
} catch {
owsFail("Error: \(error)")
}
@ -715,6 +718,16 @@ public class GRDBSchemaMigrator: NSObject {
}
}
migrator.registerMigration(MigrationId.indexSignalRecipients.rawValue) { db in
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
SignalRecipient.anyEnumerate(transaction: transaction.asAnyWrite) { (signalRecipient: SignalRecipient,
_: UnsafeMutablePointer<ObjCBool>) in
GRDBFullTextSearchFinder.modelWasInserted(model: signalRecipient, transaction: transaction)
}
}
// MARK: - Schema Migration Insertion Point
}
@ -726,8 +739,9 @@ public class GRDBSchemaMigrator: NSObject {
migrator.registerMigration(MigrationId.dataMigration_populateGalleryItems.rawValue) { db in
do {
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
try createInitialGalleryRecords(transaction: transaction)
transaction.finalizeTransaction()
} catch {
owsFail("Error: \(error)")
}
@ -735,11 +749,12 @@ public class GRDBSchemaMigrator: NSObject {
migrator.registerMigration(MigrationId.dataMigration_markOnboardedUsers_v2.rawValue) { db in
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
if TSAccountManager.sharedInstance().isRegistered(transaction: transaction.asAnyWrite) {
Logger.info("marking existing user as onboarded")
TSAccountManager.sharedInstance().setIsOnboarded(true, transaction: transaction.asAnyWrite)
}
transaction.finalizeTransaction()
}
migrator.registerMigration(MigrationId.dataMigration_clearLaunchScreenCache.rawValue) { _ in
@ -748,19 +763,20 @@ public class GRDBSchemaMigrator: NSObject {
migrator.registerMigration(MigrationId.dataMigration_enableV2RegistrationLockIfNecessary.rawValue) { db in
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
guard KeyBackupService.hasMasterKey(transaction: transaction.asAnyWrite) else {
transaction.finalizeTransaction()
return
}
OWS2FAManager.keyValueStore().setBool(true, key: OWS2FAManager.isRegistrationLockV2EnabledKey, transaction: transaction.asAnyWrite)
transaction.finalizeTransaction()
}
migrator.registerMigration(MigrationId.dataMigration_resetStorageServiceData.rawValue) { db in
let transaction = GRDBWriteTransaction(database: db)
defer { transaction.finalizeTransaction() }
SSKEnvironment.shared.storageServiceManager.resetLocalData(transaction: transaction.asAnyWrite)
transaction.finalizeTransaction()
}
migrator.registerMigration(MigrationId.dataMigration_markAllInteractionsAsNotDeleted.rawValue) { db in

View File

@ -28,6 +28,15 @@ public class FullTextSearchFinder: NSObject {
}
}
@objc
public func modelWasUpdatedObjc(model: TSYapDatabaseObject, transaction: SDSAnyWriteTransaction) {
guard let model = model as? SDSModel else {
owsFailDebug("Invalid model.")
return
}
modelWasUpdated(model: model, transaction: transaction)
}
public func modelWasUpdated(model: SDSModel, transaction: SDSAnyWriteTransaction) {
assert(type(of: model).shouldBeIndexedForFTS)
@ -342,6 +351,13 @@ class GRDBFullTextSearchFinder: NSObject {
return nil
}
return model
case SignalRecipient.collection():
guard let model = SignalRecipient.anyFetch(uniqueId: uniqueId,
transaction: transaction.asAnyRead) else {
owsFailDebug("Couldn't load record: \(collection)")
return nil
}
return model
default:
owsFailDebug("Unexpected record type: \(collection)")
return nil
@ -515,6 +531,8 @@ class AnySearchIndexer {
return self.messageIndexer.index(message, transaction: transaction)
} else if let signalAccount = object as? SignalAccount {
return self.recipientIndexer.index(signalAccount.recipientAddress, transaction: transaction)
} else if let signalRecipient = object as? SignalRecipient {
return self.recipientIndexer.index(signalRecipient.address, transaction: transaction)
} else {
return nil
}

View File

@ -771,6 +771,8 @@ NSUInteger const kUserProfileSchemaVersion = 1;
{
[super anyDidInsertWithTransaction:transaction];
[self reindexAssociatedModels:transaction];
[self.userProfileReadCache didInsertOrUpdateUserProfile:self transaction:transaction];
}
@ -778,6 +780,8 @@ NSUInteger const kUserProfileSchemaVersion = 1;
{
[super anyDidUpdateWithTransaction:transaction];
[self reindexAssociatedModels:transaction];
[self.userProfileReadCache didInsertOrUpdateUserProfile:self transaction:transaction];
}
@ -788,6 +792,33 @@ NSUInteger const kUserProfileSchemaVersion = 1;
[self.userProfileReadCache didRemoveUserProfile:self transaction:transaction];
}
- (void)reindexAssociatedModels:(SDSAnyWriteTransaction *)transaction
{
// The profile can affect how accounts, recipients and contact threads are indexed, so we
// need to re-index them whenever the profile changes.
FullTextSearchFinder *fullTextSearchFinder = [FullTextSearchFinder new];
AnySignalAccountFinder *accountFinder = [AnySignalAccountFinder new];
SignalAccount *_Nullable signalAccount = [accountFinder signalAccountForAddress:self.address
transaction:transaction];
if (signalAccount != nil) {
[fullTextSearchFinder modelWasUpdatedObjcWithModel:signalAccount transaction:transaction];
}
AnySignalRecipientFinder *signalRecipientFinder = [AnySignalRecipientFinder new];
SignalRecipient *_Nullable signalRecipient = [signalRecipientFinder signalRecipientForAddress:self.address
transaction:transaction];
if (signalRecipient != nil) {
[fullTextSearchFinder modelWasUpdatedObjcWithModel:signalRecipient transaction:transaction];
}
TSContactThread *_Nullable contactThread = [TSContactThread getThreadWithContactAddress:self.address
transaction:transaction];
if (contactThread != nil) {
[fullTextSearchFinder modelWasUpdatedObjcWithModel:contactThread transaction:transaction];
}
}
+ (void)mergeUserProfilesIfNecessaryForAddress:(SignalServiceAddress *)address
transaction:(SDSAnyWriteTransaction *)transaction
{