2017-07-04 00:04:31 +02:00
|
|
|
|
//
|
|
|
|
|
// Article+Database.swift
|
|
|
|
|
// Database
|
|
|
|
|
//
|
|
|
|
|
// Created by Brent Simmons on 7/3/17.
|
|
|
|
|
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
import RSDatabase
|
|
|
|
|
import Data
|
2017-09-05 02:10:02 +02:00
|
|
|
|
import RSParser
|
2017-07-04 00:04:31 +02:00
|
|
|
|
|
|
|
|
|
extension Article {
|
|
|
|
|
|
2017-09-08 22:36:30 +02:00
|
|
|
|
init?(row: FMResultSet, authors: Set<Author>, attachments: Set<Attachment>, tags: Set<String>, accountID: String) {
|
2017-07-04 00:04:31 +02:00
|
|
|
|
|
2017-07-08 02:49:16 +02:00
|
|
|
|
guard let feedID = row.string(forColumn: DatabaseKey.feedID) else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
guard let uniqueID = row.string(forColumn: DatabaseKey.uniqueID) else {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let articleID = row.string(forColumn: DatabaseKey.articleID)!
|
|
|
|
|
let title = row.string(forColumn: DatabaseKey.title)
|
|
|
|
|
let contentHTML = row.string(forColumn: DatabaseKey.contentHTML)
|
|
|
|
|
let contentText = row.string(forColumn: DatabaseKey.contentText)
|
|
|
|
|
let url = row.string(forColumn: DatabaseKey.url)
|
|
|
|
|
let externalURL = row.string(forColumn: DatabaseKey.externalURL)
|
|
|
|
|
let summary = row.string(forColumn: DatabaseKey.summary)
|
|
|
|
|
let imageURL = row.string(forColumn: DatabaseKey.imageURL)
|
|
|
|
|
let bannerImageURL = row.string(forColumn: DatabaseKey.bannerImageURL)
|
|
|
|
|
let datePublished = row.date(forColumn: DatabaseKey.datePublished)
|
|
|
|
|
let dateModified = row.date(forColumn: DatabaseKey.dateModified)
|
2017-09-10 03:46:58 +02:00
|
|
|
|
let accountInfo: AccountInfo? = nil // TODO
|
2017-08-22 16:45:09 +02:00
|
|
|
|
|
2017-09-09 21:57:24 +02:00
|
|
|
|
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)
|
2017-09-05 02:10:02 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 22:36:30 +02:00
|
|
|
|
init(parsedItem: ParsedItem, accountID: String, feedID: String) {
|
2017-09-05 02:10:02 +02:00
|
|
|
|
|
|
|
|
|
let authors = Author.authorsWithParsedAuthors(parsedItem.authors)
|
|
|
|
|
let attachments = Attachment.attachmentsWithParsedAttachments(parsedItem.attachments)
|
|
|
|
|
let tags = tagSetWithParsedTags(parsedItem.tags)
|
|
|
|
|
|
2017-09-09 21:57:24 +02:00
|
|
|
|
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)
|
2017-07-04 00:04:31 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func databaseDictionary() -> NSDictionary {
|
|
|
|
|
|
2017-08-21 07:43:46 +02:00
|
|
|
|
let d = NSMutableDictionary()
|
2017-07-04 00:04:31 +02:00
|
|
|
|
|
2017-09-05 02:10:02 +02:00
|
|
|
|
d[DatabaseKey.articleID] = articleID
|
|
|
|
|
d[DatabaseKey.feedID] = feedID
|
|
|
|
|
d[DatabaseKey.uniqueID] = uniqueID
|
|
|
|
|
|
|
|
|
|
d.addOptionalString(title, DatabaseKey.title)
|
|
|
|
|
d.addOptionalString(contentHTML, DatabaseKey.contentHTML)
|
2017-09-09 21:09:48 +02:00
|
|
|
|
d.addOptionalString(contentText, DatabaseKey.contentText)
|
2017-09-05 02:10:02 +02:00
|
|
|
|
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
|
2017-07-04 00:04:31 +02:00
|
|
|
|
|
|
|
|
|
return d.copy() as! NSDictionary
|
|
|
|
|
}
|
2017-09-09 21:09:48 +02:00
|
|
|
|
|
2017-09-09 21:57:24 +02:00
|
|
|
|
private func addPossibleStringChangeWithKeyPath(_ comparisonKeyPath: KeyPath<Article,String?>, _ otherArticle: Article, _ key: String, _ dictionary: NSMutableDictionary) {
|
2017-09-09 21:09:48 +02:00
|
|
|
|
|
|
|
|
|
if self[keyPath: comparisonKeyPath] != otherArticle[keyPath: comparisonKeyPath] {
|
|
|
|
|
dictionary.addOptionalStringDefaultingEmpty(self[keyPath: comparisonKeyPath], key)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func changesFrom(_ otherArticle: Article) -> NSDictionary? {
|
|
|
|
|
|
|
|
|
|
if self == otherArticle {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let d = NSMutableDictionary()
|
2017-09-09 21:57:24 +02:00
|
|
|
|
if uniqueID != otherArticle.uniqueID {
|
|
|
|
|
// This should be super-rare, if ever.
|
|
|
|
|
if !otherArticle.uniqueID.isEmpty {
|
|
|
|
|
d[DatabaseKey.uniqueID] = otherArticle.uniqueID
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-09 21:09:48 +02:00
|
|
|
|
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.title, otherArticle, DatabaseKey.title, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.contentHTML, otherArticle, DatabaseKey.contentHTML, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.contentText, otherArticle, DatabaseKey.contentText, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.url, otherArticle, DatabaseKey.url, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.externalURL, otherArticle, DatabaseKey.externalURL, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.summary, otherArticle, DatabaseKey.summary, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.imageURL, otherArticle, DatabaseKey.imageURL, d)
|
|
|
|
|
addPossibleStringChangeWithKeyPath(\Article.bannerImageURL, otherArticle, DatabaseKey.bannerImageURL, d)
|
|
|
|
|
|
|
|
|
|
// If updated versions of dates are nil, and we have existing dates, keep the existing dates.
|
|
|
|
|
// This is data that’s good to have, and it’s likely that a feed removing dates is doing so in error.
|
|
|
|
|
|
2017-09-09 21:57:24 +02:00
|
|
|
|
if datePublished != otherArticle.datePublished {
|
2017-09-09 21:09:48 +02:00
|
|
|
|
if let updatedDatePublished = otherArticle.datePublished {
|
|
|
|
|
d[DatabaseKey.datePublished] = updatedDatePublished
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-09 21:57:24 +02:00
|
|
|
|
if dateModified != otherArticle.dateModified {
|
2017-09-09 21:09:48 +02:00
|
|
|
|
if let updatedDateModified = otherArticle.dateModified {
|
|
|
|
|
d[DatabaseKey.dateModified] = updatedDateModified
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: accountInfo
|
|
|
|
|
|
2017-09-09 21:57:24 +02:00
|
|
|
|
if d.count < 1 {
|
2017-09-09 21:09:48 +02:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return d
|
|
|
|
|
}
|
2017-09-05 02:10:02 +02:00
|
|
|
|
|
2017-09-10 03:46:58 +02:00
|
|
|
|
static func articlesWithParsedItems(_ parsedItems: Set<ParsedItem>, _ accountID: String, _ feedID: String) -> Set<Article> {
|
2017-09-05 17:53:45 +02:00
|
|
|
|
|
2017-09-06 22:33:04 +02:00
|
|
|
|
return Set(parsedItems.map{ Article(parsedItem: $0, accountID: accountID, feedID: feedID) })
|
2017-09-05 02:10:02 +02:00
|
|
|
|
}
|
2017-09-05 17:53:45 +02:00
|
|
|
|
|
2017-07-04 00:04:31 +02:00
|
|
|
|
}
|
2017-08-07 06:16:13 +02:00
|
|
|
|
|
2017-08-21 02:46:15 +02:00
|
|
|
|
extension Article: DatabaseObject {
|
|
|
|
|
|
2017-08-21 07:43:46 +02:00
|
|
|
|
public var databaseID: String {
|
2017-08-21 02:46:15 +02:00
|
|
|
|
get {
|
|
|
|
|
return articleID
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-07 06:16:13 +02:00
|
|
|
|
extension Set where Element == Article {
|
|
|
|
|
|
|
|
|
|
func articleIDs() -> Set<String> {
|
|
|
|
|
|
2017-08-21 22:31:14 +02:00
|
|
|
|
return Set<String>(map { $0.databaseID })
|
2017-08-07 06:16:13 +02:00
|
|
|
|
}
|
2017-08-27 00:37:15 +02:00
|
|
|
|
|
2017-09-02 23:19:42 +02:00
|
|
|
|
func dictionary() -> [String: Article] {
|
|
|
|
|
|
|
|
|
|
var d = [String: Article]()
|
|
|
|
|
for article in self {
|
|
|
|
|
d[article.articleID] = article
|
|
|
|
|
}
|
|
|
|
|
return d
|
|
|
|
|
}
|
2017-09-05 02:10:02 +02:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-09 21:09:48 +02:00
|
|
|
|
func addOptionalStringDefaultingEmpty(_ value: String?, _ key: String) {
|
|
|
|
|
|
|
|
|
|
if let value = value {
|
|
|
|
|
self[key] = value
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
self[key] = ""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-05 02:10:02 +02:00
|
|
|
|
func addOptionalDate(_ date: Date?, _ key: String) {
|
|
|
|
|
|
|
|
|
|
if let date = date {
|
|
|
|
|
self[key] = date as NSDate
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-07 06:16:13 +02:00
|
|
|
|
}
|