This commit is contained in:
Maurice Parker 2019-09-29 14:07:52 -05:00
commit 56cdac6519
5 changed files with 48 additions and 28 deletions

View File

@ -1115,7 +1115,7 @@ private extension FeedbinAccountDelegate {
let parsedItems: [ParsedItem] = entries.map { entry in
let authors = Set([ParsedAuthor(name: entry.authorName, url: entry.jsonFeed?.jsonFeedAuthor?.url, avatarURL: entry.jsonFeed?.jsonFeedAuthor?.avatarURL, emailAddress: nil)])
return ParsedItem(syncServiceID: String(entry.articleID), uniqueID: String(entry.articleID), feedURL: String(entry.feedID), url: nil, externalURL: entry.url, title: entry.title, contentHTML: entry.contentHTML, contentText: nil, summary: entry.summary, imageURL: nil, bannerImageURL: nil, datePublished: entry.parseDatePublished(), dateModified: nil, authors: authors, tags: nil, attachments: nil)
return ParsedItem(syncServiceID: String(entry.articleID), uniqueID: String(entry.articleID), feedURL: String(entry.feedID), url: nil, externalURL: entry.url, title: entry.title, contentHTML: entry.contentHTML, contentText: nil, summary: entry.summary, imageURL: nil, bannerImageURL: nil, datePublished: entry.parsedDatePublished, dateModified: nil, authors: authors, tags: nil, attachments: nil)
}
return Set(parsedItems)

View File

@ -10,7 +10,7 @@ import Foundation
import RSParser
import RSCore
struct FeedbinEntry: Codable {
final class FeedbinEntry: Codable {
let articleID: Int
let feedID: Int
@ -23,6 +23,19 @@ struct FeedbinEntry: Codable {
let dateArrived: String?
let jsonFeed: FeedbinEntryJSONFeed?
// Feedbin dates can't be decoded by the JSONDecoding 8601 decoding strategy. Feedbin
// requires a very specific date formatter to work and even then it fails occasionally.
// Rather than loose all the entries we only lose the one date by decoding as a string
// and letting the one date fail when parsed.
lazy var parsedDatePublished: Date? = {
if let datePublished = datePublished {
return RSDateWithString(datePublished)
}
else {
return nil
}
}()
enum CodingKeys: String, CodingKey {
case articleID = "id"
case feedID = "feed_id"
@ -35,19 +48,6 @@ struct FeedbinEntry: Codable {
case dateArrived = "created_at"
case jsonFeed = "json_feed"
}
// Feedbin dates can't be decoded by the JSONDecoding 8601 decoding strategy. Feedbin
// requires a very specific date formatter to work and even then it fails occasionally.
// Rather than loose all the entries we only lose the one date by decoding as a string
// and letting the one date fail when parsed.
func parseDatePublished() -> Date? {
if datePublished != nil {
return FeedbinDate.formatter.date(from: datePublished!)
} else {
return nil
}
}
}
struct FeedbinEntryJSONFeed: Codable {

View File

@ -20,6 +20,7 @@ final class ArticlesTable: DatabaseTable {
private let statusesTable: StatusesTable
private let authorsLookupTable: DatabaseLookupTable
private let attachmentsLookupTable: DatabaseLookupTable
private var databaseArticlesCache = [String: DatabaseArticle]()
private lazy var searchTable: SearchTable = {
return SearchTable(queue: queue, articlesTable: self)
@ -482,16 +483,21 @@ private extension ArticlesTable {
func makeDatabaseArticles(with resultSet: FMResultSet) -> Set<DatabaseArticle> {
let articles = resultSet.mapToSet { (row) -> DatabaseArticle? in
// The resultSet is a result of a JOIN query with the statuses table,
// so we can get the statuses at the same time and avoid additional database lookups.
guard let status = statusesTable.statusWithRow(resultSet) else {
assertionFailure("Expected status.")
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
assertionFailure("Expected articleID.")
return nil
}
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
assertionFailure("Expected articleID.")
// Articles are removed from the cache when theyre updated.
// See saveUpdatedArticles.
if let databaseArticle = databaseArticlesCache[articleID] {
return databaseArticle
}
// The resultSet is a result of a JOIN query with the statuses table,
// so we can get the statuses at the same time and avoid additional database lookups.
guard let status = statusesTable.statusWithRow(resultSet, articleID: articleID) else {
assertionFailure("Expected status.")
return nil
}
guard let feedID = row.string(forColumn: DatabaseKey.feedID) else {
@ -514,7 +520,9 @@ private extension ArticlesTable {
let datePublished = row.date(forColumn: DatabaseKey.datePublished)
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
return DatabaseArticle(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, status: status)
let databaseArticle = DatabaseArticle(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, status: status)
databaseArticlesCache[articleID] = databaseArticle
return databaseArticle
}
return articles
@ -670,6 +678,7 @@ private extension ArticlesTable {
func saveUpdatedArticles(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
removeArticlesFromDatabaseArticlesCache(updatedArticles)
saveUpdatedRelatedObjects(updatedArticles, fetchedArticles, database)
for updatedArticle in updatedArticles {
@ -690,10 +699,17 @@ private extension ArticlesTable {
// Not unexpected. There may be no changes.
return
}
updateRowsWithDictionary(changesDictionary, whereKey: DatabaseKey.articleID, matches: updatedArticle.articleID, database: database)
}
func removeArticlesFromDatabaseArticlesCache(_ updatedArticles: Set<Article>) {
let articleIDs = updatedArticles.articleIDs()
for articleID in articleIDs {
databaseArticlesCache[articleID] = nil
}
}
func statusIndicatesArticleIsIgnorable(_ status: ArticleStatus) -> Bool {
// Ignorable articles: either userDeleted==1 or (not starred and arrival date > 4 months).
if status.userDeleted {

View File

@ -105,17 +105,21 @@ final class StatusesTable: DatabaseTable {
guard let articleID = row.string(forColumn: DatabaseKey.articleID) else {
return nil
}
return statusWithRow(row, articleID: articleID)
}
func statusWithRow(_ row: FMResultSet, articleID: String) ->ArticleStatus? {
if let cachedStatus = cache[articleID] {
return cachedStatus
}
guard let dateArrived = row.date(forColumn: DatabaseKey.dateArrived) else {
return nil
}
let articleStatus = ArticleStatus(articleID: articleID, dateArrived: dateArrived, row: row)
cache.addStatusIfNotCached(articleStatus)
return articleStatus
}

View File

@ -16,7 +16,7 @@ Heres [How to Support NetNewsWire](Technotes/HowToSupportNetNewsWire.markdown
#### Community
[Join the Slack group](https://join.slack.com/t/netnewswire/shared_invite/enQtNjM4MDA1MjQzMDkzLTNlNjBhOWVhYzdhYjA4ZWFhMzQ1MTUxYjU0NTE5ZGY0YzYwZWJhNjYwNTNmNTg2NjIwYWY4YzhlYzk5NmU3ZTc) to talk with other NetNewsWire users — and to help out, if youd like to, by testing, coding, writing, providing feedback, or just helping us think things through. Everybody is welcome and encouraged to join.
[Join the Slack group](https://ranchero.com/netnewswire/slack) to talk with other NetNewsWire users — and to help out, if youd like to, by testing, coding, writing, providing feedback, or just helping us think things through. Everybody is welcome and encouraged to join.
Every community member is expected to abide by the code of conduct which is included in the [Contributing](CONTRIBUTING.md) page.