diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index db7f23fd3..489182245 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -718,6 +718,10 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, database.fetchStarredAndUnreadCount(for: flattenedWebFeeds().webFeedIDs(), completion: completion) } + public func fetchCountForStarredArticles() throws -> Int { + return try database.fetchStarredArticlesCount(flattenedWebFeeds().webFeedIDs()) + } + public func fetchUnreadArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) { database.fetchUnreadArticleIDsAsync(completion: completion) } diff --git a/Account/Sources/Account/AccountManager.swift b/Account/Sources/Account/AccountManager.swift index bc1911947..07bd893d9 100644 --- a/Account/Sources/Account/AccountManager.swift +++ b/Account/Sources/Account/AccountManager.swift @@ -393,6 +393,17 @@ public final class AccountManager: UnreadCountProvider { } } } + + // MARK: - Fetching Article Counts + + public func fetchCountForStarredArticles() throws -> Int { + precondition(Thread.isMainThread) + var count = 0 + for account in activeAccounts { + count += try account.fetchCountForStarredArticles() + } + return count + } // MARK: - Caches diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift index 5a7355201..fae1df9b2 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift @@ -114,6 +114,10 @@ public final class ArticlesDatabase { return try articlesTable.fetchStarredArticles(webFeedIDs, limit) } + public func fetchStarredArticlesCount(_ webFeedIDs: Set) throws -> Int { + return try articlesTable.fetchStarredArticlesCount(webFeedIDs) + } + public func fetchArticlesMatching(_ searchString: String, _ webFeedIDs: Set) throws -> Set
{ return try articlesTable.fetchArticlesMatching(searchString, webFeedIDs) } diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift index ab7655474..a64be83dc 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift @@ -32,7 +32,8 @@ final class ArticlesTable: DatabaseTable { let articleCutoffDate = Date().bySubtracting(days: 90) private typealias ArticlesFetchMethod = (FMDatabase) -> Set
- + private typealias ArticlesCountFetchMethod = (FMDatabase) -> Int + init(name: String, accountID: String, queue: DatabaseQueue, retentionStyle: ArticlesDatabase.RetentionStyle) { self.name = name @@ -103,6 +104,10 @@ final class ArticlesTable: DatabaseTable { fetchArticlesAsync({ self.fetchStarredArticles(webFeedIDs, limit, $0) }, completion) } + func fetchStarredArticlesCount(_ webFeedIDs: Set) throws -> Int { + return try fetchArticlesCount{ self.fetchStarredArticlesCount(webFeedIDs, $0) } + } + // MARK: - Fetching Search Articles func fetchArticlesMatching(_ searchString: String) throws -> Set
{ @@ -671,6 +676,23 @@ private extension ArticlesTable { return articles } + private func fetchArticlesCount(_ fetchMethod: @escaping ArticlesCountFetchMethod) throws -> Int { + var articlesCount = 0 + var error: DatabaseError? = nil + queue.runInDatabaseSync { databaseResult in + switch databaseResult { + case .success(let database): + articlesCount = fetchMethod(database) + case .failure(let databaseError): + error = databaseError + } + } + if let error = error { + throw(error) + } + return articlesCount + } + private func fetchArticlesAsync(_ fetchMethod: @escaping ArticlesFetchMethod, _ completion: @escaping ArticleSetResultBlock) { queue.runInDatabase { databaseResult in @@ -745,6 +767,19 @@ private extension ArticlesTable { return articlesWithSQL(sql, parameters, database) } + func fetchArticleCountsWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject]) -> Int { + let sql = "select count(*) from articles natural join statuses where \(whereClause);" + guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else { + return 0 + } + var articlesCount = 0 + if resultSet.next() { + articlesCount = resultSet.long(forColumnIndex: 0) + } + resultSet.close() + return articlesCount + } + func fetchArticlesMatching(_ searchString: String, _ database: FMDatabase) -> Set
{ let sql = "select rowid from search where search match ?;" let sqlSearchString = sqliteSearchString(with: searchString) @@ -840,20 +875,31 @@ private extension ArticlesTable { return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters) } - func fetchStarredArticles(_ webFeedIDs: Set, _ limit: Int?, _ database: FMDatabase) -> Set
{ - // select * from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1; - if webFeedIDs.isEmpty { - return Set
() - } - let parameters = webFeedIDs.map { $0 as AnyObject } - let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))! - var whereClause = "feedID in \(placeholders) and starred=1" - if let limit = limit { - whereClause.append(" order by coalesce(datePublished, dateModified, dateArrived) desc limit \(limit)") - } - return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters) - } - + func fetchStarredArticles(_ webFeedIDs: Set, _ limit: Int?, _ database: FMDatabase) -> Set
{ + // select * from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1; + if webFeedIDs.isEmpty { + return Set
() + } + let parameters = webFeedIDs.map { $0 as AnyObject } + let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))! + var whereClause = "feedID in \(placeholders) and starred=1" + if let limit = limit { + whereClause.append(" order by coalesce(datePublished, dateModified, dateArrived) desc limit \(limit)") + } + return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters) + } + + func fetchStarredArticlesCount(_ webFeedIDs: Set, _ database: FMDatabase) -> Int { + // select count from articles natural join statuses where feedID in ('http://ranchero.com/xml/rss.xml') and starred=1; + if webFeedIDs.isEmpty { + return 0 + } + let parameters = webFeedIDs.map { $0 as AnyObject } + let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))! + let whereClause = "feedID in \(placeholders) and starred=1" + return fetchArticleCountsWithWhereClause(database, whereClause: whereClause, parameters: parameters) + } + func fetchArticlesMatching(_ searchString: String, _ webFeedIDs: Set, _ database: FMDatabase) -> Set
{ let articles = fetchArticlesMatching(searchString, database) // TODO: include the feedIDs in the SQL rather than filtering here. diff --git a/Shared/Widget/WidgetDataEncoder.swift b/Shared/Widget/WidgetDataEncoder.swift index 86c46be3b..db830eb8d 100644 --- a/Shared/Widget/WidgetDataEncoder.swift +++ b/Shared/Widget/WidgetDataEncoder.swift @@ -73,7 +73,7 @@ public final class WidgetDataEncoder { let latestData = WidgetData(currentUnreadCount: SmartFeedsController.shared.unreadFeed.unreadCount, currentTodayCount: SmartFeedsController.shared.todayFeed.unreadCount, - currentStarredCount: try! SmartFeedsController.shared.starredFeed.fetchArticles().count, + currentStarredCount: try AccountManager.shared.fetchCountForStarredArticles(), unreadArticles: unread, starredArticles: starred, todayArticles:today,