From c3fbf88fbb9776ed11e8a024b98440f733bfc785 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 2 Jan 2020 18:21:18 -0700 Subject: [PATCH] Add check so that we don't update article statuses for articles that we have pending statuses to send. Issue #1515 --- .../Feedbin/FeedbinAccountDelegate.swift | 82 +++++++++++++------ Frameworks/SyncDatabase/SyncDatabase.swift | 11 +++ Frameworks/SyncDatabase/SyncStatusTable.swift | 40 +++++++++ 3 files changed, 110 insertions(+), 23 deletions(-) diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift index 14d2d4e49..fb5cad188 100644 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift @@ -1237,20 +1237,38 @@ private extension FeedbinAccountDelegate { return } - let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) - account.fetchUnreadArticleIDs { articleIDsResult in - guard let currentUnreadArticleIDs = try? articleIDsResult.get() else { - return + database.selectPendingReadStatusArticleIDs() { result in + + func process(_ pendingArticleIDs: Set) { + + let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) + let updatableFeedbinUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(pendingArticleIDs) + + account.fetchUnreadArticleIDs { articleIDsResult in + guard let currentUnreadArticleIDs = try? articleIDsResult.get() else { + return + } + + // Mark articles as unread + let deltaUnreadArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) + account.markAsUnread(deltaUnreadArticleIDs) + + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs) + account.markAsRead(deltaReadArticleIDs) + } + } - - // Mark articles as unread - let deltaUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - account.markAsUnread(deltaUnreadArticleIDs) - - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(feedbinUnreadArticleIDs) - account.markAsRead(deltaReadArticleIDs) + + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): + os_log(.error, log: self.log, "Sync Article Read Status failed: %@.", error.localizedDescription) + } + } + } func syncArticleStarredState(account: Account, articleIDs: [Int]?) { @@ -1258,20 +1276,38 @@ private extension FeedbinAccountDelegate { return } - let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) - account.fetchStarredArticleIDs { articleIDsResult in - guard let currentStarredArticleIDs = try? articleIDsResult.get() else { - return + database.selectPendingStarredStatusArticleIDs() { result in + + func process(_ pendingArticleIDs: Set) { + + let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) + let updatableFeedbinUnreadArticleIDs = feedbinStarredArticleIDs.subtracting(pendingArticleIDs) + + account.fetchStarredArticleIDs { articleIDsResult in + guard let currentStarredArticleIDs = try? articleIDsResult.get() else { + return + } + + // Mark articles as starred + let deltaStarredArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentStarredArticleIDs) + account.markAsStarred(deltaStarredArticleIDs) + + // Mark articles as unstarred + let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs) + account.markAsUnstarred(deltaUnstarredArticleIDs) + } + + } + + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): + os_log(.error, log: self.log, "Sync Article Starred Status failed: %@.", error.localizedDescription) } - // Mark articles as starred - let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) - account.markAsStarred(deltaStarredArticleIDs) - - // Mark articles as unstarred - let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) - account.markAsUnstarred(deltaUnstarredArticleIDs) } + } func deleteTagging(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result) -> Void) { diff --git a/Frameworks/SyncDatabase/SyncDatabase.swift b/Frameworks/SyncDatabase/SyncDatabase.swift index 975bc5607..7790193e9 100644 --- a/Frameworks/SyncDatabase/SyncDatabase.swift +++ b/Frameworks/SyncDatabase/SyncDatabase.swift @@ -13,6 +13,9 @@ import RSDatabase public typealias SyncStatusesResult = Result, DatabaseError> public typealias SyncStatusesCompletionBlock = (SyncStatusesResult) -> Void +public typealias SyncStatusArticleIDsResult = Result, DatabaseError> +public typealias SyncStatusArticleIDsCompletionBlock = (SyncStatusArticleIDsResult) -> Void + public struct SyncDatabase { private let syncStatusTable: SyncStatusTable @@ -41,6 +44,14 @@ public struct SyncDatabase { syncStatusTable.selectPendingCount(completion) } + public func selectPendingReadStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { + syncStatusTable.selectPendingReadStatusArticleIDs(completion: completion) + } + + public func selectPendingStarredStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { + syncStatusTable.selectPendingStarredStatusArticleIDs(completion: completion) + } + public func resetSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) { syncStatusTable.resetSelectedForProcessing(articleIDs, completion: completion) } diff --git a/Frameworks/SyncDatabase/SyncStatusTable.swift b/Frameworks/SyncDatabase/SyncStatusTable.swift index 04100c783..3d93ffab1 100644 --- a/Frameworks/SyncDatabase/SyncStatusTable.swift +++ b/Frameworks/SyncDatabase/SyncStatusTable.swift @@ -83,6 +83,14 @@ struct SyncStatusTable: DatabaseTable { } } + func selectPendingReadStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { + selectPendingArticleIDsAsync(.read, completion) + } + + func selectPendingStarredStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { + selectPendingArticleIDsAsync(.starred, completion) + } + func resetSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) { queue.runInTransaction { databaseResult in @@ -156,6 +164,38 @@ private extension SyncStatusTable { return SyncStatus(articleID: articleID, key: key, flag: flag, selected: selected) } + + func selectPendingArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ completion: @escaping SyncStatusArticleIDsCompletionBlock) { + + queue.runInDatabase { databaseResult in + + func makeDatabaseCall(_ database: FMDatabase) { + let sql = "select articleID from syncStatus where selected == false and key = \"\(statusKey.rawValue)\";" + + guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { + DispatchQueue.main.async { + completion(.success(Set())) + } + return + } + + let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) } + DispatchQueue.main.async { + completion(.success(articleIDs)) + } + } + + switch databaseResult { + case .success(let database): + makeDatabaseCall(database) + case .failure(let databaseError): + DispatchQueue.main.async { + completion(.failure(databaseError)) + } + } + } + } + } private func callCompletion(_ completion: DatabaseCompletionBlock?, _ databaseError: DatabaseError?) {