OSDN Git Service

static method to instance method
[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     func removeDataFile()
36 }
37
38 protocol CoreDataAccessor: CoreDataProvider {
39     
40     func insertNewObject<T>(for entity: Entity<T>) -> T?
41     func delete(_ object: NSManagedObject)
42     func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T?
43     func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?) throws -> [T]
44     
45     func object(with objectId: NSManagedObjectID) -> NSManagedObject
46 }
47
48 protocol CoreDataManager: CoreDataAccessor {
49     
50     associatedtype InstanceType = Self
51     
52     static var `default`: InstanceType { get }
53     
54     static func oneTimeEditor() -> InstanceType
55 }
56
57 // MARK: - Extension
58 extension CoreDataProvider {
59     
60     static func context(for type: CoreDataManagerType) -> NSManagedObjectContext {
61         
62         switch type {
63         case .reader: return core.parentContext
64             
65         case .editor: return core.editorContext()
66         }
67     }
68     
69     func save(errorHandler: (Error) -> Void) {
70         
71         do {
72             
73             try save()
74             
75         } catch {
76             
77             errorHandler(error)
78         }
79     }
80     
81     func save() throws {
82         
83         guard context.commitEditing() else {
84             
85             throw CoreDataError.couldNotSave("\(String(describing: type(of: self))) unable to commit editing before saveing")
86         }
87         
88         do {
89             
90             try context.save()
91             
92         } catch (let error as NSError) {
93             
94             throw CoreDataError.couldNotSave(error.localizedDescription)
95         }
96         
97         guard let parent = context.parent else { return }
98         
99         // save parent context
100         var catchedError: NSError? = nil
101         parent.performAndWait {
102             
103             do {
104                 
105                 try parent.save()
106                 
107             } catch (let error as NSError) {
108                 
109                 catchedError = error
110             }
111         }
112         
113         if let error = catchedError {
114             
115             throw CoreDataError.couldNotSave(error.localizedDescription)
116             
117         }
118     }
119     
120     func removeDataFile() {
121         
122         MOCGenerator(type(of: self).core.config).removeDataFile()
123     }
124     
125     func presentOnMainThread(_ error: Error) {
126         
127         if Thread.isMainThread {
128             
129             NSApp.presentError(error)
130             
131         } else {
132             
133             DispatchQueue.main.sync {
134                 
135                 _ = NSApp.presentError(error)
136             }
137         }
138     }
139 }
140
141 extension CoreDataAccessor {
142     
143     func insertNewObject<T>(for entity: Entity<T>) -> T? {
144         
145         return NSEntityDescription.insertNewObject(forEntityName: entity.name, into: context) as? T
146     }
147     
148     func delete(_ object: NSManagedObject) {
149         
150         context.delete(object)
151     }
152     
153     func object<T>(of entity: Entity<T>, with objectId: NSManagedObjectID) -> T? {
154         
155         return context.object(with: objectId) as? T
156     }
157     
158     func objects<T>(of entity: Entity<T>, sortDescriptors: [NSSortDescriptor]? = nil, predicate: NSPredicate? = nil) throws -> [T] {
159         
160         let req = NSFetchRequest<T>(entityName: entity.name)
161         req.sortDescriptors = sortDescriptors
162         req.predicate = predicate
163         
164         return try context.fetch(req)
165     }
166     
167     func object(with objectId: NSManagedObjectID) -> NSManagedObject {
168         
169         return context.object(with: objectId)
170     }
171 }