From 095c8575f39a9a1ed4a8f7c489cc2e782762f7c9 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Wed, 29 Apr 2020 19:13:50 -0500 Subject: [PATCH] Add CloudKit deletes --- Frameworks/Account/Account.swift | 9 ++++++ .../CloudKitArticlesZoneDelegate.swift | 30 ++++++++++++++----- .../ArticlesDatabase/ArticlesDatabase.swift | 7 ++++- .../ArticlesDatabase/ArticlesTable.swift | 25 +++++++++++++++- 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 66927d935..51426da29 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -854,6 +854,15 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, markAndFetchNew(articleIDs: articleIDs, statusKey: .starred, flag: false, completion: completion) } + // Delete the articles associated with the given set of articleIDs + func delete(articleIDs: Set, completion: DatabaseCompletionBlock? = nil) { + guard !articleIDs.isEmpty else { + completion?(nil) + return + } + database.delete(articleIDs: articleIDs, completion: completion) + } + /// Empty caches that can reasonably be emptied. Call when the app goes in the background, for instance. func emptyCaches() { database.emptyCaches() diff --git a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift index 0fece208b..bb9330764 100644 --- a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift @@ -38,11 +38,13 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { self.database.selectPendingStarredStatusArticleIDs() { result in switch result { case .success(let pendingStarredStatusArticleIDs): - - self.process(records: changed, - pendingReadStatusArticleIDs: pendingReadStatusArticleIDs, - pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs, - completion: completion) + + self.delete(recordKeys: deleted, pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs) { + self.update(records: changed, + pendingReadStatusArticleIDs: pendingReadStatusArticleIDs, + pendingStarredStatusArticleIDs: pendingStarredStatusArticleIDs, + completion: completion) + } case .failure(let error): os_log(.error, log: self.log, "Error occurred geting pending starred records: %@", error.localizedDescription) @@ -59,8 +61,20 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { } private extension CloudKitArticlesZoneDelegate { - - func process(records: [CKRecord], pendingReadStatusArticleIDs: Set, pendingStarredStatusArticleIDs: Set, completion: @escaping (Result) -> Void) { + + func delete(recordKeys: [CloudKitRecordKey], pendingStarredStatusArticleIDs: Set, completion: @escaping () -> Void) { + let receivedRecordIDs = recordKeys.filter({ $0.recordType == CloudKitArticlesZone.CloudKitArticleStatus.recordType }).map({ $0.recordID }) + let receivedArticleIDs = Set(receivedRecordIDs.map({ stripPrefix($0.externalID) })) + let deletableArticleIDs = receivedArticleIDs.subtracting(pendingStarredStatusArticleIDs) + + database.deleteSelectedForProcessing(Array(deletableArticleIDs)) { _ in + self.account?.delete(articleIDs: deletableArticleIDs) { _ in + completion() + } + } + } + + func update(records: [CKRecord], pendingReadStatusArticleIDs: Set, pendingStarredStatusArticleIDs: Set, completion: @escaping (Result) -> Void) { let receivedUnreadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ stripPrefix($0.externalID) })) let receivedReadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ stripPrefix($0.externalID) })) @@ -75,7 +89,7 @@ private extension CloudKitArticlesZoneDelegate { let group = DispatchGroup() group.enter() - account?.markAsUnread(updateableUnreadArticleIDs) { result in + account?.markAsUnread(updateableUnreadArticleIDs) { _ in group.leave() } diff --git a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift index 04e3e915b..6bbe3035e 100644 --- a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift +++ b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift @@ -201,7 +201,7 @@ public final class ArticlesDatabase { articlesTable.fetchStarredAndUnreadCount(webFeedIDs, completion) } - // MARK: - Saving and Updating Articles + // MARK: - Saving, Updating, and Deleting Articles /// Update articles and save new ones — for feed-based systems (local and iCloud). public func update(with parsedItems: Set, webFeedID: String, completion: @escaping UpdateArticlesCompletionBlock) { @@ -215,6 +215,11 @@ public final class ArticlesDatabase { articlesTable.update(webFeedIDsAndItems, defaultRead, completion) } + /// Delete articles + public func delete(articleIDs: Set, completion: DatabaseCompletionBlock?) { + articlesTable.delete(articleIDs: articleIDs, completion: completion) + } + // MARK: - Status /// Fetch the articleIDs of unread articles in feeds specified by webFeedIDs. diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index dc67a779f..a49031210 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -170,7 +170,7 @@ final class ArticlesTable: DatabaseTable { return nil } - // MARK: - Updating + // MARK: - Updating and Deleting func update(_ parsedItems: Set, _ webFeedID: String, _ completion: @escaping UpdateArticlesCompletionBlock) { precondition(retentionStyle == .feedBased) @@ -318,6 +318,29 @@ final class ArticlesTable: DatabaseTable { } } + public func delete(articleIDs: Set, completion: DatabaseCompletionBlock?) { + self.queue.runInTransaction { (databaseResult) in + + func makeDatabaseCalls(_ database: FMDatabase) { + self.removeArticles(articleIDs, database) + DispatchQueue.main.async { + completion?(nil) + } + } + + switch databaseResult { + case .success(let database): + makeDatabaseCalls(database) + case .failure(let databaseError): + DispatchQueue.main.async { + completion?(databaseError) + } + } + + } + + } + // MARK: - Unread Counts func fetchUnreadCount(_ webFeedIDs: Set, _ since: Date, _ completion: @escaping SingleUnreadCountCompletionBlock) {