Progress toward getting Database.framework to build. Mostly just commented stuff out.

This commit is contained in:
Brent Simmons 2017-08-20 22:43:46 -07:00
parent 9ddaaf5f5d
commit 4010011b5a
16 changed files with 338 additions and 259 deletions

View File

@ -10,8 +10,7 @@ import Foundation
public struct Attachment: Hashable {
public let databaseID: String // Calculated
public let articleID: String // Article.databaseID
public let attachmentID: String // Calculated
public let url: String
public let mimeType: String?
public let title: String?
@ -19,16 +18,15 @@ public struct Attachment: Hashable {
public let durationInSeconds: 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.mimeType = mimeType
self.title = title
self.sizeInBytes = sizeInBytes
self.durationInSeconds = durationInSeconds
var s = articleID + url
var s = url
s += mimeType ?? ""
s += title ?? ""
if let sizeInBytes = sizeInBytes {
@ -39,11 +37,11 @@ public struct Attachment: Hashable {
}
self.hashValue = s.hashValue
if let databaseID = databaseID {
self.databaseID = databaseID
if let attachmentID = attachmentID {
self.attachmentID = attachmentID
}
else {
self.databaseID = databaseIDWithString(s)
self.attachmentID = databaseIDWithString(s)
}
}

View File

@ -12,10 +12,11 @@ import RSDatabase
// AccountInfo is a plist-compatible dictionary thats stored as a binary plist in the database.
func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
return nil
}
return propertyList(withData: rawAccountInfo) as? AccountInfo
}
//func accountInfoWithRow(_ row: FMResultSet) -> AccountInfo? {
//
// guard let rawAccountInfo = row.data(forColumn: DatabaseKey.accountInfo) else {
// return nil
// }
// return propertyList(withData: rawAccountInfo) as? AccountInfo
//}

View File

@ -10,80 +10,80 @@ import Foundation
import RSDatabase
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
self.queue = queue
}
// func uniquedArticles(_ fetchedArticles: Set<Article>, statusesTable: StatusesTable) -> Set<Article> {
//
// 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> {
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
}
// typealias FeedCountCallback = (Int) -> Void
//
// func numberOfArticlesWithFeedID(_ feedID: String, callback: @escaping FeedCountCallback) {
//
// queue.fetch { (database: FMDatabase!)
//
// let sql = "select count(*) from articles where feedID = ?;"
// var numberOfArticles = -1
//
// if let resultSet = database.executeQuery(sql, withArgumentsIn: [feedID]) {
//
// while (resultSet.next()) {
// numberOfArticles = resultSet.long(forColumnIndex: 0)
// break
// }
// }
//
// DispatchQueue.main.async() {
// callback(numberOfArticles)
// }
// }
//
// }
//}
typealias FeedCountCallback = (Int) -> Void
//private extension ArticlesTable {
func numberOfArticlesWithFeedID(_ feedID: String, callback: @escaping FeedCountCallback) {
queue.fetch { (database: FMDatabase!)
let sql = "select count(*) from articles where feedID = ?;"
var numberOfArticles = -1
if let resultSet = database.executeQuery(sql, withArgumentsIn: [feedID]) {
while (resultSet.next()) {
numberOfArticles = resultSet.long(forColumnIndex: 0)
break
}
}
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) }
}
}
// 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) }
// }
//}

View File

