Implement updated retention policy.

This commit is contained in:
Brent Simmons 2020-04-18 20:18:32 -07:00
parent d2812fa132
commit b2b000dd2e
5 changed files with 30 additions and 52 deletions

View File

@ -146,7 +146,7 @@ public final class ArticlesDatabase {
/// Fetch all non-zero unread counts.
public func fetchAllUnreadCounts(_ completion: @escaping UnreadCountDictionaryCompletionBlock) {
let operation = FetchAllUnreadCountsOperation(databaseQueue: queue, cutoffDate: articlesTable.articleCutoffDate)
let operation = FetchAllUnreadCountsOperation(databaseQueue: queue)
operationQueue.cancelOperations(named: operation.name!)
operation.completionBlock = { operation in
let fetchOperation = operation as! FetchAllUnreadCountsOperation
@ -167,7 +167,7 @@ public final class ArticlesDatabase {
/// Fetch non-zero unread counts for given webFeedIDs.
public func fetchUnreadCounts(for webFeedIDs: Set<String>, _ completion: @escaping UnreadCountDictionaryCompletionBlock) {
let operation = FetchUnreadCountsForFeedsOperation(webFeedIDs: webFeedIDs, databaseQueue: queue, cutoffDate: articlesTable.articleCutoffDate)
let operation = FetchUnreadCountsForFeedsOperation(webFeedIDs: webFeedIDs, databaseQueue: queue)
operation.completionBlock = { operation in
let fetchOperation = operation as! FetchUnreadCountsForFeedsOperation
completion(fetchOperation.result)
@ -265,9 +265,11 @@ public final class ArticlesDatabase {
// MARK: - Cleanup
// These are to be used only at startup. These are to prevent the database from growing forever.
/// Calls the various clean-up functions.
/// Calls the various clean-up functions. To be used only at startup.
///
/// This prevents the database from growing forever. If we didnt do this:
/// 1) The database would grow to an inordinate size, and
/// 2) the app would become very slow.
public func cleanupDatabaseAtStartup(subscribedToWebFeedIDs: Set<String>) {
if retentionStyle == .syncSystem {
articlesTable.deleteOldArticles()

View File

@ -181,7 +181,7 @@ final class ArticlesTable: DatabaseTable {
// 1. Ensure statuses for all the incoming articles.
// 2. Create incoming articles with parsedItems.
// 3. [Deleted - no longer needed]
// 3. [Deleted - this step is no longer needed]
// 4. Fetch all articles for the feed.
// 5. Create array of Articles not in database and save them.
// 6. Create array of updated Articles and save whats changed.
@ -494,6 +494,8 @@ final class ArticlesTable: DatabaseTable {
/// we do this in a careful way: delete articles older than a year,
/// check to see how much time has passed, then decide whether or not to continue.
/// Repeat for successively more-recent dates.
///
/// Returns `true` if it deleted old articles all the way up to the 90 day cutoff date.
func deleteOldArticles() {
precondition(retentionStyle == .syncSystem)
@ -537,10 +539,10 @@ final class ArticlesTable: DatabaseTable {
switch self.retentionStyle {
case .syncSystem:
sql = "select articleID from statuses where dateArrived<? and read=1 and starred=0 and articleID not in (select articleID from articles);"
sql = "delete from statuses where dateArrived<? and read=1 and starred=0 and articleID not in (select articleID from articles);"
cutoffDate = Date().bySubtracting(days: 180)
case .feedBased:
sql = "select articleID from statuses where dateArrived<? and starred=0 and articleID not in (select articleID from articles);"
sql = "delete from statuses where dateArrived<? and starred=0 and articleID not in (select articleID from articles);"
cutoffDate = Date().bySubtracting(days: 30)
}
@ -672,31 +674,11 @@ private extension ArticlesTable {
return cachedArticles.union(articlesWithFetchedAuthors)
}
func fetchArticlesWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject], withLimits: Bool) -> Set<Article> {
// Dont fetch articles that shouldnt appear in the UI. The rules:
// * Must not be deleted.
// * Must be either 1) starred or 2) dateArrived must be newer than cutoff date.
if withLimits {
let sql = "select * from articles natural join statuses where \(whereClause) and (starred=1 or dateArrived>?);"
return articlesWithSQL(sql, parameters + [articleCutoffDate as AnyObject], database)
}
else {
let sql = "select * from articles natural join statuses where \(whereClause);"
return articlesWithSQL(sql, parameters, database)
}
func fetchArticlesWithWhereClause(_ database: FMDatabase, whereClause: String, parameters: [AnyObject]) -> Set<Article> {
let sql = "select * from articles natural join statuses where \(whereClause);"
return articlesWithSQL(sql, parameters, database)
}
// func fetchUnreadCount(_ webFeedID: 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 (starred=1 or dateArrived>?);"
// return numberWithSQLAndParameters(sql, [webFeedID, articleCutoffDate], in: database)
// }
func fetchArticlesMatching(_ searchString: String, _ database: FMDatabase) -> Set<Article> {
let sql = "select rowid from search where search match ?;"
let sqlSearchString = sqliteSearchString(with: searchString)
@ -712,7 +694,7 @@ private extension ArticlesTable {
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(searchRowIDs.count))!
let whereClause = "searchRowID in \(placeholders)"
let parameters: [AnyObject] = Array(searchRowIDs) as [AnyObject]
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: true)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func sqliteSearchString(with searchString: String) -> String {
@ -785,7 +767,7 @@ private extension ArticlesTable {
let parameters = webFeedIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let whereClause = "feedID in \(placeholders)"
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: true)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchUnreadArticles(_ webFeedIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
@ -796,11 +778,11 @@ private extension ArticlesTable {
let parameters = webFeedIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let whereClause = "feedID in \(placeholders) and read=0"
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: true)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchArticlesForFeedID(_ webFeedID: String, withLimits: Bool, _ database: FMDatabase) -> Set<Article> {
return fetchArticlesWithWhereClause(database, whereClause: "articles.feedID = ?", parameters: [webFeedID as AnyObject], withLimits: withLimits)
return fetchArticlesWithWhereClause(database, whereClause: "articles.feedID = ?", parameters: [webFeedID as AnyObject])
}
func fetchArticles(articleIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
@ -810,7 +792,7 @@ private extension ArticlesTable {
let parameters = articleIDs.map { $0 as AnyObject }
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(articleIDs.count))!
let whereClause = "articleID in \(placeholders)"
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: false)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchArticlesSince(_ webFeedIDs: Set<String>, _ cutoffDate: Date, _ database: FMDatabase) -> Set<Article> {
@ -823,7 +805,7 @@ private extension ArticlesTable {
let parameters = webFeedIDs.map { $0 as AnyObject } + [cutoffDate as AnyObject, cutoffDate as AnyObject]
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let whereClause = "feedID in \(placeholders) and (datePublished > ? or (datePublished is null and dateArrived > ?))"
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: false)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchStarredArticles(_ webFeedIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {
@ -834,7 +816,7 @@ private extension ArticlesTable {
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 fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters, withLimits: false)
return fetchArticlesWithWhereClause(database, whereClause: whereClause, parameters: parameters)
}
func fetchArticlesMatching(_ searchString: String, _ webFeedIDs: Set<String>, _ database: FMDatabase) -> Set<Article> {

View File

@ -22,11 +22,9 @@ public final class FetchAllUnreadCountsOperation: MainThreadOperation {
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
private let queue: DatabaseQueue
private let cutoffDate: Date
init(databaseQueue: DatabaseQueue, cutoffDate: Date) {
init(databaseQueue: DatabaseQueue) {
self.queue = databaseQueue
self.cutoffDate = cutoffDate
}
public func run() {
@ -49,9 +47,9 @@ public final class FetchAllUnreadCountsOperation: MainThreadOperation {
private extension FetchAllUnreadCountsOperation {
func fetchUnreadCounts(_ database: FMDatabase) {
let sql = "select distinct feedID, count(*) from articles natural join statuses where read=0 and (starred=1 or dateArrived>?) group by feedID;"
let sql = "select distinct feedID, count(*) from articles natural join statuses where read=0 group by feedID;"
guard let resultSet = database.executeQuery(sql, withArgumentsIn: [cutoffDate]) else {
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
informOperationDelegateOfCompletion()
return
}

View File

@ -52,9 +52,9 @@ public final class FetchFeedUnreadCountOperation: MainThreadOperation {
private extension FetchFeedUnreadCountOperation {
func fetchUnreadCount(_ database: FMDatabase) {
let sql = "select count(*) from articles natural join statuses where feedID=? and read=0 and (starred=1 or dateArrived>?);"
let sql = "select count(*) from articles natural join statuses where feedID=? and read=0;"
guard let resultSet = database.executeQuery(sql, withArgumentsIn: [webFeedID, cutoffDate]) else {
guard let resultSet = database.executeQuery(sql, withArgumentsIn: [webFeedID]) else {
informOperationDelegateOfCompletion()
return
}

View File

@ -23,13 +23,11 @@ public final class FetchUnreadCountsForFeedsOperation: MainThreadOperation {
public var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock?
private let queue: DatabaseQueue
private let cutoffDate: Date
private let webFeedIDs: Set<String>
init(webFeedIDs: Set<String>, databaseQueue: DatabaseQueue, cutoffDate: Date) {
init(webFeedIDs: Set<String>, databaseQueue: DatabaseQueue) {
self.webFeedIDs = webFeedIDs
self.queue = databaseQueue
self.cutoffDate = cutoffDate
}
public func run() {
@ -53,11 +51,9 @@ private extension FetchUnreadCountsForFeedsOperation {
func fetchUnreadCounts(_ database: FMDatabase) {
let placeholders = NSString.rs_SQLValueList(withPlaceholders: UInt(webFeedIDs.count))!
let sql = "select distinct feedID, count(*) from articles natural join statuses where feedID in \(placeholders) and read=0 and (starred=1 or dateArrived>?) group by feedID;"
let sql = "select distinct feedID, count(*) from articles natural join statuses where feedID in \(placeholders) and read=0 group by feedID;"
var parameters = [Any]()
parameters += Array(webFeedIDs) as [Any]
parameters += [cutoffDate] as [Any]
let parameters = Array(webFeedIDs) as [Any]
guard let resultSet = database.executeQuery(sql, withArgumentsIn: parameters) else {
informOperationDelegateOfCompletion()