mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Make a mess of things. Article and ArticleStatus are now immutable structs.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import Foundation
|
||||
import RSDatabase
|
||||
import Data
|
||||
import RSParser
|
||||
|
||||
extension Article {
|
||||
|
||||
@@ -35,20 +36,129 @@ extension Article {
|
||||
let accountInfo: [String: Any]? = nil // TODO
|
||||
|
||||
// authors, tags, and attachments are fetched from related tables, after init.
|
||||
let authors: [Author]? = nil
|
||||
let tags: Set<String>? = nil
|
||||
let attachments: [Attachment]? = nil
|
||||
|
||||
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(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: nil, tags: nil, attachments: nil, accountInfo: accountInfo)
|
||||
}
|
||||
|
||||
convenience init(parsedItem: ParsedItem, feedID: String, account: Account) {
|
||||
|
||||
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
||||
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)
|
||||
}
|
||||
|
||||
func databaseDictionary() -> NSDictionary {
|
||||
|
||||
let d = NSMutableDictionary()
|
||||
|
||||
d[DatabaseKey.articleID] = articleID
|
||||
d[DatabaseKey.feedID] = feedID
|
||||
d[DatabaseKey.uniqueID] = uniqueID
|
||||
|
||||
d.addOptionalString(title, DatabaseKey.title)
|
||||
d.addOptionalString(contentHTML, DatabaseKey.contentHTML)
|
||||
d.addOptionalString(url, DatabaseKey.url)
|
||||
d.addOptionalString(externalURL, DatabaseKey.externalURL)
|
||||
d.addOptionalString(summary, DatabaseKey.summary)
|
||||
d.addOptionalString(imageURL, DatabaseKey.imageURL)
|
||||
d.addOptionalString(bannerImageURL, DatabaseKey.bannerImageURL)
|
||||
|
||||
d.addOptionalDate(datePublished, DatabaseKey.datePublished)
|
||||
d.addOptionalDate(dateModified, DatabaseKey.dateModified)
|
||||
|
||||
// TODO: accountInfo
|
||||
|
||||
return d.copy() as! NSDictionary
|
||||
}
|
||||
|
||||
// MARK: Updating with ParsedItem
|
||||
|
||||
func updateTagsWithParsedTags(_ parsedTags: [String]?) -> Bool {
|
||||
|
||||
// Return true if there's a change.
|
||||
|
||||
let currentTags = tags
|
||||
|
||||
if parsedTags == nil && currentTags == nil {
|
||||
return false
|
||||
}
|
||||
if parsedTags != nil && currentTags == nil {
|
||||
tags = Set(parsedItemTags!)
|
||||
return true
|
||||
}
|
||||
if parsedTags == nil && currentTags != nil {
|
||||
tags = nil
|
||||
return true
|
||||
}
|
||||
let parsedTagSet = Set(parsedTags!)
|
||||
if parsedTagSet == tags! {
|
||||
return false
|
||||
}
|
||||
tags = parsedTagSet
|
||||
return true
|
||||
}
|
||||
|
||||
func updateAttachmentsWithParsedAttachments(_ parsedAttachments: [ParsedAttachment]?) -> Bool {
|
||||
|
||||
// Return true if there's a change.
|
||||
|
||||
let currentAttachments = attachments
|
||||
let updatedAttachments = Attachment.attachmentsWithParsedAttachments(parsedAttachments)
|
||||
|
||||
if updatedAttachments == nil && currentAttachments == nil {
|
||||
return false
|
||||
}
|
||||
if updatedAttachments != nil && currentAttachments == nil {
|
||||
attachments = updatedAttachments
|
||||
return true
|
||||
}
|
||||
if updatedAttachments == nil && currentAttachments != nil {
|
||||
attachments = nil
|
||||
return true
|
||||
}
|
||||
|
||||
guard let currentAttachments = currentAttachments, let updatedAttachments = updatedAttachments else {
|
||||
assertionFailure("currentAttachments and updatedAttachments must both be non-nil.")
|
||||
return false
|
||||
}
|
||||
if currentAttachments != updatedAttachments {
|
||||
attachments = updatedAttachments
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func updateAuthorsWithParsedAuthors(_ parsedAuthors: [ParsedAuthor]?) -> Bool {
|
||||
|
||||
// Return true if there's a change.
|
||||
|
||||
let currentAuthors = authors
|
||||
let updatedAuthors = Author.authorsWithParsedAuthors(parsedAuthors)
|
||||
|
||||
if updatedAuthors == nil && currentAuthors == nil {
|
||||
return false
|
||||
}
|
||||
if updatedAuthors != nil && currentAuthors == nil {
|
||||
authors = updatedAuthors
|
||||
return true
|
||||
}
|
||||
if updatedAuthors == nil && currentAuthors != nil {
|
||||
authors = nil
|
||||
return true
|
||||
}
|
||||
|
||||
guard let currentAuthors = currentAuthors, let updatedAuthors = updatedAuthors else {
|
||||
assertionFailure("currentAuthors and updatedAuthors must both be non-nil.")
|
||||
return false
|
||||
}
|
||||
if currentAuthors != updatedAuthors {
|
||||
authors = updatedAuthors
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Article: DatabaseObject {
|
||||
@@ -62,11 +172,6 @@ extension Article: DatabaseObject {
|
||||
|
||||
extension Set where Element == Article {
|
||||
|
||||
func withNilProperty<T>(_ keyPath: KeyPath<Article,T?>) -> Set<Article> {
|
||||
|
||||
return Set(filter{ $0[keyPath: keyPath] == nil })
|
||||
}
|
||||
|
||||
func articleIDs() -> Set<String> {
|
||||
|
||||
return Set<String>(map { $0.databaseID })
|
||||
@@ -84,7 +189,7 @@ extension Set where Element == Article {
|
||||
|
||||
func missingStatuses() -> Set<Article> {
|
||||
|
||||
return withNilProperty(\Article.status)
|
||||
return Set<Article>(self.filter { $0.status == nil })
|
||||
}
|
||||
|
||||
func statuses() -> Set<ArticleStatus> {
|
||||
@@ -100,4 +205,26 @@ extension Set where Element == Article {
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func databaseObjects() -> [DatabaseObject] {
|
||||
|
||||
return self.map{ $0 as DatabaseObject }
|
||||
}
|
||||
}
|
||||
|
||||
private extension NSMutableDictionary {
|
||||
|
||||
func addOptionalString(_ value: String?, _ key: String) {
|
||||
|
||||
if let value = value {
|
||||
self[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func addOptionalDate(_ date: Date?, _ key: String) {
|
||||
|
||||
if let date = date {
|
||||
self[key] = date as NSDate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import Foundation
|
||||
import Data
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
|
||||
extension Attachment {
|
||||
|
||||
@@ -26,6 +27,24 @@ extension Attachment {
|
||||
self.init(attachmentID: attachmentID, url: url, mimeType: mimeType, title: title, sizeInBytes: sizeInBytes, durationInSeconds: durationInSeconds)
|
||||
}
|
||||
|
||||
init?(parsedAttachment: ParsedAttachment) {
|
||||
|
||||
guard let url = parsedAttachment.url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.init(attachmentID: nil, url: url, mimeType: parsedAttachment.mimeType, title: parsedAttachment.title, sizeInBytes: parsedAttachment.sizeInBytes, durationInSeconds: parsedAttachment.durationInSeconds)
|
||||
}
|
||||
|
||||
static func attachmentsWithParsedAttachments(_ parsedAttachments: [ParsedAttachment]?) -> Set<Attachment>? {
|
||||
|
||||
guard let parsedAttachments = parsedAttachments else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let attachments = parsedAttachments.flatMap{ Attachment(parsedAttachment: $0) }
|
||||
return attachments.isEmpty ? nil : Set(attachments)
|
||||
}
|
||||
}
|
||||
|
||||
private func optionalIntForColumn(_ row: FMResultSet, _ columnName: String) -> Int? {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import Foundation
|
||||
import Data
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
|
||||
extension Author {
|
||||
|
||||
@@ -21,6 +22,21 @@ extension Author {
|
||||
|
||||
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>? {
|
||||
|
||||
guard let parsedAuthors = parsedAuthors else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let authors = parsedAuthors.flatMap { Author(parsedAuthor: $0) }
|
||||
return authors.isEmpty ? nil : Set(authors)
|
||||
}
|
||||
}
|
||||
|
||||
extension Author: DatabaseObject {
|
||||
|
||||
@@ -20,3 +20,12 @@ extension String: DatabaseObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func tagSetWithParsedTags(_ parsedTags: [String]?) -> Set<String>? {
|
||||
|
||||
guard let parsedTags = parsedTags, !parsedTags.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return Set(parsedTags)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user