diff --git a/Frameworks/Database/ArticlesTable.swift b/Frameworks/Database/ArticlesTable.swift index 76bf6edf4..5dc006ecf 100644 --- a/Frameworks/Database/ArticlesTable.swift +++ b/Frameworks/Database/ArticlesTable.swift @@ -24,6 +24,9 @@ final class ArticlesTable: DatabaseTable { private let tagsLookupTable: DatabaseLookupTable private let articleCache = ArticleCache() + // TODO: update articleCutoffDate as time passes and based on user preferences. + private var articleCutoffDate = NSDate.rs_dateWithNumberOfDays(inThePast: 3 * 31)! + init(name: String, account: Account, queue: RSDatabaseQueue) { self.name = name @@ -206,10 +209,25 @@ private extension ArticlesTable { func fetchArticlesWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject]) -> Set
{ - let sql = "select * from articles natural join statuses where \(whereClause);" - return articlesWithSQL(sql, parameters, database) + // Don’t fetch articles that shouldn’t appear in the UI. The rules: + // * Must not be deleted. + // * Must be either 1) starred or 2) dateArrived must be newer than cutoff date. + + let sql = "select * from articles natural join statuses where \(whereClause) and userDeleted=0 and (starred=1 or dateArrived>?);" + return articlesWithSQL(sql, parameters + [articleCutoffDate as AnyObject], database) } + func fetchUnreadCount(_ feedID: String, _ database: FMDatabase) -> Int { + + // Count only the articles that would appear in the UI. + // * Must be unread. + // * Must not be deleted. + // * Must be either 1) starred or 2) dateArrived must be newer than cutoff date. + + let sql = "select count(*) from articles natural join statuses where feedID=? and read=0 and userDeleted=0 and (starred=1 or dateArrived>?);" + return numberWithSQLAndParameters(sql, [feedID, articleCutoffDate], in: database) + } + func fetchArticlesForFeedID(_ feedID: String, database: FMDatabase) -> Set
{ return fetchArticlesWithWhereClause(database, whereClause: "articles.feedID = ?", parameters: [feedID as AnyObject]) diff --git a/Frameworks/Database/Database.swift b/Frameworks/Database/Database.swift index ca5d2a863..38a8f032f 100644 --- a/Frameworks/Database/Database.swift +++ b/Frameworks/Database/Database.swift @@ -60,7 +60,6 @@ public final class Database { // MARK: - Unread Counts - public func fetchUnreadCounts(for feeds: Set, completion: @escaping UnreadCountCompletionBlock) { return articlesTable.fetchUnreadCounts(feeds, completion) @@ -314,31 +313,6 @@ private extension Database { // return numberWithSQLAndParameters(sql, parameters: [feedID], database) // } // -// func unreadCount(_ feedID: String, _ database: FMDatabase) -> Int { -// -// let totalNumberOfArticles = numberOfArticles(feedID, database) -// -// if totalNumberOfArticles <= minimumNumberOfArticles { -// return unreadCountIgnoringCutoffDate(feedID, database) -// } -// return unreadCountRespectingCutoffDate(feedID, database) -// } -// -// func unreadCountIgnoringCutoffDate(_ feedID: String, _ database: FMDatabase) -> Int { -// -// let sql = "select count(*) from articles natural join statuses where feedID=? and read=0 and userDeleted=0;" -// logSQL(sql) -// -// return numberWithSQLAndParameters(sql, parameters: [feedID], database) -// } -// -// func unreadCountRespectingCutoffDate(_ feedID: String, _ database: FMDatabase) -> Int { -// -// let sql = "select count(*) from articles natural join statuses where feedID=? and read=0 and userDeleted=0 and (starred=1 or dateArrived>?);" -// logSQL(sql) -// -// return numberWithSQLAndParameters(sql, parameters: [feedID, articleArrivalCutoffDate], database) -// } // // // MARK: Filtering out old articles // diff --git a/Frameworks/Database/Database.xcodeproj/project.pbxproj b/Frameworks/Database/Database.xcodeproj/project.pbxproj index 198ced1cd..0b191d7e0 100644 --- a/Frameworks/Database/Database.xcodeproj/project.pbxproj +++ b/Frameworks/Database/Database.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */; }; 846146271F0ABC7B00870CB3 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846146241F0ABC7400870CB3 /* RSParser.framework */; }; 846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846FB36A1F4A937B00EAB81D /* Feed+Database.swift */; }; + 848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */; }; 84BB4BA21F119C5400858766 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84BB4B981F119C4900858766 /* RSCore.framework */; }; 84BB4BA91F11A32800858766 /* TagsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BB4BA81F11A32800858766 /* TagsTable.swift */; }; 84D0DEA11F4A429800073503 /* String+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D0DEA01F4A429800073503 /* String+Database.swift */; }; @@ -125,6 +126,7 @@ 8455807B1F0C0DBD003CCFA1 /* Attachment+Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Attachment+Database.swift"; path = "Extensions/Attachment+Database.swift"; sourceTree = ""; }; 8461461E1F0ABC7300870CB3 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = ""; }; 846FB36A1F4A937B00EAB81D /* Feed+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Feed+Database.swift"; path = "Extensions/Feed+Database.swift"; sourceTree = ""; }; + 848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountDictionary.swift; sourceTree = ""; }; 84BB4B8F1F119C4900858766 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = ""; }; 84BB4BA81F11A32800858766 /* TagsTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagsTable.swift; sourceTree = ""; }; 84D0DEA01F4A429800073503 /* String+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "String+Database.swift"; path = "Extensions/String+Database.swift"; sourceTree = ""; }; @@ -172,6 +174,7 @@ 84F20F8E1F180D8700D8E682 /* AuthorsTable.swift */, 84BB4BA81F11A32800858766 /* TagsTable.swift */, 840405CE1F1A963700DF0296 /* AttachmentsTable.swift */, + 848AD2951F58A91E004FB0EC /* UnreadCountDictionary.swift */, 8461462A1F0AC44100870CB3 /* Extensions */, 84E156EF1F0AB81F00F8CC05 /* CreateStatements.sql */, 84E156E81F0AB75600F8CC05 /* Info.plist */, @@ -471,6 +474,7 @@ 846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */, 84D0DEA11F4A429800073503 /* String+Database.swift in Sources */, 843CB9961F34174100EE6581 /* Author+Database.swift in Sources */, + 848AD2961F58A91E004FB0EC /* UnreadCountDictionary.swift in Sources */, 845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */, 845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */, 8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */, diff --git a/Frameworks/Database/UnreadCountDictionary.swift b/Frameworks/Database/UnreadCountDictionary.swift new file mode 100644 index 000000000..16b731f9b --- /dev/null +++ b/Frameworks/Database/UnreadCountDictionary.swift @@ -0,0 +1,30 @@ +// +// UnreadCountDictionary.swift +// Database +// +// Created by Brent Simmons on 8/31/17. +// Copyright © 2017 Ranchero Software. All rights reserved. +// + +import Foundation +import Data + +public struct UnreadCountDictionary { + + private var dictionary = [String: Int]() + + subscript(_ feedID: String) -> Int? { + get { + return dictionary[feedID] + } + set { + dictionary[feedID] = newValue + } + } + + public subscript(_ feed: Feed) -> Int? { + get { + return dictionary[feed.feedID] + } + } +} diff --git a/Frameworks/RSDatabase/DatabaseTable.swift b/Frameworks/RSDatabase/DatabaseTable.swift index a390b5ad9..e50596704 100644 --- a/Frameworks/RSDatabase/DatabaseTable.swift +++ b/Frameworks/RSDatabase/DatabaseTable.swift @@ -80,18 +80,20 @@ public extension DatabaseTable { // MARK: Counting - func numberWithCountResultSet(_ resultSet: FMResultSet?) -> Int { + func numberWithCountResultSet(_ resultSet: FMResultSet) -> Int { - if let resultSet = resultSet, resultSet.next() { - return Int(resultSet.int(forColumnIndex: 0)) + guard resultSet.next() else { + return 0 } - return 0 + return Int(resultSet.int(forColumnIndex: 0)) } func numberWithSQLAndParameters(_ sql: String, _ parameters: [Any], in database: FMDatabase) -> Int { - let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) - return numberWithCountResultSet(resultSet) + if let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) { + return numberWithCountResultSet(resultSet) + } + return 0 } // MARK: Mapping