mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-01-31 11:14:54 +01:00
Make more progress on saving/updating articles.
This commit is contained in:
parent
d33d8a0330
commit
fb121f8a8c
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
|
||||
// MD5 works because:
|
||||
// * It’s fast
|
||||
|
@ -254,7 +254,15 @@ private extension ArticlesTable {
|
||||
|
||||
func updateArticles(_ articlesDictionary: [String: Article], _ parsedItemsDictionary: [String: ParsedItem], _ feed: Feed, _ completion: @escaping RSVoidCompletionBlock) {
|
||||
|
||||
|
||||
let parsedItemArticleIDs = Set(parsedItemsDictionary.keys)
|
||||
|
||||
queue.update { (database) in
|
||||
|
||||
self.statusesTable.ensureStatusesForArticleIDs(parsedItemArticleIDs, database)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,10 +8,11 @@
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Data
|
||||
|
||||
extension ParsedItem {
|
||||
|
||||
private func databaseIdentifierWithFeed(_ feed: Feed) -> String {
|
||||
func databaseIdentifierWithFeed(_ feed: Feed) -> String {
|
||||
|
||||
if let identifier = syncServiceID {
|
||||
return identifier
|
||||
@ -28,8 +29,8 @@ extension ParsedFeed {
|
||||
|
||||
var d = [String: ParsedItem]()
|
||||
|
||||
for parsedItem in parsedItems {
|
||||
let identifier = identifierForParsedItem(parsedItem, feed)
|
||||
for parsedItem in items {
|
||||
let identifier = parsedItem.databaseIdentifierWithFeed(feed)
|
||||
d[identifier] = parsedItem
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ final class StatusesTable: DatabaseTable {
|
||||
return articleStatus
|
||||
}
|
||||
|
||||
// MARK: Creating
|
||||
// MARK: Creating/Updating
|
||||
|
||||
func ensureStatusesForArticles(_ articles: Set<Article>, _ database: FMDatabase) {
|
||||
|
||||
@ -49,12 +49,32 @@ final class StatusesTable: DatabaseTable {
|
||||
return
|
||||
}
|
||||
|
||||
createAndSaveStatusesForArticles(articlesNeedingStatuses, database)
|
||||
let articleIDs = articlesNeedingStatuses.articleIDs()
|
||||
ensureStatusesForArticleIDs(articleIDs, database)
|
||||
|
||||
attachCachedStatuses(articlesNeedingStatuses)
|
||||
assert(articles.eachHasAStatus())
|
||||
}
|
||||
|
||||
|
||||
func ensureStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||
|
||||
// Check cache.
|
||||
let articleIDsMissingCachedStatus = articleIDsWithNoCachedStatus(articleIDs)
|
||||
if articleIDsMissingCachedStatus.isEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
// Check database.
|
||||
fetchAndCacheStatusesForArticleIDs(articleIDsMissingCachedStatus, database)
|
||||
let articleIDsNeedingStatus = articleIDsWithNoCachedStatus(articleIDs)
|
||||
if articleIDsNeedingStatus.isEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
// Create new statuses.
|
||||
createAndSaveStatusesForArticleIDs(articleIDsNeedingStatus, database)
|
||||
}
|
||||
|
||||
// MARK: Marking
|
||||
|
||||
func markArticleIDs(_ articleIDs: Set<String>, _ statusKey: String, _ flag: Bool, _ database: FMDatabase) {
|
||||
@ -74,6 +94,11 @@ private extension StatusesTable {
|
||||
}
|
||||
}
|
||||
|
||||
func articleIDsWithNoCachedStatus(_ articleIDs: Set<String>) -> Set<String> {
|
||||
|
||||
return Set(articleIDs.filter { cache[$0] == nil })
|
||||
}
|
||||
|
||||
// MARK: Creating
|
||||
|
||||
func saveStatuses(_ statuses: Set<ArticleStatus>, _ database: FMDatabase) {
|
||||
@ -82,7 +107,7 @@ private extension StatusesTable {
|
||||
insertRows(statusArray, insertType: .orIgnore, in: database)
|
||||
}
|
||||
|
||||
func cacheStatuses(_ statuses: [ArticleStatus]) {
|
||||
func cacheStatuses(_ statuses: Set<ArticleStatus>) {
|
||||
|
||||
let databaseObjects = statuses.map { $0 as DatabaseObject }
|
||||
cache.addObjectsNotCached(databaseObjects)
|
||||
@ -97,10 +122,19 @@ private extension StatusesTable {
|
||||
func createAndSaveStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||
|
||||
let now = Date()
|
||||
let statuses = articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) }
|
||||
let statuses = Set(articleIDs.map { ArticleStatus(articleID: $0, dateArrived: now) })
|
||||
|
||||
cacheStatuses(statuses)
|
||||
saveStatuses(Set(statuses), database)
|
||||
saveStatuses(statuses, database)
|
||||
}
|
||||
|
||||
func fetchAndCacheStatusesForArticleIDs(_ articleIDs: Set<String>, _ database: FMDatabase) {
|
||||
|
||||
guard let resultSet = selectRowsWhere(key: DatabaseKey.articleID, inValues: Array(articleIDs), in: database) else {
|
||||
return
|
||||
}
|
||||
|
||||
let statuses = resultSet.mapToSet(statusWithRow)
|
||||
cacheStatuses(statuses)
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ NSString *RSStringReplaceAll(NSString *stringToSearch, NSString *searchFor, NSSt
|
||||
|
||||
/*The hashed data is a UTF-8 encoded version of the string.*/
|
||||
|
||||
- (NSData *)rs_md5Hash;
|
||||
- (NSData *)rs_md5HashData;
|
||||
- (NSString *)rs_md5HashString;
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ NSString *RSStringReplaceAll(NSString *stringToSearch, NSString *searchFor, NSSt
|
||||
@implementation NSString (RSCore)
|
||||
|
||||
|
||||
- (NSData *)rs_md5Hash {
|
||||
- (NSData *)rs_md5HashData {
|
||||
|
||||
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return [data rs_md5Hash];
|
||||
@ -54,7 +54,7 @@ NSString *RSStringReplaceAll(NSString *stringToSearch, NSString *searchFor, NSSt
|
||||
|
||||
- (NSString *)rs_md5HashString {
|
||||
|
||||
NSData *d = [self rs_md5Hash];
|
||||
NSData *d = [self rs_md5HashData];
|
||||
return [d rs_hexadecimalString];
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ private extension JSONFeedParser {
|
||||
let tags = itemDictionary["tags"] as? [String]
|
||||
let attachments = parseAttachments(itemDictionary)
|
||||
|
||||
return ParsedItem(uniqueID: uniqueID, feedURL: feedURL, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments)
|
||||
return ParsedItem(syncServiceID: nil, uniqueID: uniqueID, feedURL: feedURL, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: summary, imageURL: imageURL, bannerImageURL: bannerImageURL, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: tags, attachments: attachments)
|
||||
}
|
||||
|
||||
static func parseUniqueID(_ itemDictionary: JSONDictionary) -> String? {
|
||||
|
@ -127,7 +127,7 @@ private extension RSSInJSONParser {
|
||||
}
|
||||
|
||||
if let uniqueID = uniqueID {
|
||||
return ParsedItem(uniqueID: uniqueID, feedURL: feedURL, url: nil, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: nil, authors: authors, tags: tags, attachments: attachments)
|
||||
return ParsedItem(syncServiceID: nil, uniqueID: uniqueID, feedURL: feedURL, url: nil, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: contentText, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: nil, authors: authors, tags: tags, attachments: attachments)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ public struct ParsedItem: Hashable {
|
||||
self.authors = authors
|
||||
self.tags = tags
|
||||
self.attachments = attachments
|
||||
self.hashValue = articleID.hashValue
|
||||
self.hashValue = feedURL.hashValue ^ uniqueID.hashValue
|
||||
}
|
||||
|
||||
public static func ==(lhs: ParsedItem, rhs: ParsedItem) -> Bool {
|
||||
|
@ -46,7 +46,7 @@ private extension RSParsedFeedTransformer {
|
||||
let dateModified = parsedArticle.dateModified
|
||||
let authors = parsedAuthors(parsedArticle.author)
|
||||
|
||||
return ParsedItem(uniqueID: uniqueID, feedURL: parsedArticle.feedURL, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: nil, attachments: nil)
|
||||
return ParsedItem(syncServiceID: nil, uniqueID: uniqueID, feedURL: parsedArticle.feedURL, url: url, externalURL: externalURL, title: title, contentHTML: contentHTML, contentText: nil, summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: datePublished, dateModified: dateModified, authors: authors, tags: nil, attachments: nil)
|
||||
}
|
||||
|
||||
static func parsedAuthors(_ authorEmailAddress: String?) -> [ParsedAuthor]? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user