Skip to content

Instantly share code, notes, and snippets.

@ainame
Created November 7, 2019 01:23
Show Gist options
  • Select an option

  • Save ainame/10b953bca71da39904309039bade2545 to your computer and use it in GitHub Desktop.

Select an option

Save ainame/10b953bca71da39904309039bade2545 to your computer and use it in GitHub Desktop.

Revisions

  1. ainame created this gist Nov 7, 2019.
    65 changes: 65 additions & 0 deletions Mappable.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,65 @@
    import Foundation
    import CoreData

    protocol NSManagedObjectMappable: NSManagedObject where MapFrom.MapFrom == Self {
    associatedtype MapFrom: MappableFromNSManagedObject
    static func mappedObject(from object: MapFrom, in context: NSManagedObjectContext) -> Self
    }

    enum MappingError: Error {
    case missingNonOptionalValue(String)
    }

    protocol MappableFromNSManagedObject where MapFrom.MapFrom == Self {
    associatedtype MapFrom: NSManagedObjectMappable
    static func mappedObject(from object: MapFrom) throws -> Self
    }

    extension MappableFromNSManagedObject {
    static func mapValue<T>(from object: MapFrom, keyPath: KeyPath<MapFrom, T?>) throws -> T {
    guard let value = object[keyPath: keyPath] else {
    throw MappingError.missingNonOptionalValue(String(describing: keyPath))
    }
    return value
    }
    }

    struct Sample {
    let string: String
    let number: Int
    let date: Date
    }

    extension Sample: MappableFromNSManagedObject {
    static func mappedObject(from object: SampleRecord) throws -> Sample {
    return Sample(
    string: try mapValue(from: object, keyPath: \.string),
    number: Int(object.number),
    date: try mapValue(from: object, keyPath: \.date)
    )
    }
    }

    extension SampleRecord: NSManagedObjectMappable {
    static func mappedObject(from object: Sample, in context: NSManagedObjectContext) -> Self {
    let entity = Self.init(context: context)
    entity.string = object.string
    entity.number = Int32(object.number)
    entity.date = object.date
    return entity
    }
    }

    class StoreService {
    private let coreDataStack: CoreDataStack

    init(from coreDataStack: CoreDataStack) {
    self.coreDataStack = coreDataStack
    }

    func insert<T: MappableFromNSManagedObject>(_ object: T) throws {
    let context = coreDataStack.newBackgroundContext
    let entity = T.MapFrom.mappedObject(from: object, in: context)
    try context.save()
    }
    }