// // PersistentContainer.swift // Reader // // Created by Shadowfacts on 12/24/21. // import CoreData import Fervor class PersistentContainer: NSPersistentContainer { private static let managedObjectModel: NSManagedObjectModel = { let url = Bundle.main.url(forResource: "Reader", withExtension: "momd")! return NSManagedObjectModel(contentsOf: url)! }() private(set) lazy var backgroundContext: NSManagedObjectContext = { let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) // todo: should the background context really be parented to the view context, or should they both be direct children of the PSC? context.parent = self.viewContext return context }() init(account: LocalData.Account) { super.init(name: "\(account.id)", managedObjectModel: PersistentContainer.managedObjectModel) loadPersistentStores { description, error in if let error = error { fatalError("Unable to load persistent store: \(error)") } } } func sync(serverGroups: [Fervor.Group], serverFeeds: [Fervor.Feed]) async throws { try await backgroundContext.perform { let existingGroups = try self.backgroundContext.fetch(Group.fetchRequest()) for group in serverGroups { if let existing = existingGroups.first(where: { $0.id == group.id }) { existing.updateFromServer(group) } else { let mo = Group(context: self.backgroundContext) mo.updateFromServer(group) } } for removed in existingGroups where !serverGroups.contains(where: { $0.id == removed.id }) { self.backgroundContext.delete(removed) } let existingFeeds = try self.backgroundContext.fetch(Feed.fetchRequest()) for feed in serverFeeds { if let existing = existingFeeds.first(where: { $0.id == feed.id }) { existing.updateFromServer(feed) } else { let mo = Feed(context: self.backgroundContext) mo.updateFromServer(feed) } } if self.backgroundContext.hasChanges { try self.backgroundContext.save() try self.viewContext.save() } } } }