From f40b400dd5ddc716f5c337fece89bc12bc2a799b Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Fri, 8 Sep 2017 13:36:30 -0700 Subject: [PATCH] Make progress on saving updated articles. --- Frameworks/Database/ArticlesTable.swift | 141 ++++++++---------- Frameworks/Database/Database.swift | 5 +- .../Extensions/Article+Database.swift | 4 +- .../Database/Extensions/Author+Database.swift | 2 +- 4 files changed, 70 insertions(+), 82 deletions(-) diff --git a/Frameworks/Database/ArticlesTable.swift b/Frameworks/Database/ArticlesTable.swift index 183cfad0d..2866f9f40 100644 --- a/Frameworks/Database/ArticlesTable.swift +++ b/Frameworks/Database/ArticlesTable.swift @@ -335,7 +335,7 @@ private extension ArticlesTable { assert(Thread.isMainThread) - updateRelatedObjects(_ parsedItems: [String: ParsedItem], _ articles: [String: Article]) +// updateRelatedObjects(_ parsedItems: [String: ParsedItem], _ articles: [String: Article]) } @@ -391,80 +391,93 @@ private extension ArticlesTable { } } - func updateRelatedAttachments(_ parsedItems: [String: ParsedItem], _ articles: [String: Article]) { + // MARK: Save New Articles - var articlesWithChanges = Set
() + func saveNewArticles(_ articles: Set
, _ database: FMDatabase) { - for (articleID, parsedItem) in parsedItems { - guard let article = articles[articleID] else { - continue - } - if !parsedItemTagsMatchArticlesTag(parsedItem, article) { - articlesChanges.insert(article) - } - } - - if articlesWithChanges.isEmpty { - return - } - queue.update { (database) in - tagsLookupTable.saveRelatedObjects(for: articlesWithChanges.databaseObjects(), in: database) - } + saveRelatedObjectsForNewArticles(articles, database) + let databaseDictionaries = articles.map { $0.databaseDictionary() } + insertRows(databaseDictionaries, insertType: .orReplace, in: database) } - func updateRelatedTags(_ parsedItems: [String: ParsedItem], _ articles: [String: Article]) { + func saveRelatedObjectsForNewArticles(_ articles: Set
, _ database: FMDatabase) { - var articlesWithChanges = Set
() + let databaseObjects = articles.databaseObjects() - for (articleID, parsedItem) in parsedItems { - guard let article = articles[articleID] else { - continue - } - if !parsedItemTagsMatchArticlesTag(parsedItem, article) { - articlesChanges.insert(article) + authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) + attachmentsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) + tagsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) + } + + // MARK: Update Existing Articles + + // TODO: use a keypath instead of separate functions. Fix code duplication. + + func articlesWithTagChanges(_ updatedArticles: Set
, _ fetchedArticles: [String: Article]) -> Set
{ + + return updatedArticles.filter{ (updatedArticle) -> Bool in + if let fetchedArticle = fetchedArticles[updatedArticle.articleID] { + return updatedArticle.tags != fetchedArticles.tags } + assertionFailure("Expected to find matching fetched article."); + return true } + } - if articlesWithChanges.isEmpty { - return + func articlesWithAttachmentChanges(_ updatedArticles: Set
, _ fetchedArticles: [String: Article]) -> Set
{ + + return updatedArticles.filter{ (updatedArticle) -> Bool in + if let fetchedArticle = fetchedArticles[updatedArticle.articleID] { + return updatedArticle.attachments != fetchedArticles.attachments + } + assertionFailure("Expected to find matching fetched article."); + return true } - queue.update { (database) in + } + + func articlesWithAuthorChanges(_ updatedArticles: Set
, _ fetchedArticles: [String: Article]) -> Set
{ + + return updatedArticles.filter{ (updatedArticle) -> Bool in + if let fetchedArticle = fetchedArticles[updatedArticle.articleID] { + return updatedArticle.authors != fetchedArticles.authors + } + assertionFailure("Expected to find matching fetched article."); + return true + } + } + + func updateRelatedTags(_ updatedArticles: Set
, _ fetchedArticles: [String: Article], _ database: FMDatabase) { + + let articlesWithChanges = articlesWithTagChanges(updatedArticles, fetchedArticles) + if !articlesWithChanges.isEmpty { tagsLookupTable.saveRelatedObjects(for: articlesWithChanges.databaseObjects(), in: database) } } - func parsedItemTagsMatchArticlesTag(_ parsedItem: ParsedItem, _ article: Article) -> Bool { + func updateRelatedAttachments(_ updatedArticles: Set
, _ fetchedArticles: [String: Article], _ database: FMDatabase) { - let parsedItemTags = parsedItem.tags - let articleTags = article.tags - - if parsedItemTags == nil && articleTags == nil { - return true + let articlesWithChanges = articlesWithAttachmentChanges(updatedArticles, fetchedArticles) + if !articlesWithChanges.isEmpty { + attachmentsLookupTable.saveRelatedObjects(for: articlesWithChanges.databaseObjects(), in: database) } - if parsedItemTags != nil && articleTags == nil { - return false - } - if parsedItemTags == nil && articleTags != nil { - return true - } - return Set(parsedItemTags!) == articleTags! } - func saveNewParsedItems(_ parsedItems: [String: ParsedItem], _ feed: Feed) { + func updateRelatedAuthors(_ updatedArticles: Set
, _ fetchedArticles: [String: Article], _ database: FMDatabase) { - // These parsedItems have no existing status or Article. - - queue.update { (database) in - - let articleIDs = Set(parsedItems.keys) - self.statusesTable.ensureStatusesForArticleIDs(articleIDs, database) - - let articles = self.articlesWithParsedItems(Set(parsedItems.values), feed) - self.saveUncachedNewArticles(articles, database) + let articlesWithChanges = articlesWithAuthorChanges(updatedArticles, fetchedArticles) + if !articlesWithChanges.isEmpty { + authorsLookupTable.saveRelatedObjects(for: articlesWithChanges.databaseObjects(), in: database) } } + func saveUpdatedArticles(_ updatedArticles: Set
, _ fetchedArticles: [String: Article], _ database: FMDatabase) { + + updateRelatedTags(updatedArticles, fetchedArticles, database) + updateRelatedAttachments(updatedArticles, fetchedArticles, database) + updatedRelatedAuthors(updatedArticles, fetchedArticles, database) + } + func articlesWithParsedItems(_ parsedItems: Set, _ feed: Feed) -> Set
{ // These Articles don’t get cached. Background-queue only. @@ -474,31 +487,9 @@ private extension ArticlesTable { func articleWithParsedItem(_ parsedItem: ParsedItem, _ feedID: String) -> Article? { - guard let account = account else { - assertionFailure("account is unexpectedly nil.") - return nil - } - - return Article(parsedItem: parsedItem, feedID: feedID, account: account) + return Article(parsedItem: parsedItem, feedID: feedID, accountID: accountID) } - func saveUncachedNewArticles(_ articles: Set
, _ database: FMDatabase) { - - saveRelatedObjects(articles, database) - - let databaseDictionaries = articles.map { $0.databaseDictionary() } - insertRows(databaseDictionaries, insertType: .orIgnore, in: database) - } - - func saveRelatedObjects(_ articles: Set
, _ database: FMDatabase) { - - let databaseObjects = articles.databaseObjects() - - authorsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) - attachmentsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) - tagsLookupTable.saveRelatedObjects(for: databaseObjects, in: database) - } - func statusIndicatesArticleIsIgnorable(_ status: ArticleStatus) -> Bool { // Ignorable articles: either userDeleted==1 or (not starred and arrival date > 4 months). diff --git a/Frameworks/Database/Database.swift b/Frameworks/Database/Database.swift index f06f61558..1e72285e8 100644 --- a/Frameworks/Database/Database.swift +++ b/Frameworks/Database/Database.swift @@ -24,12 +24,9 @@ public final class Database { private let articlesTable: ArticlesTable private var articleArrivalCutoffDate = NSDate.rs_dateWithNumberOfDays(inThePast: 3 * 31)! private let minimumNumberOfArticles = 10 - private weak var delegate: AccountDelegate? - private weak var account: Account? - public init(databaseFile: String, delegate: AccountDelegate, account: Account) { + public init(databaseFile: String) { - self.delegate = delegate self.account = account self.databaseFile = databaseFile self.queue = RSDatabaseQueue(filepath: databaseFile, excludeFromBackup: false) diff --git a/Frameworks/Database/Extensions/Article+Database.swift b/Frameworks/Database/Extensions/Article+Database.swift index a237aa910..bf487b4fa 100644 --- a/Frameworks/Database/Extensions/Article+Database.swift +++ b/Frameworks/Database/Extensions/Article+Database.swift @@ -13,7 +13,7 @@ import RSParser extension Article { - convenience init?(row: FMResultSet, authors: Set, attachments: Set, tags: Set, accountID: String) { + init?(row: FMResultSet, authors: Set, attachments: Set, tags: Set, accountID: String) { guard let feedID = row.string(forColumn: DatabaseKey.feedID) else { return nil @@ -38,7 +38,7 @@ extension Article { self.init(account: account, articleID: articleID, 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) } - convenience init(parsedItem: ParsedItem, accountID: String, feedID: String) { + init(parsedItem: ParsedItem, accountID: String, feedID: String) { let authors = Author.authorsWithParsedAuthors(parsedItem.authors) let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments) diff --git a/Frameworks/Database/Extensions/Author+Database.swift b/Frameworks/Database/Extensions/Author+Database.swift index 326ffa009..4a4a1ddc7 100644 --- a/Frameworks/Database/Extensions/Author+Database.swift +++ b/Frameworks/Database/Extensions/Author+Database.swift @@ -34,7 +34,7 @@ extension Author { return nil } - let authors = parsedAuthors.flatMap { Author(parsedAuthor: $0) } + let authors = Set(parsedAuthors.flatMap { Author(parsedAuthor: $0) }) return authors.isEmpty ? nil : authors } }