@ -25,7 +25,14 @@ struct AttachmentsTable: DatabaseTable {
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? {
let attachmentID = row.string(forColumn: DatabaseKey.attachmentID)
if let cachedAttachment = cache(attachmentID) {
guard let attachmentID = row.string(forColumn: DatabaseKey.attachmentID) else {
return nil
}
if let cachedAttachment = cache[attachmentID] as? Attachment {
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
}
}

View File

@ -31,9 +31,17 @@ struct AuthorsTable: DatabaseTable {
// MARK: DatabaseTable Methods
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 {
@ -44,7 +52,7 @@ private extension AuthorsTable {
return nil
}
if let cachedAuthor = cache[authorID] {
if let cachedAuthor = cache[authorID] as? Author {
return cachedAuthor
}

View File

@ -26,7 +26,7 @@ final class Database {
private let queue: RSDatabaseQueue
private let databaseFile: String
private let articlesTable: ArticlesTable
// private let articlesTable: ArticlesTable
private let statusesTable: StatusesTable
private let authorsLookupTable: DatabaseLookupTable
private let attachmentsLookupTable: DatabaseLookupTable
@ -41,7 +41,7 @@ final class Database {
self.databaseFile = databaseFile
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)
let authorsTable = AuthorsTable(name: DatabaseTableName.authors)

View File

@ -467,21 +467,21 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
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 */,
840405CF1F1A963700DF0296 /* AttachmentsTable.swift in Sources */,
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */,
846FB36B1F4A937B00EAB81D /* Feed+Database.swift in Sources */,
84D0DEA11F4A429800073503 /* String+Database.swift in Sources */,
843CB9961F34174100EE6581 /* Author+Database.swift in Sources */,
845580781F0AF678003CCFA1 /* Folder+Database.swift in Sources */,
845580761F0AF670003CCFA1 /* Article+Database.swift in Sources */,
845580721F0AEE49003CCFA1 /* AccountInfo.swift in Sources */,
8455807A1F0AF67D003CCFA1 /* ArticleStatus+Database.swift in Sources */,
8455807C1F0C0DBD003CCFA1 /* Attachment+Database.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;
};

View File

@ -32,17 +32,17 @@ extension Article {
let bannerImageURL = row.string(forColumn: DatabaseKey.bannerImageURL)
let datePublished = row.date(forColumn: DatabaseKey.datePublished)
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
let authors = PropertyListTransformer.authorsWithRow(row)
let tags = PropertyListTransformer.tagsWithRow(row)
let attachments = PropertyListTransformer.attachmentsWithRow(row)
let accountInfo = accountInfoWithRow(row)
// let authors = PropertyListTransformer.authorsWithRow(row)
// let tags = PropertyListTransformer.tagsWithRow(row)
// let attachments = PropertyListTransformer.attachmentsWithRow(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 {
var d = NSMutableDictionary()
let d = NSMutableDictionary()
return d.copy() as! NSDictionary
@ -51,7 +51,7 @@ extension Article {
extension Article: DatabaseObject {
var databaseID: String {
public var databaseID: String {
get {
return articleID
}

View File

@ -23,9 +23,9 @@ extension ArticleStatus {
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 {
@ -38,11 +38,19 @@ extension ArticleStatus {
d[DatabaseKey.userDeleted] = userDeleted
d[DatabaseKey.dateArrived] = dateArrived
if let accountInfo = accountInfo, let data = PropertyListTransformer.data(withPropertyList: accountInfo) {
d[DatabaseKey.accountInfo] = data
}
// if let accountInfo = accountInfo, let data = PropertyListTransformer.data(withPropertyList: accountInfo) {
// d[DatabaseKey.accountInfo] = data
// }
return d.copy() as! NSDictionary
}
}
extension ArticleStatus: DatabaseObject {
public var databaseID: String {
get {
return articleID
}
}
}

View File

@ -12,24 +12,36 @@ import RSDatabase
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 title = row.string(forColumn: DatabaseKey.title)
let sizeInBytes = optionalIntForColumn(row, DatabaseKey.sizeInBytes)
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)
if intValue < 1 {
return nil
private func optionalIntForColumn(_ row: FMResultSet, _ columnName: String) -> Int? {
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
}
}

View File

@ -23,9 +23,9 @@ extension Author {
}
}
public extension Author: DatabaseObject {
extension Author: DatabaseObject {
var databaseID: String {
public var databaseID: String {
get {
return authorID
}

View File

@ -13,6 +13,6 @@ extension Set where Element == Feed {
func feedIDs() -> Set<String> {
return Set(map { $0.feedID })
return Set<String>(map { $0.feedID })
}
}

View File

@ -14,7 +14,7 @@ import RSDatabase
extension String: DatabaseObject {
var databaseID: String {
public var databaseID: String {
get {
return self
}

View File

@ -18,6 +18,7 @@ import Data
final class StatusesTable: DatabaseTable {
let name: String
let databaseIDKey = DatabaseKey.articleID
private let cache = DatabaseObjectCache()
init(name: String) {
@ -25,40 +26,58 @@ final class StatusesTable: DatabaseTable {
self.name = name
}
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)
// Mark: DatabaseTable Methods
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
if let status = statusWithRow(row) {
return status as DatabaseObject
}
return nil
}
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 shouldnt 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 save(_ objects: [DatabaseObject], in database: FMDatabase) {
// TODO
}
// 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 shouldnt 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) {
@ -95,128 +114,144 @@ final class StatusesTable: DatabaseTable {
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
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? {
func statusWithRow(_ row: FMResultSet) -> ArticleStatus? {
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
return nil
}
if let cachedStatus = cache[articleID] {
if let cachedStatus = cache[articleID] as? ArticleStatus {
return cachedStatus
}
let status = ArticleStatus(articleID: articleID, row: row)
cache[articleID] = 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
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.
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))
}
// 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 saveStatuses(_ statuses: Set<ArticleStatus>, _ database: FMDatabase) {
let statusArray = statuses.map { $0.databaseDictionary() }
insertRows(statusArray, insertType: .orIgnore, in: database)
}
func createAndSaveStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
let articleIDs = Set(articles.map { $0.databaseID })
createAndSaveStatusesForArticleIDs(articleIDs, database)
}
func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
let now = Date()
let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
cache.addObjectsNotCached(statuses)
saveStatuses(Set(statuses), database)
}
// func saveStatuses(_ statuses: Set<ArticleStatus>, _ database: FMDatabase) {
//
// let statusArray = statuses.map { $0.databaseDictionary() }
// insertRows(statusArray, insertType: .orIgnore, in: database)
// }
//
// func createAndSaveStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
//
// let articleIDs = Set(articles.map { $0.databaseID })
// createAndSaveStatusesForArticleIDs(articleIDs, database)
// }
//
// func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
//
// let now = Date()
// let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
// cache.addObjectsNotCached(statuses)
//
// saveStatuses(Set(statuses), database)
// }
// MARK: Utilities
func articleIDsMissingCachedStatuses(_ articleIDs: Set<String>) -> Set<String> {
return Set(articleIDs.filter { !cache.objectWithIDIsCached($0) })
}
func articlesMissingStatuses(_ articles: Set<Article>) -> Set<Article> {
return articles.withNilProperty(\Article.status)
}
// func articleIDsMissingCachedStatuses(_ articleIDs: Set<String>) -> Set<String> {
//
// return Set(articleIDs.filter { !cache.objectWithIDIsCached($0) })
// }
//
// func articlesMissingStatuses(_ articles: Set<Article>) -> Set<Article> {
//
// return articles.withNilProperty(\Article.status)
// }
}
//extension ParsedItem {

View File

@ -14,6 +14,10 @@ public final class DatabaseObjectCache {
private var dictionary = [String: DatabaseObject]()
public init() {
// Compiler seems to want a public init method.
}
public func addObjects(_ objects: [DatabaseObject]) {
objects.forEach { add($0) }

Binary file not shown.