Progress toward getting Database.framework to build. Mostly just commented stuff out.
This commit is contained in:
parent
9ddaaf5f5d
commit
4010011b5a
|
@ -10,8 +10,7 @@ import Foundation
|
||||||
|
|
||||||
public struct Attachment: Hashable {
|
public struct Attachment: Hashable {
|
||||||
|
|
||||||
public let databaseID: String // Calculated
|
public let attachmentID: String // Calculated
|
||||||
public let articleID: String // Article.databaseID
|
|
||||||
public let url: String
|
public let url: String
|
||||||
public let mimeType: String?
|
public let mimeType: String?
|
||||||
public let title: String?
|
public let title: String?
|
||||||
|
@ -19,16 +18,15 @@ public struct Attachment: Hashable {
|
||||||
public let durationInSeconds: Int?
|
public let durationInSeconds: Int?
|
||||||
public let hashValue: Int
|
public let hashValue: Int
|
||||||
|
|
||||||
public init(databaseID: String?, articleID: String, url: String, mimeType: String?, title: String?, sizeInBytes: Int?, durationInSeconds: Int?) {
|
public init(attachmentID: String?, url: String, mimeType: String?, title: String?, sizeInBytes: Int?, durationInSeconds: Int?) {
|
||||||
|
|
||||||
self.articleID = articleID
|
|
||||||
self.url = url
|
self.url = url
|
||||||
self.mimeType = mimeType
|
self.mimeType = mimeType
|
||||||
self.title = title
|
self.title = title
|
||||||
self.sizeInBytes = sizeInBytes
|
self.sizeInBytes = sizeInBytes
|
||||||
self.durationInSeconds = durationInSeconds
|
self.durationInSeconds = durationInSeconds
|
||||||
|
|
||||||
var s = articleID + url
|
var s = url
|
||||||
s += mimeType ?? ""
|
s += mimeType ?? ""
|
||||||
s += title ?? ""
|
s += title ?? ""
|
||||||
if let sizeInBytes = sizeInBytes {
|
if let sizeInBytes = sizeInBytes {
|
||||||
|
@ -39,11 +37,11 @@ public struct Attachment: Hashable {
|
||||||
}
|
}
|
||||||
self.hashValue = s.hashValue
|
self.hashValue = s.hashValue
|
||||||
|
|
||||||
if let databaseID = databaseID {
|
if let attachmentID = attachmentID {
|
||||||
self.databaseID = databaseID
|
self.attachmentID = attachmentID
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.databaseID = databaseIDWithString(s)
|
self.attachmentID = databaseIDWithString(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,11 @@ import RSDatabase
|
||||||
|
|
||||||
// AccountInfo is a plist-compatible dictionary that’s stored as a binary plist in the database.
|
// AccountInfo is a plist-compatible dictionary that’s stored as a binary plist in the database.
|
||||||
|
|
||||||
func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
|
//func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
|
||||||
|
//
|
||||||
guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
|
// guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
|
||||||
return nil
|
// return nil
|
||||||
}
|
// }
|
||||||
return propertyList(withData: rawAccountInfo) as? AccountInfo
|
// return propertyList(withData: rawAccountInfo) as? AccountInfo
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
|
@ -10,80 +10,80 @@ import Foundation
|
||||||
import RSDatabase
|
import RSDatabase
|
||||||
import Data
|
import Data
|
||||||
|
|
||||||
final class ArticlesTable: DatabaseTable {
|
//final class ArticlesTable: DatabaseTable {
|
||||||
|
//
|
||||||
|
// let name: String
|
||||||
|
// private let cachedArticles: NSMapTable<NSString, Article> = NSMapTable.weakToWeakObjects()
|
||||||
|
//
|
||||||
|
// init(name: String) {
|
||||||
|
//
|
||||||
|
// self.name = name
|
||||||
|
// }
|
||||||
|
|
||||||
let name: String
|
|
||||||
let queue: RSDatabaseQueue
|
|
||||||
private let cachedArticles: NSMapTable<NSString, Article> = NSMapTable.weakToWeakObjects()
|
|
||||||
|
|
||||||
init(name: String, queue: RSDatabaseQueue) {
|
|
||||||
|
|
||||||
self.name = name
|
// func uniquedArticles(_ fetchedArticles: Set<Article>, statusesTable: StatusesTable) -> Set<Article> {
|
||||||
self.queue = queue
|
//
|
||||||
}
|
// var articles = Set<Article>()
|
||||||
|
//
|
||||||
|
// for oneArticle in fetchedArticles {
|
||||||
|
//
|
||||||
|
// assert(oneArticle.status != nil)
|
||||||
|
//
|
||||||
|
// if let existingArticle = cachedArticle(oneArticle.databaseID) {
|
||||||
|
// articles.insert(existingArticle)
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// cacheArticle(oneArticle)
|
||||||
|
// articles.insert(oneArticle)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// statusesTable.attachCachedStatuses(articles)
|
||||||
|
//
|
||||||
|
// return articles
|
||||||
|
// }
|
||||||
|
|
||||||
func uniquedArticles(_ fetchedArticles: Set<Article>, statusesTable: StatusesTable) -> Set<Article> {
|
// typealias FeedCountCallback = (Int) -> Void
|
||||||
|
//
|
||||||
var articles = Set<Article>()
|
// func numberOfArticlesWithFeedID(_ feedID: String, callback: @escaping FeedCountCallback) {
|
||||||
|
//
|
||||||
for oneArticle in fetchedArticles {
|
// queue.fetch { (database: FMDatabase!)
|
||||||
|
//
|
||||||
assert(oneArticle.status != nil)
|
// let sql = "select count(*) from articles where feedID = ?;"
|
||||||
|
// var numberOfArticles = -1
|
||||||
if let existingArticle = cachedArticle(oneArticle.databaseID) {
|
//
|
||||||
articles.insert(existingArticle)
|
// if let resultSet = database.executeQuery(sql, withArgumentsIn: [feedID]) {
|
||||||
}
|
//
|
||||||
else {
|
// while (resultSet.next()) {
|
||||||
cacheArticle(oneArticle)
|
// numberOfArticles = resultSet.long(forColumnIndex: 0)
|
||||||
articles.insert(oneArticle)
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
statusesTable.attachCachedStatuses(articles)
|
// DispatchQueue.main.async() {
|
||||||
|
// callback(numberOfArticles)
|
||||||
return articles
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
typealias FeedCountCallback = (Int) -> Void
|
//private extension ArticlesTable {
|
||||||
|
|
||||||
func numberOfArticlesWithFeedID(_ feedID: String, callback: @escaping FeedCountCallback) {
|
// func cachedArticle(_ articleID: String) -> Article? {
|
||||||
|
//
|
||||||
queue.fetch { (database: FMDatabase!)
|
// return cachedArticles.object(forKey: articleID as NSString)
|
||||||
|
// }
|
||||||
let sql = "select count(*) from articles where feedID = ?;"
|
//
|
||||||
var numberOfArticles = -1
|
// func cacheArticle(_ article: Article) {
|
||||||
|
//
|
||||||
if let resultSet = database.executeQuery(sql, withArgumentsIn: [feedID]) {
|
// cachedArticles.setObject(article, forKey: article.databaseID as NSString)
|
||||||
|
// }
|
||||||
while (resultSet.next()) {
|
//
|
||||||
numberOfArticles = resultSet.long(forColumnIndex: 0)
|
// func cacheArticles(_ articles: Set<Article>) {
|
||||||
break
|
//
|
||||||
}
|
// articles.forEach { cacheArticle($0) }
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
DispatchQueue.main.async() {
|
|
||||||
callback(numberOfArticles)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension ArticlesTable {
|
|
||||||
|
|
||||||
func cachedArticle(_ articleID: String) -> Article? {
|
|
||||||
|
|
||||||
return cachedArticles.object(forKey: articleID as NSString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheArticle(_ article: Article) {
|
|
||||||
|
|
||||||
cachedArticles.setObject(article, forKey: article.databaseID as NSString)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheArticles(_ articles: Set<Article>) {
|
|
||||||
|
|
||||||
articles.forEach { cacheArticle($0) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,14 @@ struct AttachmentsTable: DatabaseTable {
|
||||||
|
|
||||||
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
||||||
|
|
||||||
return attachmentWithRow(row) as DatabaseObject
|
if let attachment = attachmentWithRow(row) {
|
||||||
|
return attachment as DatabaseObject
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func save(_ objects: [DatabaseObject], in database: FMDatabase) {
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +40,17 @@ private extension AttachmentsTable {
|
||||||
|
|
||||||
func attachmentWithRow(_ row: FMResultSet) -> Attachment? {
|
func attachmentWithRow(_ row: FMResultSet) -> Attachment? {
|
||||||
|
|
||||||
let attachmentID = row.string(forColumn: DatabaseKey.attachmentID)
|
guard let attachmentID = row.string(forColumn: DatabaseKey.attachmentID) else {
|
||||||
if let cachedAttachment = cache(attachmentID) {
|
return nil
|
||||||
|
}
|
||||||
|
if let cachedAttachment = cache[attachmentID] as? Attachment {
|
||||||
return cachedAttachment
|
return cachedAttachment
|
||||||
}
|
}
|
||||||
|
|
||||||
return Attachment(attachmentID: attachmentID, row: row)
|
guard let attachment = Attachment(attachmentID: attachmentID, row: row) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cache[attachmentID] = attachment as DatabaseObject
|
||||||
|
return attachment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,17 @@ struct AuthorsTable: DatabaseTable {
|
||||||
// MARK: DatabaseTable Methods
|
// MARK: DatabaseTable Methods
|
||||||
|
|
||||||
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
||||||
|
|
||||||
return authorWithRow(row) as DatabaseObject
|
if let author = authorWithRow(row) {
|
||||||
|
return author as DatabaseObject
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func save(_ objects: [DatabaseObject], in database: FMDatabase) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AuthorsTable {
|
private extension AuthorsTable {
|
||||||
|
@ -44,7 +52,7 @@ private extension AuthorsTable {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if let cachedAuthor = cache[authorID] {
|
if let cachedAuthor = cache[authorID] as? Author {
|
||||||
return cachedAuthor
|
return cachedAuthor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ final class Database {
|
||||||
|
|
||||||
private let queue: RSDatabaseQueue
|
private let queue: RSDatabaseQueue
|
||||||
private let databaseFile: String
|
private let databaseFile: String
|
||||||
private let articlesTable: ArticlesTable
|
// private let articlesTable: ArticlesTable
|
||||||
private let statusesTable: StatusesTable
|
private let statusesTable: StatusesTable
|
||||||
private let authorsLookupTable: DatabaseLookupTable
|
private let authorsLookupTable: DatabaseLookupTable
|
||||||
private let attachmentsLookupTable: DatabaseLookupTable
|
private let attachmentsLookupTable: DatabaseLookupTable
|
||||||
|
@ -41,7 +41,7 @@ final class Database {
|
||||||
self.databaseFile = databaseFile
|
self.databaseFile = databaseFile
|
||||||
self.queue = RSDatabaseQueue(filepath: databaseFile, excludeFromBackup: false)
|
self.queue = RSDatabaseQueue(filepath: databaseFile, excludeFromBackup: false)
|
||||||
|
|
||||||
self.articlesTable = ArticlesTable(name: DatabaseTableName.articles, queue: queue)
|
// self.articlesTable = ArticlesTable(name: DatabaseTableName.articles, queue: queue)
|
||||||
self.statusesTable = StatusesTable(name: DatabaseTableName.statuses)
|
self.statusesTable = StatusesTable(name: DatabaseTableName.statuses)
|
||||||
|
|
||||||
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)
|
||||||
|
|
|
@ -467,21 +467,21 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
84E156EA1F0AB80500F8CC05 /* Database.swift in Sources */,
|
|
||||||
84E156EC1F0AB80E00F8CC05 /* ArticlesTable.swift in Sources */,
|
|
||||||
84E156EE1F0AB81400F8CC05 /* StatusesTable.swift in Sources */,
|
|
||||||
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */,
|
|
||||||
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
|
||||||
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */,
|
845580671F0AEBCD003CCFA1 /* Constants.swift in Sources */,
|
||||||
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
|
|
||||||
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */,
|
|
||||||
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */,
|
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */,
|
||||||
|
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */,
|
||||||
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
|
||||||
845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */,
|
845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */,
|
||||||
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
|
||||||
845580721F0AEE49003CCFA1 /* AccountInfo.swift in Sources */,
|
|
||||||
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
|
||||||
|
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.swift in Sources */,
|
||||||
84BB4BA91F11A32800858766 /* TagsTable.swift in Sources */,
|
84BB4BA91F11A32800858766 /* TagsTable.swift in Sources */,
|
||||||
|
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
|
||||||
|
84F20F8F1F180D8700D8E682 /* AuthorsTable.swift in Sources */,
|
||||||
|
84E156EC1F0AB80E00F8CC05 /* ArticlesTable.swift in Sources */,
|
||||||
|
84E156EE1F0AB81400F8CC05 /* StatusesTable.swift in Sources */,
|
||||||
|
845580721F0AEE49003CCFA1 /* AccountInfo.swift in Sources */,
|
||||||
|
84E156EA1F0AB80500F8CC05 /* Database.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,17 +32,17 @@ extension Article {
|
||||||
let bannerImageURL = row.string(forColumn: DatabaseKey.bannerImageURL)
|
let bannerImageURL = row.string(forColumn: DatabaseKey.bannerImageURL)
|
||||||
let datePublished = row.date(forColumn: DatabaseKey.datePublished)
|
let datePublished = row.date(forColumn: DatabaseKey.datePublished)
|
||||||
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
|
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
|
||||||
let authors = PropertyListTransformer.authorsWithRow(row)
|
// let authors = PropertyListTransformer.authorsWithRow(row)
|
||||||
let tags = PropertyListTransformer.tagsWithRow(row)
|
// let tags = PropertyListTransformer.tagsWithRow(row)
|
||||||
let attachments = PropertyListTransformer.attachmentsWithRow(row)
|
// let attachments = PropertyListTransformer.attachmentsWithRow(row)
|
||||||
let accountInfo = accountInfoWithRow(row)
|
// let accountInfo = accountInfoWithRow(row)
|
||||||
|
|
||||||
self.init(account: account, feedID: feed, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo)
|
self.init(account: account, feedID: feedID, uniqueID: uniqueID, title: title, contentHTML: contentHTML, contentText: contentText, url: url, externalURL: externalURL, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: accountInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func databaseDictionary() -> NSDictionary {
|
func databaseDictionary() -> NSDictionary {
|
||||||
|
|
||||||
var d = NSMutableDictionary()
|
let d = NSMutableDictionary()
|
||||||
|
|
||||||
|
|
||||||
return d.copy() as! NSDictionary
|
return d.copy() as! NSDictionary
|
||||||
|
@ -51,7 +51,7 @@ extension Article {
|
||||||
|
|
||||||
extension Article: DatabaseObject {
|
extension Article: DatabaseObject {
|
||||||
|
|
||||||
var databaseID: String {
|
public var databaseID: String {
|
||||||
get {
|
get {
|
||||||
return articleID
|
return articleID
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ extension ArticleStatus {
|
||||||
dateArrived = NSDate.distantPast
|
dateArrived = NSDate.distantPast
|
||||||
}
|
}
|
||||||
|
|
||||||
let accountInfoPlist = accountInfoWithRow(row)
|
// let accountInfoPlist = accountInfoWithRow(row)
|
||||||
|
|
||||||
self.init(articleID: articleID, read: read, starred: starred, userDeleted: userDeleted, dateArrived: dateArrived!, accountInfo: accountInfoPlist)
|
self.init(articleID: articleID, read: read, starred: starred, userDeleted: userDeleted, dateArrived: dateArrived!, accountInfo: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func databaseDictionary() -> NSDictionary {
|
func databaseDictionary() -> NSDictionary {
|
||||||
|
@ -38,11 +38,19 @@ extension ArticleStatus {
|
||||||
d[DatabaseKey.userDeleted] = userDeleted
|
d[DatabaseKey.userDeleted] = userDeleted
|
||||||
d[DatabaseKey.dateArrived] = dateArrived
|
d[DatabaseKey.dateArrived] = dateArrived
|
||||||
|
|
||||||
if let accountInfo = accountInfo, let data = PropertyListTransformer.data(withPropertyList: accountInfo) {
|
// if let accountInfo = accountInfo, let data = PropertyListTransformer.data(withPropertyList: accountInfo) {
|
||||||
d[DatabaseKey.accountInfo] = data
|
// d[DatabaseKey.accountInfo] = data
|
||||||
}
|
// }
|
||||||
|
|
||||||
return d.copy() as! NSDictionary
|
return d.copy() as! NSDictionary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ArticleStatus: DatabaseObject {
|
||||||
|
|
||||||
|
public var databaseID: String {
|
||||||
|
get {
|
||||||
|
return articleID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,24 +12,36 @@ import RSDatabase
|
||||||
|
|
||||||
extension Attachment {
|
extension Attachment {
|
||||||
|
|
||||||
init?(databaseID: String, row: FMResultSet) {
|
init?(attachmentID: String, row: FMResultSet) {
|
||||||
|
|
||||||
|
guard let url = row.string(forColumn: DatabaseKey.url) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let articleID = row.string(forColumn: DatabaseKey.articleID)
|
|
||||||
let url = row.string(forColumn: DatabaseKey.url)
|
|
||||||
let mimeType = row.string(forColumn: DatabaseKey.mimeType)
|
let mimeType = row.string(forColumn: DatabaseKey.mimeType)
|
||||||
let title = row.string(forColumn: DatabaseKey.title)
|
let title = row.string(forColumn: DatabaseKey.title)
|
||||||
let sizeInBytes = optionalIntForColumn(row, DatabaseKey.sizeInBytes)
|
let sizeInBytes = optionalIntForColumn(row, DatabaseKey.sizeInBytes)
|
||||||
let durationInSeconds = optionalIntForColumn(row, DatabaseKey.durationInSeconds)
|
let durationInSeconds = optionalIntForColumn(row, DatabaseKey.durationInSeconds)
|
||||||
|
|
||||||
self.init(databaseID: databaseID, articleID: articleID, url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
|
self.init(attachmentID: attachmentID, url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func optionalIntForColumn(_ row: FMResultSet, _ columnName: String) -> Int? {
|
}
|
||||||
|
|
||||||
let intValue = row.long(forColumn: columnName)
|
private func optionalIntForColumn(_ row: FMResultSet, _ columnName: String) -> Int? {
|
||||||
if intValue < 1 {
|
|
||||||
return nil
|
let intValue = row.long(forColumn: columnName)
|
||||||
|
if intValue < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return intValue
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Attachment: DatabaseObject {
|
||||||
|
|
||||||
|
public var databaseID: String {
|
||||||
|
get {
|
||||||
|
return attachmentID
|
||||||
}
|
}
|
||||||
return intValue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ extension Author {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Author: DatabaseObject {
|
extension Author: DatabaseObject {
|
||||||
|
|
||||||
var databaseID: String {
|
public var databaseID: String {
|
||||||
get {
|
get {
|
||||||
return authorID
|
return authorID
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,6 @@ extension Set where Element == Feed {
|
||||||
|
|
||||||
func feedIDs() -> Set<String> {
|
func feedIDs() -> Set<String> {
|
||||||
|
|
||||||
return Set(map { $0.feedID })
|
return Set<String>(map { $0.feedID })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import RSDatabase
|
||||||
|
|
||||||
extension String: DatabaseObject {
|
extension String: DatabaseObject {
|
||||||
|
|
||||||
var databaseID: String {
|
public var databaseID: String {
|
||||||
get {
|
get {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import Data
|
||||||
final class StatusesTable: DatabaseTable {
|
final class StatusesTable: DatabaseTable {
|
||||||
|
|
||||||
let name: String
|
let name: String
|
||||||
|
let databaseIDKey = DatabaseKey.articleID
|
||||||
private let cache = DatabaseObjectCache()
|
private let cache = DatabaseObjectCache()
|
||||||
|
|
||||||
init(name: String) {
|
init(name: String) {
|
||||||
|
@ -25,40 +26,58 @@ final class StatusesTable: DatabaseTable {
|
||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
func markArticles(_ articles: Set<Article>, statusKey: String, flag: Bool) {
|
// Mark: DatabaseTable Methods
|
||||||
|
|
||||||
// Main thread.
|
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
|
||||||
|
|
||||||
assertNoMissingStatuses(articles)
|
if let status = statusWithRow(row) {
|
||||||
let statuses = Set(articles.flatMap { $0.status })
|
return status as DatabaseObject
|
||||||
markArticleStatuses(statuses, statusKey: statusKey, flag: flag)
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachStatuses(_ articles: Set<Article>, _ database: FMDatabase) {
|
func save(_ objects: [DatabaseObject], in database: FMDatabase) {
|
||||||
|
|
||||||
// Look in cache first.
|
// TODO
|
||||||
attachCachedStatuses(articles)
|
|
||||||
let articlesNeedingStatuses = articlesMissingStatuses(articles)
|
|
||||||
if articlesNeedingStatuses.isEmpty {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch from database.
|
|
||||||
fetchAndCacheStatusesForArticles(articlesNeedingStatuses, database)
|
|
||||||
attachCachedStatuses(articlesNeedingStatuses)
|
|
||||||
|
|
||||||
// Create new statuses, and cache and save them in the database.
|
|
||||||
// It shouldn’t happen that an Article in the database has no corresponding ArticleStatus,
|
|
||||||
// but the case should be handled anyway.
|
|
||||||
|
|
||||||
let articlesNeedingStatusesCreated = articlesMissingStatuses(articlesNeedingStatuses)
|
|
||||||
if articlesNeedingStatusesCreated.isEmpty {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
createAndSaveStatusesForArticles(articlesNeedingStatusesCreated, database)
|
|
||||||
|
|
||||||
assertNoMissingStatuses(articles)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// func markArticles(_ articles: Set<Article>, statusKey: String, flag: Bool) {
|
||||||
|
//
|
||||||
|
// // Main thread.
|
||||||
|
//
|
||||||
|
// assertNoMissingStatuses(articles)
|
||||||
|
// let statuses = Set(articles.flatMap { $0.status })
|
||||||
|
// markArticleStatuses(statuses, statusKey: statusKey, flag: flag)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func attachStatuses(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
|
// // Look in cache first.
|
||||||
|
// attachCachedStatuses(articles)
|
||||||
|
// let articlesNeedingStatuses = articlesMissingStatuses(articles)
|
||||||
|
// if articlesNeedingStatuses.isEmpty {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Fetch from database.
|
||||||
|
// fetchAndCacheStatusesForArticles(articlesNeedingStatuses, database)
|
||||||
|
// attachCachedStatuses(articlesNeedingStatuses)
|
||||||
|
//
|
||||||
|
// // Create new statuses, and cache and save them in the database.
|
||||||
|
// // It shouldn’t happen that an Article in the database has no corresponding ArticleStatus,
|
||||||
|
// // but the case should be handled anyway.
|
||||||
|
//
|
||||||
|
// let articlesNeedingStatusesCreated = articlesMissingStatuses(articlesNeedingStatuses)
|
||||||
|
// if articlesNeedingStatusesCreated.isEmpty {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// createAndSaveStatusesForArticles(articlesNeedingStatusesCreated, database)
|
||||||
|
//
|
||||||
|
// assertNoMissingStatuses(articles)
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
// func ensureStatusesForParsedArticles(_ parsedArticles: [ParsedItem], _ callback: @escaping RSVoidCompletionBlock) {
|
// func ensureStatusesForParsedArticles(_ parsedArticles: [ParsedItem], _ callback: @escaping RSVoidCompletionBlock) {
|
||||||
|
@ -95,128 +114,144 @@ final class StatusesTable: DatabaseTable {
|
||||||
|
|
||||||
private extension StatusesTable {
|
private extension StatusesTable {
|
||||||
|
|
||||||
func attachCachedStatuses(_ articles: Set<Article>) {
|
|
||||||
|
|
||||||
articles.forEach { (oneArticle) in
|
|
||||||
|
|
||||||
if let cachedStatus = cache[oneArticle.databaseID] {
|
|
||||||
oneArticle.status = cachedStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertNoMissingStatuses(_ articles: Set<Article>) {
|
|
||||||
|
|
||||||
for oneArticle in articles {
|
|
||||||
if oneArticle.status == nil {
|
|
||||||
assertionFailure("All articles must have a status at this point.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Fetching
|
// MARK: Fetching
|
||||||
|
|
||||||
func fetchAndCacheStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
func statusWithRow(_ row: FMResultSet) -> ArticleStatus? {
|
||||||
|
|
||||||
fetchAndCacheStatusesForArticleIDs(articles.articleIDs(), database)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchAndCacheStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
|
||||||
|
|
||||||
if let statuses = fetchStatusesForArticleIDs(articleIDs, database) {
|
|
||||||
cache.addObjectsNotCached(Array(statuses))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) -> Set<ArticleStatus>? {
|
|
||||||
|
|
||||||
guard let resultSet = selectRowsWhere(key: DatabaseKey.articleID, inValues: Array(articleIDs), in: database) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return articleStatusesWithResultSet(resultSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func articleStatusesWithResultSet(_ resultSet: FMResultSet) -> Set<ArticleStatus> {
|
|
||||||
|
|
||||||
return resultSet.mapToSet(articleStatusWithRow)
|
|
||||||
}
|
|
||||||
|
|
||||||
func articleStatusWithRow(_ row: FMResultSet) -> ArticleStatus? {
|
|
||||||
|
|
||||||
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
|
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let cachedStatus = cache[articleID] {
|
if let cachedStatus = cache[articleID] as? ArticleStatus {
|
||||||
return cachedStatus
|
return cachedStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = ArticleStatus(articleID: articleID, row: row)
|
let status = ArticleStatus(articleID: articleID, row: row)
|
||||||
cache[articleID] = status
|
cache[articleID] = status
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func attachCachedStatuses(_ articles: Set<Article>) {
|
||||||
|
//
|
||||||
|
// articles.forEach { (oneArticle) in
|
||||||
|
//
|
||||||
|
// if let cachedStatus = cache[oneArticle.databaseID] {
|
||||||
|
// oneArticle.status = cachedStatus
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func assertNoMissingStatuses(_ articles: Set<Article>) {
|
||||||
|
//
|
||||||
|
// for oneArticle in articles {
|
||||||
|
// if oneArticle.status == nil {
|
||||||
|
// assertionFailure("All articles must have a status at this point.")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// MARK: Fetching
|
||||||
|
|
||||||
|
// func fetchAndCacheStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
|
// fetchAndCacheStatusesForArticleIDs(articles.articleIDs(), database)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func fetchAndCacheStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
|
// if let statuses = fetchStatusesForArticleIDs(articleIDs, database) {
|
||||||
|
// cache.addObjectsNotCached(Array(statuses))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func fetchStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) -> Set<ArticleStatus>? {
|
||||||
|
//
|
||||||
|
// guard let resultSet = selectRowsWhere(key: DatabaseKey.articleID, inValues: Array(articleIDs), in: database) else {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// return articleStatusesWithResultSet(resultSet)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func articleStatusesWithResultSet(_ resultSet: FMResultSet) -> Set<ArticleStatus> {
|
||||||
|
//
|
||||||
|
// return resultSet.mapToSet(articleStatusWithRow)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func articleStatusWithRow(_ row: FMResultSet) -> ArticleStatus? {
|
||||||
|
//
|
||||||
|
// guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// if let cachedStatus = cache[articleID] {
|
||||||
|
// return cachedStatus
|
||||||
|
// }
|
||||||
|
// let status = ArticleStatus(articleID: articleID, row: row)
|
||||||
|
// cache[articleID] = status
|
||||||
|
// return status
|
||||||
|
// }
|
||||||
|
|
||||||
// MARK: Updating
|
// MARK: Updating
|
||||||
|
|
||||||
func markArticleStatuses(_ statuses: Set<ArticleStatus>, statusKey: String, flag: Bool) {
|
// 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)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// Ignore the statuses where status.[statusKey] == flag. Update the remainder and save in database.
|
// private func updateArticleStatusesInDatabase(_ articleIDs: Set<String>, statusKey: String, flag: Bool) {
|
||||||
|
//
|
||||||
var articleIDsToUpdate = Set<String>()
|
// updateRowsWithValue(NSNumber(value: flag), valueKey: statusKey, whereKey: DatabaseKey.articleID, matches: Array(articleIDs))
|
||||||
|
// }
|
||||||
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
|
// MARK: Creating
|
||||||
|
|
||||||
func saveStatuses(_ statuses: Set<ArticleStatus>, _ database: FMDatabase) {
|
// func saveStatuses(_ statuses: Set<ArticleStatus>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
let statusArray = statuses.map { $0.databaseDictionary() }
|
// let statusArray = statuses.map { $0.databaseDictionary() }
|
||||||
insertRows(statusArray, insertType: .orIgnore, in: database)
|
// insertRows(statusArray, insertType: .orIgnore, in: database)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
func createAndSaveStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
// func createAndSaveStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
let articleIDs = Set(articles.map { $0.databaseID })
|
// let articleIDs = Set(articles.map { $0.databaseID })
|
||||||
createAndSaveStatusesForArticleIDs(articleIDs, database)
|
// createAndSaveStatusesForArticleIDs(articleIDs, database)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
// func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||||
|
//
|
||||||
let now = Date()
|
// let now = Date()
|
||||||
let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
|
// let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
|
||||||
cache.addObjectsNotCached(statuses)
|
// cache.addObjectsNotCached(statuses)
|
||||||
|
//
|
||||||
saveStatuses(Set(statuses), database)
|
// saveStatuses(Set(statuses), database)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// MARK: Utilities
|
// MARK: Utilities
|
||||||
|
|
||||||
func articleIDsMissingCachedStatuses(_ articleIDs: Set<String>) -> Set<String> {
|
// func articleIDsMissingCachedStatuses(_ articleIDs: Set<String>) -> Set<String> {
|
||||||
|
//
|
||||||
return Set(articleIDs.filter { !cache.objectWithIDIsCached($0) })
|
// return Set(articleIDs.filter { !cache.objectWithIDIsCached($0) })
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
func articlesMissingStatuses(_ articles: Set<Article>) -> Set<Article> {
|
// func articlesMissingStatuses(_ articles: Set<Article>) -> Set<Article> {
|
||||||
|
//
|
||||||
return articles.withNilProperty(\Article.status)
|
// return articles.withNilProperty(\Article.status)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
//extension ParsedItem {
|
//extension ParsedItem {
|
||||||
|
|
|
@ -14,6 +14,10 @@ public final class DatabaseObjectCache {
|
||||||
|
|
||||||
private var dictionary = [String: DatabaseObject]()
|
private var dictionary = [String: DatabaseObject]()
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
// Compiler seems to want a public init method.
|
||||||
|
}
|
||||||
|
|
||||||
public func addObjects(_ objects: [DatabaseObject]) {
|
public func addObjects(_ objects: [DatabaseObject]) {
|
||||||
|
|
||||||
objects.forEach { add($0) }
|
objects.forEach { add($0) }
|
||||||
|
|
BIN
ToDo.ooutline
BIN
ToDo.ooutline
Binary file not shown.
Loading…
Reference in New Issue