From 3fbf803518b6e49129689e809e21fb67ea562fc5 Mon Sep 17 00:00:00 2001 From: Davide Date: Wed, 2 Oct 2024 13:35:49 +0200 Subject: [PATCH] Ignore unmappable Core Data entities (#660) But implement .discard for testing. --- .../AppDataProfiles/CDProfileRepository.swift | 4 +-- .../Business/CoreDataRepository.swift | 29 ++++++++++++++----- Passepartout/Shared/Shared+AppLibrary.swift | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Passepartout/Library/Sources/AppDataProfiles/CDProfileRepository.swift b/Passepartout/Library/Sources/AppDataProfiles/CDProfileRepository.swift index b23dbe86..0598c9db 100644 --- a/Passepartout/Library/Sources/AppDataProfiles/CDProfileRepository.swift +++ b/Passepartout/Library/Sources/AppDataProfiles/CDProfileRepository.swift @@ -35,7 +35,7 @@ extension AppData { registry: Registry, coder: ProfileCoder, context: NSManagedObjectContext, - onResultError: ((Error) -> Bool)? + onResultError: ((Error) -> CoreDataResultAction)? ) -> any ProfileRepository { let repository = CoreDataRepository(context: context) { $0.sortDescriptors = [ @@ -57,7 +57,7 @@ extension AppData { cdProfile.lastUpdate = Date() return cdProfile } onResultError: { - onResultError?($0) ?? true + onResultError?($0) ?? .ignore } return repository diff --git a/Passepartout/Library/Sources/UtilsLibrary/Business/CoreDataRepository.swift b/Passepartout/Library/Sources/UtilsLibrary/Business/CoreDataRepository.swift index d902005e..881fb3bd 100644 --- a/Passepartout/Library/Sources/UtilsLibrary/Business/CoreDataRepository.swift +++ b/Passepartout/Library/Sources/UtilsLibrary/Business/CoreDataRepository.swift @@ -31,10 +31,19 @@ public protocol CoreDataUniqueEntity: NSManagedObject, UniqueEntity { // Core Data entity must have a unique "uuid" field } +public enum CoreDataResultAction { + case ignore + + case discard + + case halt +} + public actor CoreDataRepository: NSObject, Repository, NSFetchedResultsControllerDelegate where CD: CoreDataUniqueEntity, T: UniqueEntity { + private let entityName: String private let context: NSManagedObjectContext @@ -43,7 +52,7 @@ public actor CoreDataRepository: NSObject, private let toMapper: (T, NSManagedObjectContext) throws -> CD - private let onResultError: ((Error) -> Bool)? // true = keep going + private let onResultError: ((Error) -> CoreDataResultAction)? private let entitiesSubject: CurrentValueSubject, Never> @@ -55,7 +64,7 @@ public actor CoreDataRepository: NSObject, beforeFetch: ((NSFetchRequest) -> Void)? = nil, fromMapper: @escaping (CD) throws -> T?, toMapper: @escaping (T, NSManagedObjectContext) throws -> CD, - onResultError: ((Error) -> Bool)? = nil + onResultError: ((Error) -> CoreDataResultAction)? = nil ) { guard let entityName = CD.entity().name else { fatalError("Unable to find entity name for \(CD.self)") @@ -193,16 +202,22 @@ private extension CoreDataRepository { do { return try self?.fromMapper($0) } catch { - if let onResultError = self?.onResultError { + switch self?.onResultError?(error) { + case .discard: + self?.context.delete($0) - // on false, discard results - guard onResultError(error) else { - throw ResultError.mapping(error) - } + case .halt: + throw ResultError.mapping(error) + + default: + break } return nil } } + + try self?.context.save() + let result = EntitiesResult(entities, isFiltering: controller.fetchRequest.predicate != nil) self?.entitiesSubject.send(result) } catch { diff --git a/Passepartout/Shared/Shared+AppLibrary.swift b/Passepartout/Shared/Shared+AppLibrary.swift index a58bf0ba..f148a5bc 100644 --- a/Passepartout/Shared/Shared+AppLibrary.swift +++ b/Passepartout/Shared/Shared+AppLibrary.swift @@ -50,7 +50,7 @@ extension ProfileManager { context: store.context ) { error in pp_log(.app, .error, "Unable to decode result: \(error)") - return true + return .ignore } return ProfileManager(repository: repository)