Do things. I forget what, since it was yesterday or whatever. Progress, anyway.

This commit is contained in:
Brent Simmons 2017-07-31 18:39:42 -07:00
parent c76d42b42f
commit b756f39cbe
3 changed files with 65 additions and 53 deletions

View File

@ -36,6 +36,11 @@ public final class ArticleStatus: Hashable {
self.hashValue = articleID.hashValue self.hashValue = articleID.hashValue
} }
public convenience init(articleID: String, dateArrived: Date) {
init(articleID: articleID, read: false, starred: false, userDeleted: false, dateArrived: dateArrived, accountInfo: nil)
}
public func boolStatus(forKey key: String) -> Bool { public func boolStatus(forKey key: String) -> Bool {
if let articleStatusKey = ArticleStatusKey(rawValue: key) { if let articleStatusKey = ArticleStatusKey(rawValue: key) {

View File

@ -46,6 +46,10 @@ final class StatusesTable: DatabaseTable {
func ensureStatusesForParsedArticles(_ parsedArticles: [ParsedItem], _ callback: @escaping RSVoidCompletionBlock) { func ensureStatusesForParsedArticles(_ parsedArticles: [ParsedItem], _ callback: @escaping RSVoidCompletionBlock) {
// 1. Check cache for statuses
// 2. Fetch statuses not found in cache
// 3. Create, save, and cache statuses not found in database
var articleIDs = Set(parsedArticles.map { $0.articleID }) var articleIDs = Set(parsedArticles.map { $0.articleID })
articleIDs = articleIDsMissingStatuses(articleIDs) articleIDs = articleIDsMissingStatuses(articleIDs)
if articleIDs.isEmpty { if articleIDs.isEmpty {
@ -62,11 +66,17 @@ final class StatusesTable: DatabaseTable {
self.cache.addObjectsNotCached(Array(statuses)) self.cache.addObjectsNotCached(Array(statuses))
let newArticleIDs = self.articleIDsMissingStatuses(articleIDs) let newArticleIDs = self.articleIDsMissingStatuses(articleIDs)
self.createStatusForNewArticleIDs(newArticleIDs) if !newArticleIDs.isEmpty {
self.createAndSaveStatusesForArticleIDs(newArticleIDs)
}
callback() callback()
} }
} }
} }
}
private extension StatusesTable {
func assertNoMissingStatuses(_ articles: Set<Article>) { func assertNoMissingStatuses(_ articles: Set<Article>) {
@ -77,30 +87,6 @@ final class StatusesTable: DatabaseTable {
} }
} }
} }
}
private extension StatusesTable {
// MARK: Marking
func markArticleStatuses(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
// Ignore the statuses where status.[statusKey] == flag. Update the remainder and save in database.
var articleIDs = Set<String>()
statuses.forEach { (oneStatus) in
if oneStatus.boolStatus(forKey: statusKey) != flag {
oneStatus.setBoolStatus(flag, forKey: statusKey)
articleIDs.insert(oneStatus.articleID)
}
}
if !articleIDs.isEmpty {
updateArticleStatusesInDatabase(articleIDs, statusKey: statusKey, flag: flag)
}
}
// MARK: Fetching // MARK: Fetching
@ -126,12 +112,27 @@ private extension StatusesTable {
return statuses return statuses
} }
// MARK: Saving // MARK: Updating
func saveStatuses(_ statuses: Set<ArticleStatus>) { func markArticleStatuses(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
let statusArray = statuses.map { $0.databaseDictionary() } // Ignore the statuses where status.[statusKey] == flag. Update the remainder and save in database.
insertRows(statusArray, insertType: .orIgnore)
var articleIDsToUpdate = Set<String>()
statuses.forEach { (oneStatus) in
if oneStatus.boolStatus(forKey: statusKey) == flag {
return
}
oneStatus.setBoolStatus(flag, forKey: statusKey)
articleIDsToUpdate.insert(oneStatus.articleID)
}
if !articleIDsToUpdate.isEmpty {
updateArticleStatusesInDatabase(articleIDsToUpdate, statusKey: statusKey, flag: flag)
}
} }
private func updateArticleStatusesInDatabase(_ articleIDs: Set<String>, statusKey: String, flag: Bool) { private func updateArticleStatusesInDatabase(_ articleIDs: Set<String>, statusKey: String, flag: Bool) {
@ -141,30 +142,26 @@ private extension StatusesTable {
// MARK: Creating // MARK: Creating
func createStatusForNewArticleIDs(_ articleIDs: Set<String>) { func saveStatuses(_ statuses: Set<ArticleStatus>) {
let statusArray = statuses.map { $0.databaseDictionary() }
insertRows(statusArray, insertType: .orIgnore)
}
func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>) {
let now = Date() let now = Date()
let statuses = articleIDs.map { (oneArticleID) -> ArticleStatus in let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
return ArticleStatus(articleID: oneArticleID, read: false, starred: false, userDeleted: false, dateArrived: now)
}
cache.addObjectsNotCached(statuses) cache.addObjectsNotCached(statuses)
queue.update { (database: FMDatabase!) -> Void in saveStatuses(Set(statuses))
let falseValue = NSNumber(value: false)
articleIDs.forEach { (oneArticleID) in
let _ = database.executeUpdate("insert or ignore into statuses (read, articleID, starred, userDeleted, dateArrived) values (?, ?, ?, ?, ?)", withArgumentsIn:[falseValue, oneArticleID as NSString, falseValue, falseValue, now])
}
}
} }
// MARK: Utilities // MARK: Utilities
func articleIDsMissingStatuses(_ articleIDs: Set<String>) -> Set<String> { func articleIDsMissingStatuses(_ articleIDs: Set<String>) -> Set<String> {
return Set(articleIDs.filter { cache[$0] == nil }) return Set(articleIDs.filter { !objectWithIDIsCached[$0] })
} }
} }

View File

@ -8,6 +8,8 @@
import Foundation import Foundation
// Not thread-safe.
public final class ObjectCache<T> { public final class ObjectCache<T> {
private let keyPathForID: KeyPath<T,String> private let keyPathForID: KeyPath<T,String>
@ -60,7 +62,7 @@ public final class ObjectCache<T> {
// When an object is not already cached, cache it, // When an object is not already cached, cache it,
// then consider that version the unique version. // then consider that version the unique version.
return objects.map({ (object) -> T in return objects.map { (object) -> T in
let identifier = identifierForObject(object) let identifier = identifierForObject(object)
if let cachedObject = self[identifier] { if let cachedObject = self[identifier] {
@ -68,7 +70,15 @@ public final class ObjectCache<T> {
} }
add(object) add(object)
return object return object
}) }
}
public func objectWithIDIsCached(_ identifier: String) -> Bool {
if let _ = self[identifier] {
return true
}
return false
} }
public subscript(_ identifier: String) -> T? { public subscript(_ identifier: String) -> T? {