Allow for multiple sync status records in sync database.
This commit is contained in:
parent
a48cbfe1ca
commit
bedce4946f
|
@ -44,6 +44,7 @@
|
|||
513323082281070D00C30F19 /* AccountFeedbinSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513323072281070C00C30F19 /* AccountFeedbinSyncTest.swift */; };
|
||||
5133230A2281082F00C30F19 /* subscriptions_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 513323092281082F00C30F19 /* subscriptions_initial.json */; };
|
||||
5133230C2281088A00C30F19 /* subscriptions_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230B2281088A00C30F19 /* subscriptions_add.json */; };
|
||||
5139A6382459822D004D960C /* CloudKitArticleStatusUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5139A6372459822D004D960C /* CloudKitArticleStatusUpdate.swift */; };
|
||||
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
|
||||
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; };
|
||||
514BF5202391B0DB00902FE8 /* SingleArticleFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514BF51F2391B0DB00902FE8 /* SingleArticleFetcher.swift */; };
|
||||
|
@ -294,6 +295,7 @@
|
|||
513323072281070C00C30F19 /* AccountFeedbinSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFeedbinSyncTest.swift; sourceTree = "<group>"; };
|
||||
513323092281082F00C30F19 /* subscriptions_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_initial.json; sourceTree = "<group>"; };
|
||||
5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = "<group>"; };
|
||||
5139A6372459822D004D960C /* CloudKitArticleStatusUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitArticleStatusUpdate.swift; sourceTree = "<group>"; };
|
||||
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = "<group>"; };
|
||||
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = "<group>"; };
|
||||
514BF51F2391B0DB00902FE8 /* SingleArticleFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleArticleFetcher.swift; sourceTree = "<group>"; };
|
||||
|
@ -556,6 +558,7 @@
|
|||
519E84A72434C5EF00D238B0 /* CloudKitArticlesZone.swift */,
|
||||
519E84AB2435019100D238B0 /* CloudKitArticlesZoneDelegate.swift */,
|
||||
5150FFFD243823B800C1A442 /* CloudKitError.swift */,
|
||||
5139A6372459822D004D960C /* CloudKitArticleStatusUpdate.swift */,
|
||||
51E4DB2D242633ED0091EB5B /* CloudKitZone.swift */,
|
||||
51C034DE242D65D20014DC71 /* CloudKitZoneResult.swift */,
|
||||
);
|
||||
|
@ -1158,6 +1161,7 @@
|
|||
9E12B0202334696A00ADE5A0 /* FeedlyCreateFeedsForCollectionFoldersOperation.swift in Sources */,
|
||||
552032FD229D5D5A009559E0 /* ReaderAPITagging.swift in Sources */,
|
||||
9EAEC62A23331EE70085D7C9 /* FeedlyOrigin.swift in Sources */,
|
||||
5139A6382459822D004D960C /* CloudKitArticleStatusUpdate.swift in Sources */,
|
||||
9E5EC15B23E01DEF00A4E503 /* FeedlyRTLTextSanitizer.swift in Sources */,
|
||||
51B36305244B6135000DEF2A /* TwitterEntities.swift in Sources */,
|
||||
5132DE832449306F00806ADE /* TwitterStatus.swift in Sources */,
|
||||
|
|
|
@ -120,12 +120,15 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
|||
|
||||
func processWithArticles(_ articles: Set<Article>) {
|
||||
|
||||
let syncStatusesDict = Dictionary(grouping: syncStatuses, by: { $0.articleID })
|
||||
let articlesDict = articles.reduce(into: [String: Article]()) { result, article in
|
||||
result[article.articleID] = article
|
||||
}
|
||||
let statusedArticles = syncStatuses.map { ($0, articlesDict[$0.articleID]) }
|
||||
let statusUpdates = syncStatusesDict.map { (key, value) in
|
||||
return CloudKitArticleStatusUpdate(articleID: key, statuses: value, article: articlesDict[key])
|
||||
}
|
||||
|
||||
self.articlesZone.modifyArticles(statusedArticles) { result in
|
||||
self.articlesZone.modifyArticles(statusUpdates) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.database.deleteSelectedForProcessing(syncStatuses.map({ $0.articleID })) { _ in
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// CloudKitArticleStatusUpdate.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Maurice Parker on 4/29/20.
|
||||
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SyncDatabase
|
||||
import Articles
|
||||
|
||||
struct CloudKitArticleStatusUpdate {
|
||||
|
||||
enum Record {
|
||||
case all
|
||||
case statusOnly
|
||||
case delete
|
||||
}
|
||||
|
||||
var articleID: String
|
||||
var statuses: [SyncStatus]
|
||||
var article: Article?
|
||||
|
||||
var record: Record {
|
||||
if statuses.contains(where: { $0.key == .deleted }) {
|
||||
return .delete
|
||||
}
|
||||
|
||||
if let article = article {
|
||||
if statuses.contains(where: { $0.key == .new }) {
|
||||
return .all
|
||||
}
|
||||
if article.status.read == false || article.status.starred == true {
|
||||
return .all
|
||||
}
|
||||
}
|
||||
|
||||
return .statusOnly
|
||||
}
|
||||
|
||||
var isRead: Bool {
|
||||
if let article = article {
|
||||
return article.status.read
|
||||
}
|
||||
|
||||
if let status = statuses.first(where: { $0.key == .read }) {
|
||||
return status.flag
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var isStarred: Bool {
|
||||
if let article = article {
|
||||
return article.status.starred
|
||||
}
|
||||
|
||||
if let status = statuses.first(where: { $0.key == .starred }) {
|
||||
return status.flag
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
|
@ -104,8 +104,8 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
delete(ckQuery: ckQuery, completion: completion)
|
||||
}
|
||||
|
||||
func modifyArticles(_ statusArticles: [(status: SyncStatus, article: Article?)], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard !statusArticles.isEmpty else {
|
||||
func modifyArticles(_ statusUpdates: [CloudKitArticleStatusUpdate], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard !statusUpdates.isEmpty else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
@ -113,25 +113,16 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
var modifyRecords = [CKRecord]()
|
||||
var deleteRecordIDs = [CKRecord.ID]()
|
||||
|
||||
for statusArticle in statusArticles {
|
||||
switch (statusArticle.status.key, statusArticle.status.flag) {
|
||||
case (.new, _):
|
||||
modifyRecords.append(makeStatusRecord(statusArticle))
|
||||
if let article = statusArticle.article {
|
||||
if article.status.read == false || article.status.starred == true {
|
||||
modifyRecords.append(makeArticleRecord(article))
|
||||
}
|
||||
}
|
||||
case (.starred, true), (.read, false):
|
||||
modifyRecords.append(makeStatusRecord(statusArticle))
|
||||
if let article = statusArticle.article {
|
||||
modifyRecords.append(makeArticleRecord(article))
|
||||
}
|
||||
case (.deleted, true):
|
||||
deleteRecordIDs.append(CKRecord.ID(recordName: statusID(statusArticle.status.articleID), zoneID: Self.zoneID))
|
||||
default:
|
||||
modifyRecords.append(makeStatusRecord(statusArticle))
|
||||
deleteRecordIDs.append(CKRecord.ID(recordName: articleID(statusArticle.status.articleID), zoneID: Self.zoneID))
|
||||
for statusUpdate in statusUpdates {
|
||||
switch statusUpdate.record {
|
||||
case .all:
|
||||
modifyRecords.append(makeStatusRecord(statusUpdate))
|
||||
modifyRecords.append(makeArticleRecord(statusUpdate.article!))
|
||||
case .delete:
|
||||
deleteRecordIDs.append(CKRecord.ID(recordName: statusID(statusUpdate.articleID), zoneID: Self.zoneID))
|
||||
case .statusOnly:
|
||||
modifyRecords.append(makeStatusRecord(statusUpdate))
|
||||
deleteRecordIDs.append(CKRecord.ID(recordName: articleID(statusUpdate.articleID), zoneID: Self.zoneID))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +131,7 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
case .success:
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
self.handleModifyArticlesError(error, statusArticles: statusArticles, completion: completion)
|
||||
self.handleModifyArticlesError(error, statusUpdates: statusUpdates, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,12 +140,12 @@ final class CloudKitArticlesZone: CloudKitZone {
|
|||
|
||||
private extension CloudKitArticlesZone {
|
||||
|
||||
func handleModifyArticlesError(_ error: Error, statusArticles: [(status: SyncStatus, article: Article?)], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
func handleModifyArticlesError(_ error: Error, statusUpdates: [CloudKitArticleStatusUpdate], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
if case CloudKitZoneError.userDeletedZone = error {
|
||||
self.createZoneRecord() { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.modifyArticles(statusArticles, completion: completion)
|
||||
self.modifyArticles(statusUpdates, completion: completion)
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
@ -183,28 +174,16 @@ private extension CloudKitArticlesZone {
|
|||
return record
|
||||
}
|
||||
|
||||
func makeStatusRecord(_ statusArticle: (status: SyncStatus, article: Article?)) -> CKRecord {
|
||||
let status = statusArticle.status
|
||||
let recordID = CKRecord.ID(recordName: statusID(status.articleID), zoneID: Self.zoneID)
|
||||
func makeStatusRecord(_ statusUpdate: CloudKitArticleStatusUpdate) -> CKRecord {
|
||||
let recordID = CKRecord.ID(recordName: statusID(statusUpdate.articleID), zoneID: Self.zoneID)
|
||||
let record = CKRecord(recordType: CloudKitArticleStatus.recordType, recordID: recordID)
|
||||
|
||||
if let webFeedExternalID = statusArticle.article?.webFeed?.externalID {
|
||||
if let webFeedExternalID = statusUpdate.article?.webFeed?.externalID {
|
||||
record[CloudKitArticleStatus.Fields.webFeedExternalID] = webFeedExternalID
|
||||
}
|
||||
|
||||
if let article = statusArticle.article {
|
||||
record[CloudKitArticleStatus.Fields.read] = article.status.read ? "1" : "0"
|
||||
record[CloudKitArticleStatus.Fields.starred] = article.status.starred ? "1" : "0"
|
||||
} else {
|
||||
switch status.key {
|
||||
case .read:
|
||||
record[CloudKitArticleStatus.Fields.read] = status.flag ? "1" : "0"
|
||||
case .starred:
|
||||
record[CloudKitArticleStatus.Fields.starred] = status.flag ? "1" : "0"
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
record[CloudKitArticleStatus.Fields.read] = statusUpdate.isRead ? "1" : "0"
|
||||
record[CloudKitArticleStatus.Fields.starred] = statusUpdate.isStarred ? "1" : "0"
|
||||
|
||||
return record
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue