Make progress on saving updated articles.

This commit is contained in:
Brent Simmons 2017-09-08 13:36:30 -07:00
parent 9ee20ee270
commit f40b400dd5
4 changed files with 70 additions and 82 deletions

View File

@ -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<Article>()
func saveNewArticles(_ articles: Set<Article>, _ 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<Article>, _ database: FMDatabase) {
var articlesWithChanges = Set<Article>()
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<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
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<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
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<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
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<Article>, _ 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<Article>, _ 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<Article>, _ 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<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
updateRelatedTags(updatedArticles, fetchedArticles, database)
updateRelatedAttachments(updatedArticles, fetchedArticles, database)
updatedRelatedAuthors(updatedArticles, fetchedArticles, database)
}
func articlesWithParsedItems(_ parsedItems: Set<ParsedItem>, _ feed: Feed) -> Set<Article> {
// These Articles dont 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<Article>, _ database: FMDatabase) {
saveRelatedObjects(articles, database)
let databaseDictionaries = articles.map { $0.databaseDictionary() }
insertRows(databaseDictionaries, insertType: .orIgnore, in: database)
}
func saveRelatedObjects(_ articles: Set<Article>, _ 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).

View File

@ -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)

View File

@ -13,7 +13,7 @@ import RSParser
extension Article {
convenience init?(row: FMResultSet, authors: Set<Author>, attachments: Set<Attachment>, tags: Set<String>, accountID: String) {
init?(row: FMResultSet, authors: Set<Author>, attachments: Set<Attachment>, tags: Set<String>, 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)

View File

@ -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
}
}