Skip to content
Snippets Groups Projects
Commit c0ef6d7d authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Merge branch 'feature/contacts-text-search' into 'main'

Contacts text search

See merge request elixxir/client-ios-db!27
parents f52a83a8 26b749b7
No related branches found
No related tags found
1 merge request!27Contacts text search
...@@ -39,6 +39,17 @@ extension Contact: FetchableRecord, PersistableRecord { ...@@ -39,6 +39,17 @@ extension Contact: FetchableRecord, PersistableRecord {
break break
} }
if let text = query.text {
let columns = [Column.username, Column.email, Column.phone, Column.nickname]
let escape = #"\"#
let escapedText = text.replacingOccurrences(of: "%", with: "\(escape)%")
let pattern = "%\(escapedText)%"
request = request.filter(columns
.map { $0.like(pattern, escape: escape) }
.joined(operator: .or)
)
}
if let authStatus = query.authStatus { if let authStatus = query.authStatus {
request = request.filter(Set(authStatus.map(\.rawValue)).contains(Column.authStatus)) request = request.filter(Set(authStatus.map(\.rawValue)).contains(Column.authStatus))
} }
......
...@@ -150,6 +150,10 @@ extension Contact { ...@@ -150,6 +150,10 @@ extension Contact {
/// If `.some(.some("username"))`, include contacts with provided username. /// If `.some(.some("username"))`, include contacts with provided username.
/// If `.some(.none)`, include contacts without username set. /// If `.some(.none)`, include contacts without username set.
/// If `.none` (default), disable the filter. /// If `.none` (default), disable the filter.
/// - text: Filter contacts using text search.
/// If set, include contacts with `username`, `email`, `phone` or `nickname`
/// containing the provided phrase.
/// If `nil` (default), disable the filter.
/// - authStatus: Filter contacts by auth status. /// - authStatus: Filter contacts by auth status.
/// If set, only contacts with any of the provided auth statuses will be fetched. /// If set, only contacts with any of the provided auth statuses will be fetched.
/// If `nil` (default), the filter is not used. /// If `nil` (default), the filter is not used.
...@@ -161,12 +165,14 @@ extension Contact { ...@@ -161,12 +165,14 @@ extension Contact {
public init( public init(
id: Set<Contact.ID>? = nil, id: Set<Contact.ID>? = nil,
username: String?? = nil, username: String?? = nil,
text: String? = nil,
authStatus: Set<AuthStatus>? = nil, authStatus: Set<AuthStatus>? = nil,
isRecent: Bool? = nil, isRecent: Bool? = nil,
sortBy: SortOrder = .username() sortBy: SortOrder = .username()
) { ) {
self.id = id self.id = id
self.username = username self.username = username
self.text = text
self.authStatus = authStatus self.authStatus = authStatus
self.isRecent = isRecent self.isRecent = isRecent
self.sortBy = sortBy self.sortBy = sortBy
...@@ -182,6 +188,13 @@ extension Contact { ...@@ -182,6 +188,13 @@ extension Contact {
/// If `.none`, disable the filter. /// If `.none`, disable the filter.
public var username: String?? public var username: String??
/// Filter contacts using text search
///
/// If set, include contacts with `username`, `email`, `phone` or `nickname`
/// containing the provided phrase.
/// If `nil`, disable the filter.
public var text: String?
/// Filter contacts by auth status /// Filter contacts by auth status
/// ///
/// If set, only contacts with any of the provided auth statuses will be fetched. /// If set, only contacts with any of the provided auth statuses will be fetched.
......
...@@ -366,4 +366,90 @@ final class ContactGRDBTests: XCTestCase { ...@@ -366,4 +366,90 @@ final class ContactGRDBTests: XCTestCase {
contactF.withAuthStatus(.verificationFailed), contactF.withAuthStatus(.verificationFailed),
]) ])
} }
func testFetchingByText() throws {
// Mock up contacts:
let contactA = try db.saveContact(.stub("A")
.withUsername("john_a")
.withEmail("john.a@test.com")
.withPhone("100-200-001")
.withNickname("JohnA")
.withCreatedAt(.stub(1))
)
let contactB = try db.saveContact(.stub("B")
.withUsername("john_b")
.withEmail("john.b@test.com")
.withPhone("100-123-002")
.withNickname("JohnB")
.withCreatedAt(.stub(2))
)
let contactC = try db.saveContact(.stub("C")
.withUsername("mary-1")
.withEmail("mary2@test.com")
.withPhone("100-123-003")
.withNickname("Mary1")
.withCreatedAt(.stub(3))
)
let contactD = try db.saveContact(.stub("D")
.withUsername("mary-2")
.withEmail("mary2@test.com")
.withPhone("100-200-004")
.withNickname("Mary2")
.withCreatedAt(.stub(4))
)
let contactE = try db.saveContact(.stub("E")
.withUsername("admin1")
.withEmail("admin1@test.com")
.withPhone("100-200-005")
.withNickname("Admin 100% (1)")
.withCreatedAt(.stub(5))
)
let contactF = try db.saveContact(.stub("F")
.withUsername("admin2")
.withEmail("admin2@test.com")
.withPhone("100-123-006")
.withNickname("Admin 100% (2)")
.withCreatedAt(.stub(6))
)
// Fetch contacts with text:
XCTAssertNoDifference(try db.fetchContacts(.init(text: "john", sortBy: .createdAt())), [
contactA,
contactB,
])
XCTAssertNoDifference(try db.fetchContacts(.init(text: "John", sortBy: .createdAt())), [
contactA,
contactB,
])
XCTAssertNoDifference(try db.fetchContacts(.init(text: "mary", sortBy: .createdAt())), [
contactC,
contactD,
])
XCTAssertNoDifference(try db.fetchContacts(.init(text: "123", sortBy: .createdAt())), [
contactB,
contactC,
contactF,
])
XCTAssertNoDifference(try db.fetchContacts(.init(text: "100%", sortBy: .createdAt())), [
contactE,
contactF,
])
// Fetch contacts with `nil` text query:
XCTAssertNoDifference(try db.fetchContacts(.init(text: nil, sortBy: .createdAt())), [
contactA,
contactB,
contactC,
contactD,
contactE,
contactF,
])
}
} }
...@@ -38,6 +38,30 @@ extension Contact { ...@@ -38,6 +38,30 @@ extension Contact {
contact.username = username contact.username = username
return contact return contact
} }
func withEmail(_ email: String?) -> Contact {
var contact = self
contact.email = email
return contact
}
func withPhone(_ phone: String?) -> Contact {
var contact = self
contact.phone = phone
return contact
}
func withNickname(_ nickname: String?) -> Contact {
var contact = self
contact.nickname = nickname
return contact
}
func withCreatedAt(_ createdAt: Date) -> Contact {
var contact = self
contact.createdAt = createdAt
return contact
}
} }
extension Group { extension Group {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment