Make fetchStarredArticles an async call. Also have it respect subscribed-to feed IDs.

This commit is contained in:
Brent Simmons 2019-12-07 22:23:44 -08:00
parent a561ea9484
commit 0b87531f2f
6 changed files with 103 additions and 91 deletions

View File

@ -674,13 +674,13 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
} }
public func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) { public func fetchUnreadArticleIDs(_ callback: @escaping (Set<String>) -> Void) {
return database.fetchUnreadArticleIDsAsync(webFeedIDs: flattenedWebFeeds().webFeedIDs(), callback: callback) database.fetchUnreadArticleIDsAsync(webFeedIDs: flattenedWebFeeds().webFeedIDs(), callback: callback)
} }
public func fetchStarredArticleIDs() -> Set<String> { public func fetchStarredArticleIDs(_ callback: @escaping (Set<String>) -> Void) {
return database.fetchStarredArticleIDs() database.fetchStarredArticleIDsAsync(webFeedIDs: flattenedWebFeeds().webFeedIDs(), callback: callback)
} }
public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> { public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return database.fetchArticleIDsForStatusesWithoutArticles() return database.fetchArticleIDsForStatusesWithoutArticles()
} }

View File

@ -1224,27 +1224,27 @@ private extension FeedbinAccountDelegate {
} }
let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } )
let currentStarredArticleIDs = account.fetchStarredArticleIDs() account.fetchStarredArticleIDs { currentStarredArticleIDs in
// Mark articles as starred
// Mark articles as starred let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs)
let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs))
let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs)) account.update(markStarredArticles, statusKey: .starred, flag: true)
account.update(markStarredArticles, statusKey: .starred, flag: true)
// Save any starred statuses for articles we haven't yet received // Save any starred statuses for articles we haven't yet received
let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID })
let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs)
account.ensureStatuses(missingStarredArticleIDs, true, .starred, true) account.ensureStatuses(missingStarredArticleIDs, true, .starred, true)
// Mark articles as unstarred // Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs)
let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs)) let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs))
account.update(markUnstarredArticles, statusKey: .starred, flag: false) account.update(markUnstarredArticles, statusKey: .starred, flag: false)
// Save any unstarred statuses for articles we haven't yet received // Save any unstarred statuses for articles we haven't yet received
let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID })
let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs)
account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false) account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false)
}
} }
func deleteTagging(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) { func deleteTagging(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {

View File

@ -35,36 +35,36 @@ final class FeedlySetStarredArticlesOperation: FeedlyOperation {
let group = DispatchGroup() let group = DispatchGroup()
let remoteStarredArticleIds = allStarredEntryIdsProvider.entryIds let remoteStarredArticleIds = allStarredEntryIdsProvider.entryIds
let localStarredArticleIDs = account.fetchStarredArticleIDs() account.fetchStarredArticleIDs { localStarredArticleIDs in
// Mark articles as starred
// Mark articles as starred let deltaStarredArticleIDs = remoteStarredArticleIds.subtracting(localStarredArticleIDs)
let deltaStarredArticleIDs = remoteStarredArticleIds.subtracting(localStarredArticleIDs) let markStarredArticles = self.account.fetchArticles(.articleIDs(deltaStarredArticleIDs))
let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs)) self.account.update(markStarredArticles, statusKey: .starred, flag: true)
account.update(markStarredArticles, statusKey: .starred, flag: true)
// Save any starred statuses for articles we haven't yet received // Save any starred statuses for articles we haven't yet received
let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID })
let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs)
group.enter() group.enter()
account.ensureStatuses(missingStarredArticleIDs, true, .starred, true) { self.account.ensureStatuses(missingStarredArticleIDs, true, .starred, true) {
group.leave() group.leave()
} }
// Mark articles as unstarred // Mark articles as unstarred
let deltaUnstarredArticleIDs = localStarredArticleIDs.subtracting(remoteStarredArticleIds) let deltaUnstarredArticleIDs = localStarredArticleIDs.subtracting(remoteStarredArticleIds)
let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs)) let markUnstarredArticles = self.account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs))
account.update(markUnstarredArticles, statusKey: .starred, flag: false) self.account.update(markUnstarredArticles, statusKey: .starred, flag: false)
// Save any unstarred statuses for articles we haven't yet received // Save any unstarred statuses for articles we haven't yet received
let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID })
let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs)
group.enter() group.enter()
account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false) { self.account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false) {
group.leave() group.leave()
} }
group.notify(queue: .main) { group.notify(queue: .main) {
self.didFinish() self.didFinish()
}
} }
} }
} }

View File

