mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-25 01:01:21 +01:00
Do things. I forget what, since it was yesterday or whatever. Progress, anyway.
This commit is contained in:
parent
c76d42b42f
commit
b756f39cbe
@ -35,7 +35,12 @@ public final class ArticleStatus: Hashable {
|
||||
self.accountInfo = accountInfo
|
||||
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 {
|
||||
|
||||
if let articleStatusKey = ArticleStatusKey(rawValue: key) {
|
||||
|
@ -45,7 +45,11 @@ final class StatusesTable: DatabaseTable {
|
||||
}
|
||||
|
||||
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 })
|
||||
articleIDs = articleIDsMissingStatuses(articleIDs)
|
||||
if articleIDs.isEmpty {
|
||||
@ -62,18 +66,11 @@ final class StatusesTable: DatabaseTable {
|
||||
self.cache.addObjectsNotCached(Array(statuses))
|
||||
|
||||
let newArticleIDs = self.articleIDsMissingStatuses(articleIDs)
|
||||
self.createStatusForNewArticleIDs(newArticleIDs)
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
if !newArticleIDs.isEmpty {
|
||||
self.createAndSaveStatusesForArticleIDs(newArticleIDs)
|
||||
}
|
||||
|
||||
func assertNoMissingStatuses(_ articles: Set<Article>) {
|
||||
|
||||
for oneArticle in articles {
|
||||
if oneArticle.status == nil {
|
||||
assertionFailure("All articles must have a status at this point.")
|
||||
return
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,25 +78,14 @@ 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)
|
||||
func assertNoMissingStatuses(_ articles: Set<Article>) {
|
||||
|
||||
for oneArticle in articles {
|
||||
if oneArticle.status == nil {
|
||||
assertionFailure("All articles must have a status at this point.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !articleIDs.isEmpty {
|
||||
updateArticleStatusesInDatabase(articleIDs, statusKey: statusKey, flag: flag)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Fetching
|
||||
@ -126,45 +112,56 @@ private extension StatusesTable {
|
||||
return statuses
|
||||
}
|
||||
|
||||
// MARK: Saving
|
||||
// MARK: Updating
|
||||
|
||||
func saveStatuses(_ statuses: Set<ArticleStatus>) {
|
||||
|
||||
let statusArray = statuses.map { $0.databaseDictionary() }
|
||||
insertRows(statusArray, insertType: .orIgnore)
|
||||
func markArticleStatuses(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
|
||||
|
||||
// Ignore the statuses where status.[statusKey] == flag. Update the remainder and save in database.
|
||||
|
||||
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) {
|
||||
|
||||
updateRowsWithValue(NSNumber(value: flag), valueKey: statusKey, whereKey: DatabaseKey.articleID, matches: Array(articleIDs))
|
||||
}
|
||||
|
||||
// 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 statuses = articleIDs.map { (oneArticleID) -> ArticleStatus in
|
||||
return ArticleStatus(articleID: oneArticleID, read: false, starred: false, userDeleted: false, dateArrived: now)
|
||||
}
|
||||
let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
|
||||
cache.addObjectsNotCached(statuses)
|
||||
|
||||
queue.update { (database: FMDatabase!) -> Void in
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
saveStatuses(Set(statuses))
|
||||
}
|
||||
|
||||
// MARK: Utilities
|
||||
|
||||
func articleIDsMissingStatuses(_ articleIDs: Set<String>) -> Set<String> {
|
||||
|
||||
return Set(articleIDs.filter { cache[$0] == nil })
|
||||
return Set(articleIDs.filter { !objectWithIDIsCached[$0] })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
// Not thread-safe.
|
||||
|
||||
public final class ObjectCache<T> {
|
||||
|
||||
private let keyPathForID: KeyPath<T,String>
|
||||
@ -60,7 +62,7 @@ public final class ObjectCache<T> {
|
||||
// When an object is not already cached, cache it,
|
||||
// then consider that version the unique version.
|
||||
|
||||
return objects.map({ (object) -> T in
|
||||
return objects.map { (object) -> T in
|
||||
|
||||
let identifier = identifierForObject(object)
|
||||
if let cachedObject = self[identifier] {
|
||||
@ -68,7 +70,15 @@ public final class ObjectCache<T> {
|
||||
}
|
||||
add(object)
|
||||
return object
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func objectWithIDIsCached(_ identifier: String) -> Bool {
|
||||
|
||||
if let _ = self[identifier] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public subscript(_ identifier: String) -> T? {
|
||||
|
Loading…
Reference in New Issue
Block a user