Ignore unmappable Core Data entities (#660)
But implement .discard for testing.
This commit is contained in:
parent
f602655568
commit
3fbf803518
|
@ -35,7 +35,7 @@ extension AppData {
|
||||||
registry: Registry,
|
registry: Registry,
|
||||||
coder: ProfileCoder,
|
coder: ProfileCoder,
|
||||||
context: NSManagedObjectContext,
|
context: NSManagedObjectContext,
|
||||||
onResultError: ((Error) -> Bool)?
|
onResultError: ((Error) -> CoreDataResultAction)?
|
||||||
) -> any ProfileRepository {
|
) -> any ProfileRepository {
|
||||||
let repository = CoreDataRepository<CDProfile, Profile>(context: context) {
|
let repository = CoreDataRepository<CDProfile, Profile>(context: context) {
|
||||||
$0.sortDescriptors = [
|
$0.sortDescriptors = [
|
||||||
|
@ -57,7 +57,7 @@ extension AppData {
|
||||||
cdProfile.lastUpdate = Date()
|
cdProfile.lastUpdate = Date()
|
||||||
return cdProfile
|
return cdProfile
|
||||||
} onResultError: {
|
} onResultError: {
|
||||||
onResultError?($0) ?? true
|
onResultError?($0) ?? .ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return repository
|
return repository
|
||||||
|
|
|
@ -31,10 +31,19 @@ public protocol CoreDataUniqueEntity: NSManagedObject, UniqueEntity {
|
||||||
// Core Data entity must have a unique "uuid" field
|
// Core Data entity must have a unique "uuid" field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CoreDataResultAction {
|
||||||
|
case ignore
|
||||||
|
|
||||||
|
case discard
|
||||||
|
|
||||||
|
case halt
|
||||||
|
}
|
||||||
|
|
||||||
public actor CoreDataRepository<CD, T>: NSObject,
|
public actor CoreDataRepository<CD, T>: NSObject,
|
||||||
Repository,
|
Repository,
|
||||||
NSFetchedResultsControllerDelegate where CD: CoreDataUniqueEntity,
|
NSFetchedResultsControllerDelegate where CD: CoreDataUniqueEntity,
|
||||||
T: UniqueEntity {
|
T: UniqueEntity {
|
||||||
|
|
||||||
private let entityName: String
|
private let entityName: String
|
||||||
|
|
||||||
private let context: NSManagedObjectContext
|
private let context: NSManagedObjectContext
|
||||||
|
@ -43,7 +52,7 @@ public actor CoreDataRepository<CD, T>: NSObject,
|
||||||
|
|
||||||
private let toMapper: (T, NSManagedObjectContext) throws -> CD
|
private let toMapper: (T, NSManagedObjectContext) throws -> CD
|
||||||
|
|
||||||
private let onResultError: ((Error) -> Bool)? // true = keep going
|
private let onResultError: ((Error) -> CoreDataResultAction)?
|
||||||
|
|
||||||
private let entitiesSubject: CurrentValueSubject<EntitiesResult<T>, Never>
|
private let entitiesSubject: CurrentValueSubject<EntitiesResult<T>, Never>
|
||||||
|
|
||||||
|
@ -55,7 +64,7 @@ public actor CoreDataRepository<CD, T>: NSObject,
|
||||||
beforeFetch: ((NSFetchRequest<CD>) -> Void)? = nil,
|
beforeFetch: ((NSFetchRequest<CD>) -> Void)? = nil,
|
||||||
fromMapper: @escaping (CD) throws -> T?,
|
fromMapper: @escaping (CD) throws -> T?,
|
||||||
toMapper: @escaping (T, NSManagedObjectContext) throws -> CD,
|
toMapper: @escaping (T, NSManagedObjectContext) throws -> CD,
|
||||||
onResultError: ((Error) -> Bool)? = nil
|
onResultError: ((Error) -> CoreDataResultAction)? = nil
|
||||||
) {
|
) {
|
||||||
guard let entityName = CD.entity().name else {
|
guard let entityName = CD.entity().name else {
|
||||||
fatalError("Unable to find entity name for \(CD.self)")
|
fatalError("Unable to find entity name for \(CD.self)")
|
||||||
|
@ -193,16 +202,22 @@ private extension CoreDataRepository {
|
||||||
do {
|
do {
|
||||||
return try self?.fromMapper($0)
|
return try self?.fromMapper($0)
|
||||||
} catch {
|
} catch {
|
||||||
if let onResultError = self?.onResultError {
|
switch self?.onResultError?(error) {
|
||||||
|
case .discard:
|
||||||
|
self?.context.delete($0)
|
||||||
|
|
||||||
// on false, discard results
|
case .halt:
|
||||||
guard onResultError(error) else {
|
|
||||||
throw ResultError.mapping(error)
|
throw ResultError.mapping(error)
|
||||||
}
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try self?.context.save()
|
||||||
|
|
||||||
let result = EntitiesResult(entities, isFiltering: controller.fetchRequest.predicate != nil)
|
let result = EntitiesResult(entities, isFiltering: controller.fetchRequest.predicate != nil)
|
||||||
self?.entitiesSubject.send(result)
|
self?.entitiesSubject.send(result)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -50,7 +50,7 @@ extension ProfileManager {
|
||||||
context: store.context
|
context: store.context
|
||||||
) { error in
|
) { error in
|
||||||
pp_log(.app, .error, "Unable to decode result: \(error)")
|
pp_log(.app, .error, "Unable to decode result: \(error)")
|
||||||
return true
|
return .ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProfileManager(repository: repository)
|
return ProfileManager(repository: repository)
|
||||||
|
|
Loading…
Reference in New Issue