@ -942,27 +942,27 @@ private extension ReaderAPIAccountDelegate {
} }
let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } ) let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } )
let currentStarredArticleIDs = account.fetchStarredArticleIDs() account.fetchStarredArticleIDs { currentStarredArticleIDs in
// Mark articles as starred
// Mark articles as starred let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs)
let deltaStarredArticleIDs = feedbinStarredArticleIDs.subtracting(currentStarredArticleIDs) let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs))
let markStarredArticles = account.fetchArticles(.articleIDs(deltaStarredArticleIDs)) account.update(markStarredArticles, statusKey: .starred, flag: true)
account.update(markStarredArticles, statusKey: .starred, flag: true)
// Save any starred statuses for articles we haven't yet received // Save any starred statuses for articles we haven't yet received
let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID }) let markStarredArticleIDs = Set(markStarredArticles.map { $0.articleID })
let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs) let missingStarredArticleIDs = deltaStarredArticleIDs.subtracting(markStarredArticleIDs)
account.ensureStatuses(missingStarredArticleIDs, true, .starred, true) account.ensureStatuses(missingStarredArticleIDs, true, .starred, true)
// Mark articles as unstarred // Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs) let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(feedbinStarredArticleIDs)
let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs)) let markUnstarredArticles = account.fetchArticles(.articleIDs(deltaUnstarredArticleIDs))
account.update(markUnstarredArticles, statusKey: .starred, flag: false) account.update(markUnstarredArticles, statusKey: .starred, flag: false)
// Save any unstarred statuses for articles we haven't yet received // Save any unstarred statuses for articles we haven't yet received
let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID }) let markUnstarredArticleIDs = Set(markUnstarredArticles.map { $0.articleID })
let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs) let missingUnstarredArticleIDs = deltaUnstarredArticleIDs.subtracting(markUnstarredArticleIDs)
account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false) account.ensureStatuses(missingUnstarredArticleIDs, true, .starred, false)
}
} }

View File

@ -154,15 +154,16 @@ public final class ArticlesDatabase {
// MARK: - Status // MARK: - Status
/// Fetch the articleIDs of unread articles for feeds specified by webFeedIDs. /// Fetch the articleIDs of unread articles in feeds specified by webFeedIDs.
public func fetchUnreadArticleIDsAsync(webFeedIDs: Set<String>, callback: @escaping (Set<String>) -> Void) { public func fetchUnreadArticleIDsAsync(webFeedIDs: Set<String>, callback: @escaping (Set<String>) -> Void) {
articlesTable.fetchUnreadArticleIDsAsync(webFeedIDs, callback) articlesTable.fetchUnreadArticleIDsAsync(webFeedIDs, callback)
} }
public func fetchStarredArticleIDs() -> Set<String> { /// Fetch the articleIDs of starred articles in feeds specified by webFeedIDs.
return articlesTable.fetchStarredArticleIDs() public func fetchStarredArticleIDsAsync(webFeedIDs: Set<String>, callback: @escaping (Set<String>) -> Void) {
articlesTable.fetchStarredArticleIDsAsync(webFeedIDs, callback)
} }
public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> { public func fetchArticleIDsForStatusesWithoutArticles() -> Set<String> {
return articlesTable.fetchArticleIDsForStatusesWithoutArticles() return articlesTable.fetchArticleIDsForStatusesWithoutArticles()
} }

View File

@ -401,28 +401,12 @@ final class ArticlesTable: DatabaseTable {
// MARK: - Statuses // MARK: - Statuses
func fetchUnreadArticleIDs() -> Set<String>{ func fetchUnreadArticleIDsAsync(_ webFeedIDs: Set<String>, _ callback: @escaping (Set<String>) -> Void) {
return statusesTable.fetchUnreadArticleIDs() fetchArticleIDsAsync(.read, false, webFeedIDs, callback)
} }
func fetchUnreadArticleIDsAsync(_ webFeedIDs: Set<String>, _ callback: @escaping (Set<String>) -> Void) { func fetchStarredArticleIDsAsync(_ webFeedIDs: Set<String>, _ callback: @escaping (Set<String>) -> Void) {
queue.runInDatabase { database in fetchArticleIDsAsync(.starred, true, webFeedIDs, callback)
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let sql = "select articleID from articles natural join statuses where feedID in \(placeholders) and read=0 and userDeleted=0;"
let parameters = Array(webFeedIDs) as [Any]
guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else {
DispatchQueue.main.async {
callback(Set<String>())
}
return
}
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
DispatchQueue.main.async {
callback(articleIDs)
}
}
} }
func fetchStarredArticleIDs() -> Set<String> { func fetchStarredArticleIDs() -> Set<String> {
@ -668,6 +652,33 @@ private extension ArticlesTable {
return articlesWithResultSet(resultSet, database) return articlesWithResultSet(resultSet, database)
} }
func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool, _ webFeedIDs: Set<String>, _ callback: @escaping (Set<String>) -> Void) {
queue.runInDatabase { database in
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
var sql = "select articleID from articles natural join statuses where feedID in \(placeholders) and \(statusKey.rawValue)="
sql += value ? "1" : "0"
if statusKey != .userDeleted {
sql += " and userDeleted=0"
}
sql += ";"
let parameters = Array(webFeedIDs) as [Any]
guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else {
DispatchQueue.main.async {
callback(Set<String>())
}
return
}
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
DispatchQueue.main.async {
callback(articleIDs)
}
}
}
// MARK: - Saving Parsed Items // MARK: - Saving Parsed Items
func callUpdateArticlesCompletionBlock(_ newArticles: Set<Article>?, _ updatedArticles: Set<Article>?, _ completion: @escaping UpdateArticlesCompletionBlock) { func callUpdateArticlesCompletionBlock(_ newArticles: Set<Article>?, _ updatedArticles: Set<Article>?, _ completion: @escaping UpdateArticlesCompletionBlock) {