Implement add, move, delete folder operations for feeds.
This commit is contained in:
parent
df1faa368f
commit
90376dac03
|
@ -207,7 +207,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeWebFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
func removeWebFeed(for account: Account, with feed: WebFeed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
accountZone.removeWebFeed(feed) { result in
|
accountZone.removeWebFeed(feed, from: container) { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
container.removeWebFeed(feed)
|
container.removeWebFeed(feed)
|
||||||
|
@ -218,20 +218,33 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func moveWebFeed(for account: Account, with feed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
func moveWebFeed(for account: Account, with feed: WebFeed, from fromContainer: Container, to toContainer: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
from.removeWebFeed(feed)
|
accountZone.moveWebFeed(feed, from: fromContainer, to: toContainer) { result in
|
||||||
to.addWebFeed(feed)
|
switch result {
|
||||||
completion(.success(()))
|
case .success:
|
||||||
|
fromContainer.removeWebFeed(feed)
|
||||||
|
toContainer.addWebFeed(feed)
|
||||||
|
completion(.success(()))
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addWebFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
func addWebFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
container.addWebFeed(feed)
|
accountZone.addWebFeed(feed, to: container) { result in
|
||||||
completion(.success(()))
|
switch result {
|
||||||
|
case .success:
|
||||||
|
container.addWebFeed(feed)
|
||||||
|
completion(.success(()))
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func restoreWebFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
func restoreWebFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
container.addWebFeed(feed)
|
addWebFeed(for: account, with: feed, to: container, completion: completion)
|
||||||
completion(.success(()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> Void) {
|
func createFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> Void) {
|
||||||
|
|
|
@ -94,8 +94,72 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes a web feed from iCloud
|
/// Deletes a web feed from iCloud
|
||||||
func removeWebFeed(_ webFeed: WebFeed, completion: @escaping (Result<Void, Error>) -> Void) {
|
func removeWebFeed(_ webFeed: WebFeed, from: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
delete(externalID: webFeed.externalID , completion: completion)
|
guard let fromContainerExternalID = from.externalID else {
|
||||||
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(externalID: webFeed.externalID) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let record):
|
||||||
|
if let containerExternalIDs = record[CloudKitWebFeed.Fields.containerExternalIDs] as? [String] {
|
||||||
|
var containerExternalIDSet = Set(containerExternalIDs)
|
||||||
|
containerExternalIDSet.remove(fromContainerExternalID)
|
||||||
|
if containerExternalIDSet.isEmpty {
|
||||||
|
self.delete(externalID: webFeed.externalID , completion: completion)
|
||||||
|
} else {
|
||||||
|
record[CloudKitWebFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||||
|
self.save(record, completion: completion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveWebFeed(_ webFeed: WebFeed, from: Container, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
guard let fromContainerExternalID = from.externalID, let toContainerExternalID = to.externalID else {
|
||||||
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(externalID: webFeed.externalID) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let record):
|
||||||
|
if let containerExternalIDs = record[CloudKitWebFeed.Fields.containerExternalIDs] as? [String] {
|
||||||
|
var containerExternalIDSet = Set(containerExternalIDs)
|
||||||
|
containerExternalIDSet.remove(fromContainerExternalID)
|
||||||
|
containerExternalIDSet.insert(toContainerExternalID)
|
||||||
|
record[CloudKitWebFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||||
|
self.save(record, completion: completion)
|
||||||
|
}
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addWebFeed(_ webFeed: WebFeed, to: Container, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
guard let toContainerExternalID = to.externalID else {
|
||||||
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(externalID: webFeed.externalID) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let record):
|
||||||
|
if let containerExternalIDs = record[CloudKitWebFeed.Fields.containerExternalIDs] as? [String] {
|
||||||
|
var containerExternalIDSet = Set(containerExternalIDs)
|
||||||
|
containerExternalIDSet.insert(toContainerExternalID)
|
||||||
|
record[CloudKitWebFeed.Fields.containerExternalIDs] = Array(containerExternalIDSet)
|
||||||
|
self.save(record, completion: completion)
|
||||||
|
}
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findOrCreateAccount(completion: @escaping (Result<String, Error>) -> Void) {
|
func findOrCreateAccount(completion: @escaping (Result<String, Error>) -> Void) {
|
||||||
|
|
|
@ -62,8 +62,8 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeWebFeed(_ externalID: String) {
|
func removeWebFeed(_ externalID: String) {
|
||||||
if let webFeed = account?.existingWebFeed(withExternalID: externalID) {
|
if let webFeed = account?.existingWebFeed(withExternalID: externalID), let containers = account?.existingContainers(withWebFeed: webFeed) {
|
||||||
account?.removeWebFeed(webFeed)
|
containers.forEach { $0.removeWebFeed(webFeed) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ private extension CloudKitAcountZoneDelegate {
|
||||||
container.removeWebFeed(webFeed)
|
container.removeWebFeed(webFeed)
|
||||||
}
|
}
|
||||||
case .insert(_, let externalID, _):
|
case .insert(_, let externalID, _):
|
||||||
if let container = existingContainers.first(where: { $0.externalID == externalID }) {
|
if let container = account.existingContainer(withExternalID: externalID) {
|
||||||
container.addWebFeed(webFeed)
|
container.addWebFeed(webFeed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ extension CloudKitZone {
|
||||||
case .success:
|
case .success:
|
||||||
break
|
break
|
||||||
case .retry(let timeToWait):
|
case .retry(let timeToWait):
|
||||||
self.retryOperationIfPossible(retryAfter: timeToWait) {
|
self.retryIfPossible(after: timeToWait) {
|
||||||
self.subscribe()
|
self.subscribe()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -96,20 +96,6 @@ extension CloudKitZone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func save(_ record: CKRecord, completion: @escaping (Result<Void, Error>) -> Void) {
|
|
||||||
modify(recordsToSave: [record], recordIDsToDelete: [], completion: completion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func delete(externalID: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
|
||||||
guard let externalID = externalID else {
|
|
||||||
completion(.failure(CloudKitZoneError.invalidParameter))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let recordID = CKRecord.ID(recordName: externalID, zoneID: Self.zoneID)
|
|
||||||
modify(recordsToSave: [], recordIDsToDelete: [recordID], completion: completion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func query(_ query: CKQuery, completion: @escaping (Result<[CKRecord], Error>) -> Void) {
|
func query(_ query: CKQuery, completion: @escaping (Result<[CKRecord], Error>) -> Void) {
|
||||||
guard let database = database else {
|
guard let database = database else {
|
||||||
completion(.failure(CloudKitZoneError.unknown))
|
completion(.failure(CloudKitZoneError.unknown))
|
||||||
|
@ -125,7 +111,7 @@ extension CloudKitZone {
|
||||||
completion(.failure(CloudKitZoneError.unknown))
|
completion(.failure(CloudKitZoneError.unknown))
|
||||||
}
|
}
|
||||||
case .retry(let timeToWait):
|
case .retry(let timeToWait):
|
||||||
self.retryOperationIfPossible(retryAfter: timeToWait) {
|
self.retryIfPossible(after: timeToWait) {
|
||||||
self.query(query, completion: completion)
|
self.query(query, completion: completion)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -134,6 +120,50 @@ extension CloudKitZone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fetch(externalID: String?, completion: @escaping (Result<CKRecord, Error>) -> Void) {
|
||||||
|
guard let externalID = externalID else {
|
||||||
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let recordID = CKRecord.ID(recordName: externalID, zoneID: Self.zoneID)
|
||||||
|
|
||||||
|
database?.fetch(withRecordID: recordID) { record, error in
|
||||||
|
switch CloudKitZoneResult.resolve(error) {
|
||||||
|
case .success:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let record = record {
|
||||||
|
completion(.success(record))
|
||||||
|
} else {
|
||||||
|
completion(.failure(CloudKitZoneError.unknown))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .retry(let timeToWait):
|
||||||
|
self.retryIfPossible(after: timeToWait) {
|
||||||
|
self.fetch(externalID: externalID, completion: completion)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
completion(.failure(error!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func save(_ record: CKRecord, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
modify(recordsToSave: [record], recordIDsToDelete: [], completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete(externalID: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
guard let externalID = externalID else {
|
||||||
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let recordID = CKRecord.ID(recordName: externalID, zoneID: Self.zoneID)
|
||||||
|
modify(recordsToSave: [], recordIDsToDelete: [recordID], completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
func modify(recordsToSave: [CKRecord], recordIDsToDelete: [CKRecord.ID], completion: @escaping (Result<Void, Error>) -> Void) {
|
func modify(recordsToSave: [CKRecord], recordIDsToDelete: [CKRecord.ID], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
let op = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete)
|
let op = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete)
|
||||||
|
|
||||||
|
@ -173,7 +203,7 @@ extension CloudKitZone {
|
||||||
completion(.failure(CloudKitZoneError.userDeletedZone))
|
completion(.failure(CloudKitZoneError.userDeletedZone))
|
||||||
}
|
}
|
||||||
case .retry(let timeToWait):
|
case .retry(let timeToWait):
|
||||||
self.retryOperationIfPossible(retryAfter: timeToWait) {
|
self.retryIfPossible(after: timeToWait) {
|
||||||
self.modify(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete, completion: completion)
|
self.modify(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete, completion: completion)
|
||||||
}
|
}
|
||||||
case .limitExceeded:
|
case .limitExceeded:
|
||||||
|
@ -230,7 +260,7 @@ extension CloudKitZone {
|
||||||
self.changeToken = token
|
self.changeToken = token
|
||||||
}
|
}
|
||||||
case .retry(let timeToWait):
|
case .retry(let timeToWait):
|
||||||
self.retryOperationIfPossible(retryAfter: timeToWait) {
|
self.retryIfPossible(after: timeToWait) {
|
||||||
self.fetchChangesInZone(completion: completion)
|
self.fetchChangesInZone(completion: completion)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -299,8 +329,8 @@ private extension CloudKitZone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func retryOperationIfPossible(retryAfter: Double, block: @escaping () -> ()) {
|
func retryIfPossible(after: Double, block: @escaping () -> ()) {
|
||||||
let delayTime = DispatchTime.now() + retryAfter
|
let delayTime = DispatchTime.now() + after
|
||||||
DispatchQueue.main.asyncAfter(deadline: delayTime, execute: {
|
DispatchQueue.main.asyncAfter(deadline: delayTime, execute: {
|
||||||
block()
|
block()
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue