Refactored starred article passing to make it more reliable
This commit is contained in:
parent
f143248e08
commit
10a87ccfb6
|
@ -41,19 +41,7 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
static let imageURL = "imageURL"
|
||||
static let datePublished = "datePublished"
|
||||
static let dateModified = "dateModified"
|
||||
static let authors = "authors"
|
||||
}
|
||||
}
|
||||
|
||||
struct CloudKitAuthor {
|
||||
static let recordType = "Author"
|
||||
struct Fields {
|
||||
static let article = "article"
|
||||
static let authorID = "authorID"
|
||||
static let name = "name"
|
||||
static let url = "url"
|
||||
static let avatarURL = "avatarURL"
|
||||
static let emailAddress = "emailAddress"
|
||||
static let parsedAuthors = "parsedAuthors"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,47 +72,6 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
}
|
||||
}
|
||||
|
||||
func fetchArticle(articleID: String, completion: @escaping ((Result<(String, ParsedItem), Error>) -> Void)) {
|
||||
|
||||
let statusRecordID = CKRecord.ID(recordName: articleID, zoneID: Self.zoneID)
|
||||
let statusRecordRef = CKRecord.Reference(recordID: statusRecordID, action: .deleteSelf)
|
||||
let predicate = NSPredicate(format: "articleStatus = %@", statusRecordRef)
|
||||
let ckQuery = CKQuery(recordType: CloudKitArticle.recordType, predicate: predicate)
|
||||
|
||||
query(ckQuery) { result in
|
||||
|
||||
switch result {
|
||||
case .success(let articleRecords):
|
||||
if articleRecords.count == 1 {
|
||||
let articleRecord = articleRecords[0]
|
||||
|
||||
let articleRef = CKRecord.Reference(record: articleRecord, action: .deleteSelf)
|
||||
let predicate = NSPredicate(format: "article = %@", articleRef)
|
||||
let ckQuery = CKQuery(recordType: CloudKitAuthor.recordType, predicate: predicate)
|
||||
|
||||
self.query(ckQuery) { result in
|
||||
switch result {
|
||||
case .success(let authorRecords):
|
||||
if let webFeedID = articleRecord[CloudKitArticle.Fields.webFeedID] as? String, let parsedItem = self.makeParsedItem(articleRecord, authorRecords) {
|
||||
completion(.success((webFeedID, parsedItem)))
|
||||
} else {
|
||||
completion(.failure(CloudKitZoneError.unknown))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
completion(.failure(CloudKitZoneError.unknown))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension CloudKitArticlesZone {
|
||||
|
@ -210,58 +157,26 @@ private extension CloudKitArticlesZone {
|
|||
articleRecord[CloudKitArticle.Fields.datePublished] = article.datePublished
|
||||
articleRecord[CloudKitArticle.Fields.dateModified] = article.dateModified
|
||||
|
||||
records.append(articleRecord)
|
||||
let encoder = JSONEncoder()
|
||||
var parsedAuthors = [String]()
|
||||
|
||||
if let authors = article.authors {
|
||||
for author in authors {
|
||||
let authorRecord = CKRecord(recordType: CloudKitAuthor.recordType, recordID: generateRecordID())
|
||||
authorRecord[CloudKitAuthor.Fields.article] = CKRecord.Reference(record: articleRecord, action: .deleteSelf)
|
||||
authorRecord[CloudKitAuthor.Fields.authorID] = author.authorID
|
||||
authorRecord[CloudKitAuthor.Fields.name] = author.name
|
||||
authorRecord[CloudKitAuthor.Fields.url] = author.url
|
||||
authorRecord[CloudKitAuthor.Fields.avatarURL] = author.avatarURL
|
||||
authorRecord[CloudKitAuthor.Fields.emailAddress] = author.emailAddress
|
||||
records.append(authorRecord)
|
||||
let parsedAuthor = ParsedAuthor(name: author.name,
|
||||
url: author.url,
|
||||
avatarURL: author.avatarURL,
|
||||
emailAddress: author.emailAddress)
|
||||
if let data = try? encoder.encode(parsedAuthor), let encodedParsedAuthor = String(data: data, encoding: .utf8) {
|
||||
parsedAuthors.append(encodedParsedAuthor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
articleRecord[CloudKitArticle.Fields.parsedAuthors] = parsedAuthors
|
||||
|
||||
records.append(articleRecord)
|
||||
return records
|
||||
}
|
||||
|
||||
func makeParsedItem(_ articleRecord: CKRecord, _ authorRecords: [CKRecord]) -> ParsedItem? {
|
||||
var parsedAuthors = Set<ParsedAuthor>()
|
||||
|
||||
for authorRecord in authorRecords {
|
||||
let parsedAuthor = ParsedAuthor(name: authorRecord[CloudKitAuthor.Fields.name] as? String,
|
||||
url: authorRecord[CloudKitAuthor.Fields.url] as? String,
|
||||
avatarURL: authorRecord[CloudKitAuthor.Fields.avatarURL] as? String,
|
||||
emailAddress: authorRecord[CloudKitAuthor.Fields.emailAddress] as? String)
|
||||
parsedAuthors.insert(parsedAuthor)
|
||||
}
|
||||
|
||||
guard let uniqueID = articleRecord[CloudKitArticle.Fields.uniqueID] as? String,
|
||||
let feedURL = articleRecord[CloudKitArticle.Fields.webFeedID] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let parsedItem = ParsedItem(syncServiceID: nil,
|
||||
uniqueID: uniqueID,
|
||||
feedURL: feedURL,
|
||||
url: articleRecord[CloudKitArticle.Fields.url] as? String,
|
||||
externalURL: articleRecord[CloudKitArticle.Fields.externalURL] as? String,
|
||||
title: articleRecord[CloudKitArticle.Fields.title] as? String,
|
||||
contentHTML: articleRecord[CloudKitArticle.Fields.contentHTML] as? String,
|
||||
contentText: articleRecord[CloudKitArticle.Fields.contentText] as? String,
|
||||
summary: articleRecord[CloudKitArticle.Fields.summary] as? String,
|
||||
imageURL: articleRecord[CloudKitArticle.Fields.imageURL] as? String,
|
||||
bannerImageURL: articleRecord[CloudKitArticle.Fields.imageURL] as? String,
|
||||
datePublished: articleRecord[CloudKitArticle.Fields.datePublished] as? Date,
|
||||
dateModified: articleRecord[CloudKitArticle.Fields.dateModified] as? Date,
|
||||
authors: parsedAuthors,
|
||||
tags: nil,
|
||||
attachments: nil)
|
||||
|
||||
return parsedItem
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSParser
|
||||
import CloudKit
|
||||
import SyncDatabase
|
||||
|
||||
|
@ -26,7 +27,7 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
|
|||
}
|
||||
|
||||
func cloudKitDidChange(record: CKRecord) {
|
||||
// Process everything in the batch method
|
||||
|
||||
}
|
||||
|
||||
func cloudKitDidDelete(recordKey: CloudKitRecordKey) {
|
||||
|
@ -65,12 +66,14 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate {
|
|||
private extension CloudKitArticlesZoneDelegate {
|
||||
|
||||
func process(records: [CKRecord], pendingReadStatusArticleIDs: Set<String>, pendingStarredStatusArticleIDs: Set<String>, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
let receivedUnreadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ $0.externalID }))
|
||||
let receivedReadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ $0.externalID }))
|
||||
let receivedUnstarredArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "0" }).map({ $0.externalID }))
|
||||
let receivedStarredArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "1" }).map({ $0.externalID }))
|
||||
|
||||
let receivedUnreadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ $0.externalID }))
|
||||
let receivedReadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ $0.externalID }))
|
||||
let receivedUnstarredArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "0" }).map({ $0.externalID }))
|
||||
let receivedStarredArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "1" }).map({ $0.externalID }))
|
||||
|
||||
let receivedStarredArticles = records.filter({ $0.recordType == CloudKitArticlesZone.CloudKitArticle.recordType })
|
||||
|
||||
let updateableUnreadArticleIDs = receivedUnreadArticleIDs.subtracting(pendingReadStatusArticleIDs)
|
||||
let updateableReadArticleIDs = receivedReadArticleIDs.subtracting(pendingReadStatusArticleIDs)
|
||||
let updateableUnstarredArticleIDs = receivedUnstarredArticleIDs.subtracting(pendingStarredStatusArticleIDs)
|
||||
|
@ -98,23 +101,15 @@ private extension CloudKitArticlesZoneDelegate {
|
|||
group.leave()
|
||||
}
|
||||
|
||||
for updateableStarredArticleID in updateableStarredArticleIDs {
|
||||
|
||||
group.enter()
|
||||
articlesZone?.fetchArticle(articleID: updateableStarredArticleID) { result in
|
||||
switch result {
|
||||
case .success(let (webFeedID, parsedItem)):
|
||||
self.account?.update(webFeedID, with: Set([parsedItem])) { databaseError in
|
||||
group.leave()
|
||||
if let databaseError = databaseError {
|
||||
os_log(.error, log: self.log, "Error occurred while storing starred items: %@", databaseError.localizedDescription)
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
for receivedStarredArticle in receivedStarredArticles {
|
||||
if let parsedItem = makeParsedItem(receivedStarredArticle), let statusRef = receivedStarredArticle[CloudKitArticlesZone.CloudKitArticle.Fields.articleStatus] as? CKRecord.Reference {
|
||||
group.enter()
|
||||
self.account?.update(statusRef.recordID.externalID, with: Set([parsedItem])) { databaseError in
|
||||
group.leave()
|
||||
os_log(.error, log: self.log, "Error occurred while retrieving starred items: %@", error.localizedDescription)
|
||||
if let databaseError = databaseError {
|
||||
os_log(.error, log: self.log, "Error occurred while storing starred items: %@", databaseError.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,5 +118,44 @@ private extension CloudKitArticlesZoneDelegate {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func makeParsedItem(_ articleRecord: CKRecord) -> ParsedItem? {
|
||||
var parsedAuthors = Set<ParsedAuthor>()
|
||||
|
||||
let decoder = JSONDecoder()
|
||||
|
||||
if let encodedParsedAuthors = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.parsedAuthors] as? [String] {
|
||||
for encodedParsedAuthor in encodedParsedAuthors {
|
||||
if let data = encodedParsedAuthor.data(using: .utf8), let parsedAuthor = try? decoder.decode(ParsedAuthor.self, from: data) {
|
||||
parsedAuthors.insert(parsedAuthor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let uniqueID = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.uniqueID] as? String,
|
||||
let feedURL = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.webFeedID] as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let parsedItem = ParsedItem(syncServiceID: nil,
|
||||
uniqueID: uniqueID,
|
||||
feedURL: feedURL,
|
||||
url: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.url] as? String,
|
||||
externalURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.externalURL] as? String,
|
||||
title: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.title] as? String,
|
||||
contentHTML: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.contentHTML] as? String,
|
||||
contentText: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.contentText] as? String,
|
||||
summary: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.summary] as? String,
|
||||
imageURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.imageURL] as? String,
|
||||
bannerImageURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.imageURL] as? String,
|
||||
datePublished: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.datePublished] as? Date,
|
||||
dateModified: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.dateModified] as? Date,
|
||||
authors: parsedAuthors,
|
||||
tags: nil,
|
||||
attachments: nil)
|
||||
|
||||
return parsedItem
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 47ba87875fbd026dccc2c4d4382a98cb4a1f1fbc
|
||||
Subproject commit a977d8e84af8645fc8268ac843e8a79b3644b133
|
Loading…
Reference in New Issue