Make progress on making ArticleStatus a reference type and on making article.status non-optional.
This commit is contained in:
parent
ab43db7761
commit
6db993075b
|
@ -131,19 +131,9 @@ final class ArticlesTable: DatabaseTable {
|
||||||
|
|
||||||
// MARK: Status
|
// MARK: Status
|
||||||
|
|
||||||
func status(for article: Article) -> ArticleStatus? {
|
func mark(_ articles: Set<Article>, _ statusKey: String, _ flag: Bool) {
|
||||||
|
|
||||||
return statusesTable.cachedStatus(for: article.articleID)
|
statusesTable.mark(articles.statuses(), statusKey, flag)
|
||||||
}
|
|
||||||
|
|
||||||
func statuses(for articles: Set<Article>) -> Set<ArticleStatus> {
|
|
||||||
|
|
||||||
return statusesTable.cachedStatuses(for: articles.articleIDs())
|
|
||||||
}
|
|
||||||
|
|
||||||
func mark(_ statuses: Set<ArticleStatus>, _ statusKey: String, _ flag: Bool) {
|
|
||||||
|
|
||||||
statusesTable.mark(statuses, statusKey, flag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,19 +70,9 @@ public final class Database {
|
||||||
|
|
||||||
// MARK: - Status
|
// MARK: - Status
|
||||||
|
|
||||||
public func status(for article: Article) -> ArticleStatus? {
|
public func mark(_ articles: Set<Article>, statusKey: String, flag: Bool) {
|
||||||
|
|
||||||
return articlesTable.status(for: article)
|
articlesTable.mark(articles, statusKey, flag)
|
||||||
}
|
|
||||||
|
|
||||||
public func statuses(for articles: Set<Article>) -> Set<ArticleStatus> {
|
|
||||||
|
|
||||||
return articlesTable.statuses(for: articles)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func mark(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
|
|
||||||
|
|
||||||
articlesTable.mark(statuses, statusKey, flag)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,11 @@ extension Set where Element == Article {
|
||||||
return Set<String>(map { $0.databaseID })
|
return Set<String>(map { $0.databaseID })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func statuses() -> Set<ArticleStatus> {
|
||||||
|
|
||||||
|
return Set<ArticleStatus>(map { $0.status })
|
||||||
|
}
|
||||||
|
|
||||||
func dictionary() -> [String: Article] {
|
func dictionary() -> [String: Article] {
|
||||||
|
|
||||||
var d = [String: Article]()
|
var d = [String: Article]()
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Data
|
||||||
|
|
||||||
extension ArticleStatus {
|
extension ArticleStatus {
|
||||||
|
|
||||||
init(articleID: String, dateArrived: Date, row: FMResultSet) {
|
convenience init(articleID: String, dateArrived: Date, row: FMResultSet) {
|
||||||
|
|
||||||
let read = row.bool(forColumn: DatabaseKey.read)
|
let read = row.bool(forColumn: DatabaseKey.read)
|
||||||
let starred = row.bool(forColumn: DatabaseKey.starred)
|
let starred = row.bool(forColumn: DatabaseKey.starred)
|
||||||
|
|
|
@ -30,42 +30,27 @@ final class StatusesTable: DatabaseTable {
|
||||||
|
|
||||||
// MARK: Cache
|
// MARK: Cache
|
||||||
|
|
||||||
func cachedStatus(for articleID: String) -> ArticleStatus? {
|
// func cachedStatus(for articleID: String) -> ArticleStatus? {
|
||||||
|
//
|
||||||
|
// assert(Thread.isMainThread)
|
||||||
|
// assert(cache[articleID] != nil)
|
||||||
|
// return cache[articleID]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func cachedStatuses(for articleIDs: Set<String>) -> Set<ArticleStatus> {
|
||||||
|
//
|
||||||
|
// assert(Thread.isMainThread)
|
||||||
|
//
|
||||||
|
// var statuses = Set<ArticleStatus>()
|
||||||
|
// for articleID in articleIDs {
|
||||||
|
// if let articleStatus = cache[articleID] {
|
||||||
|
// statuses.insert(articleStatus)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return statuses
|
||||||
|
// }
|
||||||
|
|
||||||
assert(Thread.isMainThread)
|
|
||||||
assert(cache[articleID] != nil)
|
|
||||||
return cache[articleID]
|
|
||||||
}
|
|
||||||
|
|
||||||
func cachedStatuses(for articleIDs: Set<String>) -> Set<ArticleStatus> {
|
|
||||||
|
|
||||||
assert(Thread.isMainThread)
|
|
||||||
|
|
||||||
var statuses = Set<ArticleStatus>()
|
|
||||||
for articleID in articleIDs {
|
|
||||||
if let articleStatus = cache[articleID] {
|
|
||||||
statuses.insert(articleStatus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return statuses
|
|
||||||
}
|
|
||||||
|
|
||||||
func addIfNotCached(_ statuses: Set<ArticleStatus>) {
|
|
||||||
|
|
||||||
if statuses.isEmpty {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if Thread.isMainThread {
|
|
||||||
self.cache.addIfNotCached(statuses)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.cache.addIfNotCached(statuses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Creating/Updating
|
// MARK: Creating/Updating
|
||||||
|
|
||||||
|
@ -108,15 +93,13 @@ final class StatusesTable: DatabaseTable {
|
||||||
if status.boolStatus(forKey: statusKey) == flag {
|
if status.boolStatus(forKey: statusKey) == flag {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var statusCopy = status
|
status.setBoolStatus(flag, forKey: statusKey)
|
||||||
statusCopy.setBoolStatus(flag, forKey: statusKey)
|
updatedStatuses.insert(status)
|
||||||
updatedStatuses.insert(statusCopy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if updatedStatuses.isEmpty {
|
if updatedStatuses.isEmpty {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
addToCache(updatedStatuses)
|
|
||||||
|
|
||||||
queue.update { (database) in
|
queue.update { (database) in
|
||||||
self.markArticleIDs(updatedStatuses.articleIDs(), statusKey, flag, database)
|
self.markArticleIDs(updatedStatuses.articleIDs(), statusKey, flag, database)
|
||||||
|
@ -183,6 +166,22 @@ private extension StatusesTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addIfNotCached(_ statuses: Set<ArticleStatus>) {
|
||||||
|
|
||||||
|
if statuses.isEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if Thread.isMainThread {
|
||||||
|
self.cache.addIfNotCached(statuses)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.cache.addIfNotCached(statuses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Creating
|
// MARK: Creating
|
||||||
|
|
||||||
func saveStatuses(_ statuses: Set<ArticleStatus>) {
|
func saveStatuses(_ statuses: Set<ArticleStatus>) {
|
||||||
|
@ -231,7 +230,7 @@ private extension StatusesTable {
|
||||||
|
|
||||||
private final class StatusCache {
|
private final class StatusCache {
|
||||||
|
|
||||||
// Main thread only.
|
// Serial database queue only.
|
||||||
|
|
||||||
var dictionary = [String: ArticleStatus]()
|
var dictionary = [String: ArticleStatus]()
|
||||||
|
|
||||||
|
@ -239,6 +238,8 @@ private final class StatusCache {
|
||||||
|
|
||||||
// Replaces any cached statuses.
|
// Replaces any cached statuses.
|
||||||
|
|
||||||
|
assert(!Thread.isMainThread)
|
||||||
|
|
||||||
for status in statuses {
|
for status in statuses {
|
||||||
self[status.articleID] = status
|
self[status.articleID] = status
|
||||||
}
|
}
|
||||||
|
@ -248,6 +249,8 @@ private final class StatusCache {
|
||||||
|
|
||||||
// Does not replace already cached statuses.
|
// Does not replace already cached statuses.
|
||||||
|
|
||||||
|
assert(!Thread.isMainThread)
|
||||||
|
|
||||||
for status in statuses {
|
for status in statuses {
|
||||||
let articleID = status.articleID
|
let articleID = status.articleID
|
||||||
if let _ = self[articleID] {
|
if let _ = self[articleID] {
|
||||||
|
@ -259,9 +262,11 @@ private final class StatusCache {
|
||||||
|
|
||||||
subscript(_ articleID: String) -> ArticleStatus? {
|
subscript(_ articleID: String) -> ArticleStatus? {
|
||||||
get {
|
get {
|
||||||
|
assert(!Thread.isMainThread)
|
||||||
return self[articleID]
|
return self[articleID]
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
|
assert(!Thread.isMainThread)
|
||||||
self[articleID] = newValue
|
self[articleID] = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue