Fix some Database.framework build errors. Add Author cache.

This commit is contained in:
Brent Simmons 2017-09-09 12:57:24 -07:00
parent 4d816850d6
commit 7680760537
6 changed files with 92 additions and 68 deletions

View File

@ -293,7 +293,7 @@ private extension ArticlesTable {
// MARK: Update Existing Articles
func articlesWithRelatedObjectChanges(_ comparisonKeyPath: Keypath<Article, Set<AnyHashable>>, _ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
func articlesWithRelatedObjectChanges(_ comparisonKeyPath: KeyPath<Article, Set<AnyHashable>>, _ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article]) -> Set<Article> {
return updatedArticles.filter{ (updatedArticle) -> Bool in
if let fetchedArticle = fetchedArticles[updatedArticle.articleID] {
@ -304,7 +304,7 @@ private extension ArticlesTable {
}
}
func updateRelatedObjects(_ comparisonKeyPath: Keypath<Article, Set<AnyHashable>>, _ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ lookupTable: DatabaseLookupTable, _ database: FMDatabase) {
func updateRelatedObjects(_ comparisonKeyPath: KeyPath<Article, Set<AnyHashable>>, _ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ lookupTable: DatabaseLookupTable, _ database: FMDatabase) {
let articlesWithChanges = articlesWithRelatedObjectChanges(comparisonKeyPath, updatedArticles, fetchedArticles)
if !articlesWithChanges.isEmpty {
@ -312,7 +312,7 @@ private extension ArticlesTable {
}
}
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _fetchedArticles: [String: Article], _ database: FMDatabase) {
func saveUpdatedRelatedObjects(_ updatedArticles: Set<Article>, _ fetchedArticles: [String: Article], _ database: FMDatabase) {
updateRelatedObjects(\Article.tags, updatedArticles, fetchedArticles, tagsLookupTable, database)
updateRelatedObjects(\Article.authors, updatedArticles, fetchedArticles, authorsLookupTable, database)

View File

@ -31,7 +31,7 @@ final class AuthorsTable: DatabaseRelatedObjectsTable {
func objectWithRow(_ row: FMResultSet) -> DatabaseObject? {
if let author = authorWithRow(row) {
if let author = Author.authorWithRow(row) {
return author as DatabaseObject
}
return nil
@ -42,23 +42,3 @@ final class AuthorsTable: DatabaseRelatedObjectsTable {
}
}
private extension AuthorsTable {
func authorWithRow(_ row: FMResultSet) -> Author? {
guard let authorID = row.string(forColumn: DatabaseKey.authorID) else {
return nil
}
if let cachedAuthor = Author.cachedAuthor[authorID] {
return cachedAuthor
}
guard let author = Author(authorID: authorID, row: row) else {
return nil
}
cache[authorID] = author
return author
}
}

View File

@ -35,7 +35,7 @@ extension Article {
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
let accountInfo: [String: Any]? = nil // TODO
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)
self.init(accountID: accountID, 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)
}
init(parsedItem: ParsedItem, accountID: String, feedID: String) {
@ -44,7 +44,7 @@ extension Article {
let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments)
let tags = tagSetWithParsedTags(parsedItem.tags)
self.init(account: account, articleID: parsedItem.syncServiceID, feedID: feedID, uniqueID: parsedItem.uniqueID, title: parsedItem.title, contentHTML: parsedItem.contentHTML, contentText: parsedItem.contentText, url: parsedItem.url, externalURL: parsedItem.externalURL, summary: parsedItem.summary, imageURL: parsedItem.imageURL, bannerImageURL: parsedItem.bannerImageURL, datePublished: parsedItem.datePublished, dateModified: parsedItem.dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: nil)
self.init(accountID: accountID, articleID: parsedItem.syncServiceID, feedID: feedID, uniqueID: parsedItem.uniqueID, title: parsedItem.title, contentHTML: parsedItem.contentHTML, contentText: parsedItem.contentText, url: parsedItem.url, externalURL: parsedItem.externalURL, summary: parsedItem.summary, imageURL: parsedItem.imageURL, bannerImageURL: parsedItem.bannerImageURL, datePublished: parsedItem.datePublished, dateModified: parsedItem.dateModified, authors: authors, tags: tags, attachments: attachments, accountInfo: nil)
}
func databaseDictionary() -> NSDictionary {
@ -72,7 +72,7 @@ extension Article {
return d.copy() as! NSDictionary
}
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String>, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) {
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) {
if self[keyPath: comparisonKeyPath] != otherArticle[keyPath: comparisonKeyPath] {
dictionary.addOptionalStringDefaultingEmpty(self[keyPath: comparisonKeyPath], key)
@ -86,8 +86,13 @@ extension Article {
}
let d = NSMutableDictionary()
if uniqueID != otherArticle.uniqueID {
// This should be super-rare, if ever.
if !otherArticle.uniqueID.isEmpty {
d[DatabaseKey.uniqueID] = otherArticle.uniqueID
}
}
addPossibleStringChangeWithKeyPath(\Article.uniqueID, otherArticle, DatabaseKey.uniqueID, d)
addPossibleStringChangeWithKeyPath(\Article.title, otherArticle, DatabaseKey.title, d)
addPossibleStringChangeWithKeyPath(\Article.contentHTML, otherArticle, DatabaseKey.contentHTML, d)
addPossibleStringChangeWithKeyPath(\Article.contentText, otherArticle, DatabaseKey.contentText, d)
@ -100,12 +105,12 @@ extension Article {
// If updated versions of dates are nil, and we have existing dates, keep the existing dates.
// This is data thats good to have, and its likely that a feed removing dates is doing so in error.
if article.datePublished != otherArticle.datePublished {
if datePublished != otherArticle.datePublished {
if let updatedDatePublished = otherArticle.datePublished {
d[DatabaseKey.datePublished] = updatedDatePublished
}
}
if article.dateModified != otherArticle.dateModified {
if dateModified != otherArticle.dateModified {
if let updatedDateModified = otherArticle.dateModified {
d[DatabaseKey.dateModified] = updatedDateModified
}
@ -113,7 +118,7 @@ extension Article {
// TODO: accountInfo
if d.isEmpty {
if d.count < 1 {
return nil
}
@ -143,26 +148,6 @@ extension Set where Element == Article {
return Set<String>(map { $0.databaseID })
}
func eachHasAStatus() -> Bool {
for article in self {
if article.status == nil {
return false
}
}
return true
}
func missingStatuses() -> Set<Article> {
return Set<Article>(self.filter { $0.status == nil })
}
func statuses() -> Set<ArticleStatus> {
return Set<ArticleStatus>(self.flatMap { $0.status })
}
func dictionary() -> [String: Article] {
var d = [String: Article]()

View File

@ -13,32 +13,39 @@ import RSParser
extension Author {
init?(authorID: String, row: FMResultSet) {
let name = row.string(forColumn: DatabaseKey.name)
let url = row.string(forColumn: DatabaseKey.url)
let avatarURL = row.string(forColumn: DatabaseKey.avatarURL)
let emailAddress = row.string(forColumn: DatabaseKey.emailAddress)
self.init(authorID: authorID, name: name, url: url, avatarURL: avatarURL, emailAddress: emailAddress)
}
init?(parsedAuthor: ParsedAuthor) {
self.init(authorID: nil, name: parsedAuthor.name, url: parsedAuthor.url, avatarURL: parsedAuthor.avatarURL, emailAddress: parsedAuthor.emailAddress)
}
static func authorsWithParsedAuthors(_ parsedAuthors: [ParsedAuthor]?) -> Set<Author>? {
assert(!Thread.isMainThread)
guard let parsedAuthors = parsedAuthors else {
return nil
}
let authors = Set(parsedAuthors.flatMap { Author(parsedAuthor: $0) })
let authors = Set(parsedAuthors.flatMap { authorWithParsedAuthor($0) })
return authors.isEmpty ? nil : authors
}
static func authorWithRow(_ row: FMResultSet) -> Author? {
guard let authorID = row.string(forColumn: DatabaseKey.authorID) else {
return nil
}
if let cachedAuthor = cachedAuthor(authorID) {
return cachedAuthor
}
guard let author = Author(authorID: authorID, row: row) else {
return nil
}
cacheAuthor(author)
return author
}
}
// MARK: - DatabaseObject
extension Author: DatabaseObject {
public var databaseID: String {
@ -47,3 +54,55 @@ extension Author: DatabaseObject {
}
}
}
// MARK: - Private
private extension Author {
init?(authorID: String, row: FMResultSet) {
let name = row.string(forColumn: DatabaseKey.name)
let url = row.string(forColumn: DatabaseKey.url)
let avatarURL = row.string(forColumn: DatabaseKey.avatarURL)
let emailAddress = row.string(forColumn: DatabaseKey.emailAddress)
self.init(authorID: authorID, name: name, url: url, avatarURL: avatarURL, emailAddress: emailAddress)
}
init?(parsedAuthor: ParsedAuthor) {
self.init(authorID: nil, name: parsedAuthor.name, url: parsedAuthor.url, avatarURL: parsedAuthor.avatarURL, emailAddress: parsedAuthor.emailAddress)
}
static func authorWithParsedAuthor(_ parsedAuthor: ParsedAuthor) -> Author? {
if let author = Author(parsedAuthor: parsedAuthor) {
if let authorFromCache = cachedAuthor(author.authorID) {
return authorFromCache
}
cacheAuthor(author)
return author
}
return nil
}
// The authorCache isnt because we need uniquing  its just to cut down
// on the number of Author instances, since they would be frequently duplicated.
// (That is, a given feed might have 10 or 20 or whatever of the same Author.)
private static var authorCache = [String: Author]() //queue-only
static func cachedAuthor(_ authorID: String) -> Author? {
assert(!Thread.isMainThread)
return authorCache[authorID]
}
static func cacheAuthor(_ author: Author) {
assert(!Thread.isMainThread)
authorCache[author.authorID] = author
}
}

View File

@ -169,7 +169,7 @@ private final class StatusCache {
}
}
subscript(_ articleID: String) -> ArticleStatus {
subscript(_ articleID: String) -> ArticleStatus? {
get {
return self[articleID]
}

Binary file not shown.