|
| 1 | +// UnmanagedReadOnlyModel.swift |
| 2 | +// CoreDataRepository |
| 3 | +// |
| 4 | +// |
| 5 | +// MIT License |
| 6 | +// |
| 7 | +// Copyright © 2024 Andrew Roan |
| 8 | + |
| 9 | +import CoreData |
| 10 | +import Foundation |
| 11 | + |
| 12 | +/// Protocol for a value type for reading and fetchiing a ``NSManagedObject`` subclass |
| 13 | +/// |
| 14 | +/// There are times where a single ``NSManagedObject``subclass may be accessed via multiple value types. |
| 15 | +/// ``UnmanagedReadOnlyModel`` provides a minimal interface for reading and fetching values from CoreData |
| 16 | +/// without needing to implement the full ``UnmanagedModel`` protocol. |
| 17 | +/// |
| 18 | +/// For example, for `ManagedMovie`, there are two unmanaged models, `Movie` and `MoviePlaceholder`. |
| 19 | +/// `MoviePlaceholder` will never create, update, or delete a corresponding instance of `ManagedMovie`. It is read only. |
| 20 | +/// `Movie` supports all operations against a corresponding instacnce of `ManagedMovie`. |
| 21 | +/// |
| 22 | +/// ```swift |
| 23 | +/// @objc(ManagedMovie) |
| 24 | +/// final class ManagedMovie: NSManagedObject { |
| 25 | +/// @NSManaged var id: UUID? |
| 26 | +/// @NSManaged var title: String? |
| 27 | +/// } |
| 28 | +/// |
| 29 | +/// struct Movie: Hashable, UnmanagedModel { |
| 30 | +/// let id: UUID |
| 31 | +/// var title: String = "" |
| 32 | +/// var url: URL? |
| 33 | +/// |
| 34 | +/// init(managed: ManagedMovie) throws { |
| 35 | +/// self.init( |
| 36 | +/// id: managed.id!, |
| 37 | +/// title: managed.title!, |
| 38 | +/// url: managed.objectID.uriRepresentation() |
| 39 | +/// ) |
| 40 | +/// } |
| 41 | +/// |
| 42 | +/// var managedIdUrl: URL? { |
| 43 | +/// get { |
| 44 | +/// url |
| 45 | +/// } |
| 46 | +/// set(newValue) { |
| 47 | +/// url = newValue |
| 48 | +/// } |
| 49 | +/// } |
| 50 | +/// |
| 51 | +/// func asManagedModel(in context: NSManagedObjectContext) throws -> ManagedMovie { |
| 52 | +/// let object = ManagedMovie(context: context) |
| 53 | +/// object.id = id |
| 54 | +/// object.title = title |
| 55 | +/// return object |
| 56 | +/// } |
| 57 | +/// |
| 58 | +/// func updating(managed: ManagedMovie) throws { |
| 59 | +/// managed.id = id |
| 60 | +/// managed.title = title |
| 61 | +/// } |
| 62 | +/// } |
| 63 | +/// |
| 64 | +/// struct MoviePlaceholder: UnmanagedReadOnlyModel { |
| 65 | +/// let id: UUID |
| 66 | +/// |
| 67 | +/// init(managed: ManagedMovie) throws { |
| 68 | +/// self.init(id: managed.id!) |
| 69 | +/// } |
| 70 | +/// } |
| 71 | +/// ``` |
| 72 | +public protocol UnmanagedReadOnlyModel: Equatable { |
| 73 | + /// The ``NSManagedObject`` subclass `Self` corresponds to |
| 74 | + associatedtype ManagedModel: NSManagedObject |
| 75 | + |
| 76 | + /// Initialize of new instance of `Self` from an instance of ``ManagedModel`` |
| 77 | + init(managed: ManagedModel) throws |
| 78 | + |
| 79 | + /// ``NSFetchRequest`` for ``ManagedModel`` with a strongly typed ``NSFetchRequest.ResultType`` |
| 80 | + static func managedFetchRequest() -> NSFetchRequest<ManagedModel> |
| 81 | +} |
| 82 | + |
| 83 | +extension UnmanagedReadOnlyModel { |
| 84 | + public static func managedFetchRequest() -> NSFetchRequest<ManagedModel> { |
| 85 | + NSFetchRequest<ManagedModel>( |
| 86 | + entityName: ManagedModel.entity().name ?? ManagedModel.entity() |
| 87 | + .managedObjectClassName |
| 88 | + ) |
| 89 | + } |
| 90 | +} |
0 commit comments