From 2b3db8f3d4885648d0d7f5822701f45dd108fda3 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Thu, 11 Aug 2022 01:12:15 +0100
Subject: [PATCH] Filter contacts by blocked and banned status

---
 Sources/XXDatabase/Models/Contact+GRDB.swift  | 10 +++
 Sources/XXModels/Models/Contact.swift         | 26 ++++++++
 Tests/XXDatabaseTests/Contact+GRDBTests.swift | 64 +++++++++++++++++++
 Tests/XXDatabaseTests/Stubs.swift             | 12 ++++
 4 files changed, 112 insertions(+)

diff --git a/Sources/XXDatabase/Models/Contact+GRDB.swift b/Sources/XXDatabase/Models/Contact+GRDB.swift
index 978849d..1f91336 100644
--- a/Sources/XXDatabase/Models/Contact+GRDB.swift
+++ b/Sources/XXDatabase/Models/Contact+GRDB.swift
@@ -12,6 +12,8 @@ extension Contact: FetchableRecord, PersistableRecord {
     case photo
     case authStatus
     case isRecent
+    case isBlocked
+    case isBanned
     case createdAt
   }
 
@@ -58,6 +60,14 @@ extension Contact: FetchableRecord, PersistableRecord {
       request = request.filter(Column.isRecent == isRecent)
     }
 
+    if let isBlocked = query.isBlocked {
+      request = request.filter(Column.isBlocked == isBlocked)
+    }
+
+    if let isBanned = query.isBanned {
+      request = request.filter(Column.isBanned == isBanned)
+    }
+
     switch query.sortBy {
     case .username(desc: false):
       request = request.order(Column.username)
diff --git a/Sources/XXModels/Models/Contact.swift b/Sources/XXModels/Models/Contact.swift
index 3b464c1..b457973 100644
--- a/Sources/XXModels/Models/Contact.swift
+++ b/Sources/XXModels/Models/Contact.swift
@@ -173,6 +173,14 @@ extension Contact {
     ///     If `true`, only recent contacts are included.
     ///     If `false`, only non-recent contacts are included.
     ///     If `nil` (default), the filter is not used.
+    ///   - isBlocked: Filter by `isBlocked` status.
+    ///     If `true`, only blocked contacts are included.
+    ///     If `false`, only non-blocked contacts are included.
+    ///     If `nil` (default), the filter is not used.
+    ///   - isBanned: Filter by `isBanned` status.
+    ///     If `true`, only banned contacts are included.
+    ///     If `false`, only non-banned contacts are included.
+    ///     If `nil` (default), the filter is not used.
     ///   - sortBy: Sort order (defaults to `.username()`).
     public init(
       id: Set<Contact.ID>? = nil,
@@ -180,6 +188,8 @@ extension Contact {
       text: String? = nil,
       authStatus: Set<AuthStatus>? = nil,
       isRecent: Bool? = nil,
+      isBlocked: Bool? = nil,
+      isBanned: Bool? = nil,
       sortBy: SortOrder = .username()
     ) {
       self.id = id
@@ -187,6 +197,8 @@ extension Contact {
       self.text = text
       self.authStatus = authStatus
       self.isRecent = isRecent
+      self.isBlocked = isBlocked
+      self.isBanned = isBanned
       self.sortBy = sortBy
     }
 
@@ -220,6 +232,20 @@ extension Contact {
     /// If `nil`, the filter is not used.
     public var isRecent: Bool?
 
+    /// Filter by `isBlocked` status
+    ///
+    /// If `true`, only blocked contacts are included.
+    /// If `false`, only non-blocked contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isBlocked: Bool?
+
+    /// Filter by `isBanned` status
+    ///
+    /// If `true`, only banned contacts are included.
+    /// If `false`, only non-banned contacts are included.
+    /// If `nil`, the filter is not used.
+    public var isBanned: Bool?
+
     /// Contacts sort order
     public var sortBy: SortOrder
   }
diff --git a/Tests/XXDatabaseTests/Contact+GRDBTests.swift b/Tests/XXDatabaseTests/Contact+GRDBTests.swift
index 58ee5c8..ea44155 100644
--- a/Tests/XXDatabaseTests/Contact+GRDBTests.swift
+++ b/Tests/XXDatabaseTests/Contact+GRDBTests.swift
@@ -452,4 +452,68 @@ final class ContactGRDBTests: XCTestCase {
       contactF,
     ])
   }
+
+  func testFetchingByBlockedStatus() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A").withBlocked(false))
+    let contactB = try db.saveContact(.stub("B").withBlocked(true))
+    let contactC = try db.saveContact(.stub("C").withBlocked(false))
+    let contactD = try db.saveContact(.stub("D").withBlocked(true))
+
+    // Fetch blocked contacts:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBlocked: true)), [
+      contactB,
+      contactD,
+    ])
+
+    // Fetch not blocked contacts:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBlocked: false)), [
+      contactA,
+      contactC,
+    ])
+
+    // Fetch contacts regardless blocked status:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBlocked: nil)), [
+      contactA,
+      contactB,
+      contactC,
+      contactD,
+    ])
+  }
+
+  func testFetchingByBannedStatus() throws {
+    // Mock up contacts:
+
+    let contactA = try db.saveContact(.stub("A").withBanned(false))
+    let contactB = try db.saveContact(.stub("B").withBanned(true))
+    let contactC = try db.saveContact(.stub("C").withBanned(false))
+    let contactD = try db.saveContact(.stub("D").withBanned(true))
+
+    // Fetch banned contacts:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBanned: true)), [
+      contactB,
+      contactD,
+    ])
+
+    // Fetch not banned contacts:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBanned: false)), [
+      contactA,
+      contactC,
+    ])
+
+    // Fetch contacts regardless banned status:
+
+    XCTAssertNoDifference(try db.fetchContacts(.init(isBanned: nil)), [
+      contactA,
+      contactB,
+      contactC,
+      contactD,
+    ])
+  }
 }
diff --git a/Tests/XXDatabaseTests/Stubs.swift b/Tests/XXDatabaseTests/Stubs.swift
index 45bee51..780cbf6 100644
--- a/Tests/XXDatabaseTests/Stubs.swift
+++ b/Tests/XXDatabaseTests/Stubs.swift
@@ -62,6 +62,18 @@ extension Contact {
     contact.createdAt = createdAt
     return contact
   }
+
+  func withBlocked(_ isBlocked: Bool) -> Contact {
+    var contact = self
+    contact.isBlocked = isBlocked
+    return contact
+  }
+
+  func withBanned(_ isBanned: Bool) -> Contact {
+    var contact = self
+    contact.isBanned = isBanned
+    return contact
+  }
 }
 
 extension Group {
-- 
GitLab