diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index 6c279e0b9..dbf53474e 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -752,12 +752,12 @@ public enum FetchType { return try database.fetchStarredArticlesCount(flattenedFeeds().feedIDs()) } - public func fetchUnreadArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) { - database.fetchUnreadArticleIDsAsync(completion: completion) + public func fetchUnreadArticleIDs() async throws -> Set { + return try await database.fetchUnreadArticleIDsAsync() } - public func fetchStarredArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) { - database.fetchStarredArticleIDsAsync(completion: completion) + public func fetchStarredArticleIDs() async throws -> Set { + return try await database.fetchStarredArticleIDsAsync() } /// Fetch articleIDs for articles that we should have, but don’t. These articles are either (starred) or (newer than the article cutoff date). diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index 6724a7f1d..7eabf2e41 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -1276,102 +1276,81 @@ private extension FeedbinAccountDelegate { database.selectPendingReadStatusArticleIDs() { result in - @MainActor 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 - } + func process(_ pendingArticleIDs: Set) { - let group = DispatchGroup() - - // Mark articles as unread - let deltaUnreadArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - group.enter() - account.markAsUnread(deltaUnreadArticleIDs) { _ in - group.leave() - } + Task { @MainActor in + let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } ) + let updatableFeedbinUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(pendingArticleIDs) - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs) - group.enter() - account.markAsRead(deltaReadArticleIDs) { _ in - group.leave() - } - - group.notify(queue: DispatchQueue.main) { - completion() - } - - } + do { + let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs() + + // Mark articles as unread + let deltaUnreadArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs) + account.markAsUnread(deltaUnreadArticleIDs) + + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs) + account.markAsRead(deltaReadArticleIDs) + + } catch let error { + self.logger.error("Sync Articles Read Status failed: \(error.localizedDescription, privacy: .public)") + } + + completion() + } + } - } - switch result { case .success(let pendingArticleIDs): process(pendingArticleIDs) case .failure(let error): self.logger.error("Sync Articles Read Status failed: \(error.localizedDescription, privacy: .public)") } - } - } - func syncArticleStarredState(account: Account, articleIDs: [Int]?, completion: @escaping (() -> Void)) { - guard let articleIDs = articleIDs else { - completion() - return - } + func syncArticleStarredState(account: Account, articleIDs: [Int]?, completion: @escaping (() -> Void)) { + guard let articleIDs = articleIDs else { + completion() + return + } - database.selectPendingStarredStatusArticleIDs() { result in + database.selectPendingStarredStatusArticleIDs() { result in - @MainActor func process(_ pendingArticleIDs: Set) { - - let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) - let updatableFeedbinStarredArticleIDs = feedbinStarredArticleIDs.subtracting(pendingArticleIDs) + func process(_ pendingArticleIDs: Set) { - account.fetchStarredArticleIDs { articleIDsResult in - guard let currentStarredArticleIDs = try? articleIDsResult.get() else { - return - } + Task { @MainActor in + let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) + let updatableFeedbinStarredArticleIDs = feedbinStarredArticleIDs.subtracting(pendingArticleIDs) - let group = DispatchGroup() - - // Mark articles as starred - let deltaStarredArticleIDs = updatableFeedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) - group.enter() - account.markAsStarred(deltaStarredArticleIDs) { _ in - group.leave() - } + do { + let currentStarredArticleIDs = try await account.fetchStarredArticleIDs() - // Mark articles as unstarred - let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableFeedbinStarredArticleIDs) - group.enter() - account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in - group.leave() - } + // Mark articles as starred + let deltaStarredArticleIDs = updatableFeedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) + account.markAsStarred(deltaStarredArticleIDs) - group.notify(queue: DispatchQueue.main) { - completion() - } - } - - } - - switch result { - case .success(let pendingArticleIDs): - process(pendingArticleIDs) - case .failure(let error): + // Mark articles as unstarred + let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableFeedbinStarredArticleIDs) + account.markAsUnstarred(deltaUnstarredArticleIDs) + + } catch let error { + self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)") + } + + completion() + } + } + + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)") - } - - } - - } + } + } + } func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result) -> Void) { diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift index a38ee238f..c77de269e 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyIngestStarredArticleIdsOperation.swift @@ -93,16 +93,22 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation, Logging { didFinish() return } - - account.fetchStarredArticleIDs { result in - switch result { - case .success(let localStarredArticleIDs): - self.processStarredArticleIDs(localStarredArticleIDs) - - case .failure(let error): - self.didFinish(with: error) - } - } + + Task { @MainActor in + + var localStarredArticleIDs: Set? + + do { + localStarredArticleIDs = try await account.fetchStarredArticleIDs() + } catch { + didFinish(with: error) + return + } + + if let localStarredArticleIDs { + processStarredArticleIDs(localStarredArticleIDs) + } + } } func processStarredArticleIDs(_ localStarredArticleIDs: Set) { diff --git a/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift b/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift index fa618fe70..c631e0d3d 100644 --- a/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift +++ b/Account/Sources/Account/Feedly/Operations/FeedlyIngestUnreadArticleIdsOperation.swift @@ -94,16 +94,21 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation, Logging { didFinish() return } - - account.fetchUnreadArticleIDs { result in - switch result { - case .success(let localUnreadArticleIDs): - self.processUnreadArticleIDs(localUnreadArticleIDs) - - case .failure(let error): - self.didFinish(with: error) - } - } + + Task { @MainActor in + var localUnreadArticleIDs: Set? + + do { + localUnreadArticleIDs = try await account.fetchUnreadArticleIDs() + } catch { + didFinish(with: error) + return + } + + if let localUnreadArticleIDs { + processUnreadArticleIDs(localUnreadArticleIDs) + } + } } private func processUnreadArticleIDs(_ localUnreadArticleIDs: Set) { diff --git a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift index ef35dffb3..1583ecaa2 100644 --- a/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift +++ b/Account/Sources/Account/NewsBlur/Internals/NewsBlurAccountDelegate+Internal.swift @@ -316,53 +316,45 @@ extension NewsBlurAccountDelegate { } } - func syncStoryReadState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) { - guard let hashes = hashes else { - completion() - return - } + func syncStoryReadState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) { + guard let hashes = hashes else { + completion() + return + } - database.selectPendingReadStatusArticleIDs() { result in + database.selectPendingReadStatusArticleIDs() { result in @MainActor func process(_ pendingStoryHashes: Set) { - let newsBlurUnreadStoryHashes = Set(hashes.map { $0.hash } ) - let updatableNewsBlurUnreadStoryHashes = newsBlurUnreadStoryHashes.subtracting(pendingStoryHashes) + Task { @MainActor in + let newsBlurUnreadStoryHashes = Set(hashes.map { $0.hash } ) + let updatableNewsBlurUnreadStoryHashes = newsBlurUnreadStoryHashes.subtracting(pendingStoryHashes) - account.fetchUnreadArticleIDs { articleIDsResult in - guard let currentUnreadArticleIDs = try? articleIDsResult.get() else { - return - } + do { + let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs() - let group = DispatchGroup() - - // Mark articles as unread - let deltaUnreadArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentUnreadArticleIDs) - group.enter() - account.markAsUnread(deltaUnreadArticleIDs) { _ in - group.leave() - } + // Mark articles as unread + let deltaUnreadArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentUnreadArticleIDs) + account.markAsUnread(deltaUnreadArticleIDs) - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes) - group.enter() - account.markAsRead(deltaReadArticleIDs) { _ in - group.leave() - } - - group.notify(queue: DispatchQueue.main) { - completion() - } - } - } + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes) + account.markAsRead(deltaReadArticleIDs) + } catch let error { + self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)") + } - switch result { - case .success(let pendingArticleIDs): - process(pendingArticleIDs) - case .failure(let error): - self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)") - } - } - } + completion() + } + + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): + self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)") + } + } + } + } func syncStoryStarredState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) { guard let hashes = hashes else { @@ -372,37 +364,29 @@ extension NewsBlurAccountDelegate { database.selectPendingStarredStatusArticleIDs() { result in - @MainActor func process(_ pendingStoryHashes: Set) { + func process(_ pendingStoryHashes: Set) { - let newsBlurStarredStoryHashes = Set(hashes.map { $0.hash } ) - let updatableNewsBlurUnreadStoryHashes = newsBlurStarredStoryHashes.subtracting(pendingStoryHashes) + Task { @MainActor in + let newsBlurStarredStoryHashes = Set(hashes.map { $0.hash } ) + let updatableNewsBlurUnreadStoryHashes = newsBlurStarredStoryHashes.subtracting(pendingStoryHashes) - account.fetchStarredArticleIDs { articleIDsResult in - guard let currentStarredArticleIDs = try? articleIDsResult.get() else { - return - } + do { + let currentStarredArticleIDs = try await account.fetchStarredArticleIDs() - let group = DispatchGroup() - - // Mark articles as starred - let deltaStarredArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentStarredArticleIDs) - group.enter() - account.markAsStarred(deltaStarredArticleIDs) { _ in - group.leave() - } + // Mark articles as starred + let deltaStarredArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentStarredArticleIDs) + account.markAsStarred(deltaStarredArticleIDs) - // Mark articles as unstarred - let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes) - group.enter() - account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in - group.leave() - } + // Mark articles as unstarred + let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes) + account.markAsUnstarred(deltaUnstarredArticleIDs) + } catch let error { + self.logger.error("Sync story starred status failed: \(error.localizedDescription, privacy: .public)") + } - group.notify(queue: DispatchQueue.main) { - completion() - } - } - } + completion() + } + } switch result { case .success(let pendingArticleIDs): diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index 9eca30775..5b975e4c3 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -1078,102 +1078,82 @@ private extension ReaderAPIAccountDelegate { } - func syncArticleReadState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) { - guard let articleIDs = articleIDs else { - completion() - return - } + func syncArticleReadState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) { + guard let articleIDs = articleIDs else { + completion() + return + } - database.selectPendingReadStatusArticleIDs() { result in + database.selectPendingReadStatusArticleIDs() { result in @MainActor func process(_ pendingArticleIDs: Set) { - let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) - - account.fetchUnreadArticleIDs { articleIDsResult in - guard let currentUnreadArticleIDs = try? articleIDsResult.get() else { - return - } + Task { @MainActor in + let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) + + do { + let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs() - let group = DispatchGroup() - - // Mark articles as unread - let deltaUnreadArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentUnreadArticleIDs) - group.enter() - account.markAsUnread(deltaUnreadArticleIDs) { _ in - group.leave() - } + // Mark articles as unread + let deltaUnreadArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentUnreadArticleIDs) + account.markAsUnread(deltaUnreadArticleIDs) - // Mark articles as read - let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableReaderUnreadArticleIDs) - group.enter() - account.markAsRead(deltaReadArticleIDs) { _ in - group.leave() - } - - group.notify(queue: DispatchQueue.main) { - completion() - } - } - } - - switch result { - case .success(let pendingArticleIDs): - process(pendingArticleIDs) - case .failure(let error): - self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)") - } - - } - - } - - func syncArticleStarredState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) { - guard let articleIDs = articleIDs else { - completion() - return - } + // Mark articles as read + let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableReaderUnreadArticleIDs) + account.markAsRead(deltaReadArticleIDs) + } catch let error { + self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)") + } - database.selectPendingStarredStatusArticleIDs() { result in + completion() + } - @MainActor func process(_ pendingArticleIDs: Set) { - let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): + self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)") + } + } + } + } - account.fetchStarredArticleIDs { articleIDsResult in - guard let currentStarredArticleIDs = try? articleIDsResult.get() else { - return - } + func syncArticleStarredState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) { + guard let articleIDs = articleIDs else { + completion() + return + } - let group = DispatchGroup() - - // Mark articles as starred - let deltaStarredArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentStarredArticleIDs) - group.enter() - account.markAsStarred(deltaStarredArticleIDs) { _ in - group.leave() - } + database.selectPendingStarredStatusArticleIDs() { result in - // Mark articles as unstarred - let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableReaderUnreadArticleIDs) - group.enter() - account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in - group.leave() - } + func process(_ pendingArticleIDs: Set) { - group.notify(queue: DispatchQueue.main) { - completion() - } - } - } - - switch result { - case .success(let pendingArticleIDs): - process(pendingArticleIDs) - case .failure(let error): + Task { @MainActor in + do { + let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs) + + let currentStarredArticleIDs = try await account.fetchStarredArticleIDs() + + // Mark articles as starred + let deltaStarredArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentStarredArticleIDs) + account.markAsStarred(deltaStarredArticleIDs) + + // Mark articles as unstarred + let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableReaderUnreadArticleIDs) + account.markAsUnstarred(deltaUnstarredArticleIDs) + } catch let error { + self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)") + } + + completion() + } + } + + switch result { + case .success(let pendingArticleIDs): + process(pendingArticleIDs) + case .failure(let error): self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)") - } - - } - - } - + } + } + } } diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift index 17ef2e2ea..1ca10cb9f 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift @@ -239,13 +239,13 @@ public typealias ArticleStatusesResultBlock = (ArticleStatusesResult) -> Void // MARK: - Status /// Fetch the articleIDs of unread articles. - public func fetchUnreadArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) { - articlesTable.fetchUnreadArticleIDsAsync(completion) + public func fetchUnreadArticleIDsAsync() async throws -> Set { + return try await articlesTable.fetchUnreadArticleIDsAsync() } /// Fetch the articleIDs of starred articles. - public func fetchStarredArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) { - articlesTable.fetchStarredArticleIDsAsync(completion) + public func fetchStarredArticleIDsAsync() async throws -> Set { + return try await articlesTable.fetchStarredArticleIDsAsync() } /// Fetch articleIDs for articles that we should have, but don’t. These articles are either (starred) or (newer than the article cutoff date). diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift index 0b7800f7d..aba8807da 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift @@ -461,12 +461,12 @@ final class ArticlesTable: DatabaseTable { // MARK: - Statuses - func fetchUnreadArticleIDsAsync(_ completion: @escaping ArticleIDsCompletionBlock) { - statusesTable.fetchArticleIDsAsync(.read, false, completion) + func fetchUnreadArticleIDsAsync() async throws -> Set { + return try await statusesTable.fetchArticleIDsAsync(.read, false) } - func fetchStarredArticleIDsAsync(_ completion: @escaping ArticleIDsCompletionBlock) { - statusesTable.fetchArticleIDsAsync(.starred, true, completion) + func fetchStarredArticleIDsAsync() async throws -> Set { + return try await statusesTable.fetchArticleIDsAsync(.starred, true) } func fetchStarredArticleIDs() throws -> Set { diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/StatusesTable.swift b/ArticlesDatabase/Sources/ArticlesDatabase/StatusesTable.swift index c09ae1ed4..27f21df57 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/StatusesTable.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/StatusesTable.swift @@ -100,38 +100,38 @@ final class StatusesTable: DatabaseTable { func fetchStarredArticleIDs() throws -> Set { return try fetchArticleIDs("select articleID from statuses where starred=1;") } - - func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool, _ completion: @escaping ArticleIDsCompletionBlock) { - queue.runInDatabase { databaseResult in - func makeDatabaseCalls(_ database: FMDatabase) { - var sql = "select articleID from statuses where \(statusKey.rawValue)=" - sql += value ? "1" : "0" - sql += ";" + func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool) async throws -> Set { - guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { - DispatchQueue.main.async { - completion(.success(Set())) - } - return - } + return try await withCheckedThrowingContinuation { continuation in - let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) } - DispatchQueue.main.async { - completion(.success(articleIDs)) - } - } + Task { @MainActor in + queue.runInDatabase { databaseResult in - switch databaseResult { - case .success(let database): - makeDatabaseCalls(database) - case .failure(let databaseError): - DispatchQueue.main.async { - completion(.failure(databaseError)) - } - } - } - } + func makeDatabaseCalls(_ database: FMDatabase) { + var sql = "select articleID from statuses where \(statusKey.rawValue)=" + sql += value ? "1" : "0" + sql += ";" + + guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else { + continuation.resume(returning: Set()) + return + } + + let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) } + continuation.resume(returning: articleIDs) + } + + switch databaseResult { + case .success(let database): + makeDatabaseCalls(database) + case .failure(let databaseError): + continuation.resume(throwing: databaseError) + } + } + } + } + } func fetchArticleIDsForStatusesWithoutArticlesNewerThan(_ cutoffDate: Date, _ completion: @escaping ArticleIDsCompletionBlock) { queue.runInDatabase { databaseResult in