OSDN Git Service

関数名を変更
[kcd/KCD.git] / KCD / CoreDataManager.swift
1 //
2 //  CoreDataManager.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/10/26.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 enum CoreDataManagerType {
12     
13     case reader
14     case editor
15 }
16
17 enum CoreDataError: Error {
18     
19     case saveLocationIsUnuseable
20     case couldNotCreateModel
21     case couldNotCreateCoordinator(String)
22     case couldNotSave(String)
23 }
24
25 protocol CoreDataProvider {
26     
27     init(type: CoreDataManagerType)
28     
29     static var core: CoreDataCore { get }
30     
31     var context: NSManagedObjectContext { get }
32     
33     func save(errorHandler: (Error) -> Void)
34     func save() throws
35 }
36
37 protocol CoreDataAccessor: CoreDataProvider {
38     
39     func insertNewObject<T>(for entity: Entity<T>) -> T?
40     func delete(_ object: NSManagedObject)
41     func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T?
42     func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?) throws -> [T]
43     
44     func object(with objectId: NSManagedObjectID) -> NSManagedObject
45 }
46
47 protocol CoreDataManager: CoreDataAccessor {
48     
49     associatedtype InstanceType = Self
50     
51     static var `default`: InstanceType { get }
52     
53     static func oneTimeEditor() -> InstanceType
54 }
55
56 // MARK: - Extension
57 extension CoreDataProvider {
58     
59     static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
60         
61         switch type {
62         case .reader: return core.parentContext
63             
64         case .editor: return core.editorContext()
65         }
66     }
67     
68     func save(errorHandler: (Error) -> Void) {
69         
70         do {
71             
72             try save()
73             
74         } catch {
75             
76             errorHandler(error)
77         }
78     }
79     
80     func save() throws {
81         
82         guard context.commitEditing() else {
83             
84             throw CoreDataError.couldNotSave("\(String(describing: type(of: self))) unable to commit editing before saveing")
85         }
86         
87         do {
88             
89             try context.save()
90             
91         } catch (let error as NSError) {
92             
93             throw CoreDataError.couldNotSave(error.localizedDescription)
94         }
95         
96         guard let parent = context.parent else { return }
97         
98         // save parent context
99         var catchedError: NSError? = nil
100         parent.performAndWait {
101             
102             do {
103                 
104                 try parent.save()
105                 
106             } catch (let error as NSError) {
107                 
108                 catchedError = error
109             }
110         }
111         
112         if let error = catchedError {
113             
114             throw CoreDataError.couldNotSave(error.localizedDescription)
115             
116         }
117     }
118     
119     func presentOnMainThread(_ error: Error) {
120         
121         if Thread.isMainThread {
122             
123             NSApp.presentError(error)
124             
125         } else {
126             
127             DispatchQueue.main.sync {
128                 
129                 _ = NSApp.presentError(error)
130             }
131         }
132     }
133 }
134
135 extension CoreDataAccessor {
136     
137     func insertNewObject<T>(for entity: Entity<T>) -> T? {
138         
139         return NSEntityDescription.insertNewObject(forEntityName: entity.name, into: context) as? T
140     }
141     
142     func delete(_ object: NSManagedObject) {
143         
144         context.delete(object)
145     }
146     
147     func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T? {
148         
149         return context.object(with: objectId) as? T
150     }
151     
152     func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]? = nil, predicate: NSPredicate? = nil) throws -> [T] {
153         
154         let req = NSFetchRequest<T>(entityName: entity.name)
155         req.sortDescriptors = sortDescriptors
156         req.predicate = predicate
157         
158         return try context.fetch(req)
159     }
160     
161     func object(with objectId: NSManagedObjectID) -> NSManagedObject {
162         
163         return context.object(with: objectId)
164     }
165 }