diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index a624405c8..ac672d053 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -762,6 +762,17 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, database.ensureStatuses(articleIDs, defaultRead, statusKey, flag, completionHandler: completionHandler) } + /// Update statuses — set a key and value. This updates the database, and sends a .StatusesDidChange notification. + func update(statuses: Set, statusKey: ArticleStatus.Key, flag: Bool) { + // TODO: https://github.com/brentsimmons/NetNewsWire/issues/1420 + } + + /// Fetch statuses for the specified articleIDs. The completionHandler will get nil if the app is suspended. + /// To update the properties in the database, call the update method that takes Set as first parameter. + func fetchStatuses(articleIDs: Set, createIfNeeded: Bool, completionHandler: @escaping (Set?) -> Void) { + database.fetchStatuses(articleIDs: articleIDs, createIfNeeded: createIfNeeded, callback: completionHandler) + } + /// 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/ArticlesDatabase/ArticlesDatabase.swift b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift index 22f53ae1c..fcc7894c1 100644 --- a/Frameworks/ArticlesDatabase/ArticlesDatabase.swift +++ b/Frameworks/ArticlesDatabase/ArticlesDatabase.swift @@ -172,6 +172,10 @@ public final class ArticlesDatabase { return articlesTable.mark(articles, statusKey, flag) } + public func fetchStatuses(articleIDs: Set, createIfNeeded: Bool, callback: @escaping (Set?) -> Void) { + articlesTable.fetchStatuses(articleIDs, createIfNeeded, callback) + } + // MARK: - Suspend and Resume (for iOS) /// Close the database and stop running database calls. diff --git a/Frameworks/ArticlesDatabase/ArticlesTable.swift b/Frameworks/ArticlesDatabase/ArticlesTable.swift index 0cd2ac662..25e04318c 100644 --- a/Frameworks/ArticlesDatabase/ArticlesTable.swift +++ b/Frameworks/ArticlesDatabase/ArticlesTable.swift @@ -310,7 +310,28 @@ final class ArticlesTable: DatabaseTable { } } } - + + func fetchStatuses(_ articleIDs: Set, _ createIfNeeded: Bool, _ callback: @escaping (Set?) -> Void) { + guard !queue.isSuspended else { + callback(nil) + return + } + + queue.runInTransaction { (database) in + var statusesDictionary = [String: ArticleStatus]() + if createIfNeeded { + statusesDictionary = self.statusesTable.ensureStatusesForArticleIDs(articleIDs, false, database) + } + else { + statusesDictionary = self.statusesTable.existingStatusesForArticleIDs(articleIDs, database) + } + let statuses = Set(statusesDictionary.values) + DispatchQueue.main.async { + callback(statuses) + } + } + } + // MARK: - Unread Counts func fetchUnreadCounts(_ webFeedIDs: Set, _ completion: @escaping UnreadCountCompletionBlock) { diff --git a/Frameworks/ArticlesDatabase/StatusesTable.swift b/Frameworks/ArticlesDatabase/StatusesTable.swift index ff145540c..63388841c 100644 --- a/Frameworks/ArticlesDatabase/StatusesTable.swift +++ b/Frameworks/ArticlesDatabase/StatusesTable.swift @@ -46,6 +46,19 @@ final class StatusesTable: DatabaseTable { return statusesDictionary(articleIDs) } + func existingStatusesForArticleIDs(_ articleIDs: Set, _ database: FMDatabase) -> [String: ArticleStatus] { + // Check cache. + let articleIDsMissingCachedStatus = articleIDsWithNoCachedStatus(articleIDs) + if articleIDsMissingCachedStatus.isEmpty { + return statusesDictionary(articleIDs) + } + + // Check database. + fetchAndCacheStatusesForArticleIDs(articleIDsMissingCachedStatus, database) + + return statusesDictionary(articleIDs) + } + // MARK: - Marking @discardableResult