Make further progress on saving articles from feeds.
This commit is contained in:
parent
d84c65c66f
commit
a92492eb91
@ -79,10 +79,10 @@ final class ArticlesTable: DatabaseTable {
|
||||
|
||||
// MARK: Updating
|
||||
|
||||
func update(_ feed: Feed, _ parsedFeed: ParsedFeed, _ completion: @escaping RSVoidCompletionBlock) {
|
||||
func update(_ feed: Feed, _ parsedFeed: ParsedFeed, _ completion: @escaping UpdateArticlesWithFeedCompletionBlock) {
|
||||
|
||||
if parsedFeed.items.isEmpty {
|
||||
completion()
|
||||
completion(nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@ -90,40 +90,51 @@ final class ArticlesTable: DatabaseTable {
|
||||
// 2. Ignore parsedItems that are userDeleted || (!starred and really old)
|
||||
// 3. Fetch all articles for the feed.
|
||||
// 4. Create Articles with parsedItems.
|
||||
// 5.
|
||||
// 5. Create array of Articles not in database and save them.
|
||||
// 6. Create array of updated Articles and save what’s changed.
|
||||
// 7. Call back with new and updated Articles.
|
||||
|
||||
let feedID = feed.feedID
|
||||
let parsedItemArticleIDs = Set(parsedFeed.items.map { $0.databaseIdentifierWithFeed(feed) })
|
||||
let parsedItemsDictionary = parsedFeed.itemsDictionary(with: feed)
|
||||
|
||||
statusesTable.ensureStatusesForArticleIDs(parsedItemArticleIDs) {
|
||||
statusesTable.ensureStatusesForArticleIDs(parsedItemArticleIDs) { // 1
|
||||
|
||||
let filteredParsedItems = self.filterParsedItems(parsedItemsDictionary)
|
||||
let filteredParsedItems = self.filterParsedItems(parsedItemsDictionary) // 2
|
||||
if filteredParsedItems.isEmpty {
|
||||
completion()
|
||||
completion(nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
queue.fetch{ (database) in
|
||||
|
||||
let fetchedArticles = self.fetchArticlesForFeedID(feedID, withLimits: false, database: database)
|
||||
|
||||
let incomingArticles = Article.articlesWithParsedItems(parsedFeed.items, accountID, feedID)
|
||||
queue.update{ (database) in
|
||||
|
||||
let fetchedArticles = self.fetchArticlesForFeedID(feedID, withLimits: false, database: database) //3
|
||||
let fetchedArticlesDictionary = fetchedArticles.dictionary()
|
||||
|
||||
let incomingArticles = Article.articlesWithParsedItems(filteredParsedItems, accountID, feedID) //4
|
||||
let incomingArticlesDictionary = incomingArticles.dictionary()
|
||||
|
||||
let newArticles = Set(incomingArticles.filter { fetchedArticles[$0.articleID] == nil }) //5
|
||||
if !newArticles.isEmpty {
|
||||
saveNewArticles(newArticles, database)
|
||||
}
|
||||
|
||||
let updatedArticles = incomingArticles.filter{ (incomingArticle) -> Bool in //6
|
||||
if let existingArticle = fetchedArticles[incomingArticle.articleID] {
|
||||
if existingArticle != incomingArticle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !updatedArticles.isEmpty {
|
||||
saveUpdatedArticles(Set(updatedArticles), fetchedArticlesDictionary, database)
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(newArticles, updatedArticles) //7
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 3. For each parsedItem:
|
||||
// - if userDeleted || (!starred && status.dateArrived < cutoff), then ignore
|
||||
// - if matches existing article, then update database with changes between the two
|
||||
// - if new, create article and save in database
|
||||
|
||||
fetchArticlesAsync(feed, withLimits: false) { (articles) in
|
||||
self.updateArticles(articles.dictionary(), parsedFeed.itemsDictionary(with: feed), feed, completion)
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,21 +193,21 @@ private extension ArticlesTable {
|
||||
|
||||
// MARK: Fetching
|
||||
|
||||
func attachRelatedObjects(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||
|
||||
let articleArray = articles.map { $0 as DatabaseObject }
|
||||
|
||||
authorsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
attachmentsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
tagsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
|
||||
// In theory, it’s impossible to have a fetched article without a status.
|
||||
// Let’s handle that impossibility anyway.
|
||||
// Remember that, if nothing else, the user can edit the SQLite database,
|
||||
// and thus could delete all their statuses.
|
||||
|
||||
statusesTable.ensureStatusesForArticles(articles, database)
|
||||
}
|
||||
// func attachRelatedObjects(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||
//
|
||||
// let articleArray = articles.map { $0 as DatabaseObject }
|
||||
//
|
||||
// authorsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
// attachmentsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
// tagsLookupTable.attachRelatedObjects(to: articleArray, in: database)
|
||||
//
|
||||
// // In theory, it’s impossible to have a fetched article without a status.
|
||||
// // Let’s handle that impossibility anyway.
|
||||
// // Remember that, if nothing else, the user can edit the SQLite database,
|
||||
// // and thus could delete all their statuses.
|
||||
//
|
||||
// statusesTable.ensureStatusesForArticles(articles, database)
|
||||
// }
|
||||
|
||||
func articleWithRow(_ row: FMResultSet) -> Article? {
|
||||
|
||||
|
@ -8,7 +8,24 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct DatabaseTableName {
|
||||
// MARK: - Notifications
|
||||
|
||||
public extension Notification.Name {
|
||||
|
||||
public static let ArticlesDidSave = Notification.Name(rawValue: "ArticlesDidSave")
|
||||
}
|
||||
|
||||
public struct DatabaseNotificationKey {
|
||||
|
||||
// userInfo keys (with Set<Article> values) for ArticlesDidSave.
|
||||
// One or both will be present. If present, may be empty.
|
||||
static let newArticles = "newArticles"
|
||||
static let updatedArticles = "updatedArticles"
|
||||
}
|
||||
|
||||
// MARK: - Database structure
|
||||
|
||||
struct DatabaseTableName {
|
||||
|
||||
static let articles = "articles"
|
||||
static let authors = "authors"
|
||||
@ -19,7 +36,7 @@ public struct DatabaseTableName {
|
||||
static let attachmentsLookup = "attachmentsLookup"
|
||||
}
|
||||
|
||||
public struct DatabaseKey {
|
||||
struct DatabaseKey {
|
||||
|
||||
// Shared
|
||||
static let databaseID = "databaseID"
|
||||
@ -65,7 +82,7 @@ public struct DatabaseKey {
|
||||
static let emailAddress = "emailAddress"
|
||||
}
|
||||
|
||||
public struct RelationshipName {
|
||||
struct RelationshipName {
|
||||
|
||||
static let authors = "authors"
|
||||
static let tags = "tags"
|
||||
|
@ -15,6 +15,7 @@ import Data
|
||||
public typealias ArticleResultBlock = (Set<Article>) -> Void
|
||||
public typealias UnreadCountTable = [String: Int] // feedID: unreadCount
|
||||
public typealias UnreadCountCompletionBlock = (UnreadCountTable) -> Void //feedID: unreadCount
|
||||
typealias UpdateArticlesWithFeedCompletionBlock = (Set<Article>, Set<Article>) -> Void
|
||||
|
||||
public final class Database {
|
||||
|
||||
|
@ -73,7 +73,7 @@ extension Article {
|
||||
|
||||
static func articlesWithParsedItems(_ parsedItems: [ParsedItem], _ accountID: String, _ feedID: String) -> Set<Article> {
|
||||
|
||||
return parsedItems.map{ Article(parsedItem: $0, accountID: accountID, feedID: feedID) }
|
||||
return Set(parsedItems.map{ Article(parsedItem: $0, accountID: accountID, feedID: feedID) })
|
||||
}
|
||||
|
||||
// MARK: Updating with ParsedItem
|
||||
|
BIN
ToDo.ooutline
BIN
ToDo.ooutline
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user