OSDN Git Service

CoreDataIntormationの名前をCoreDataConfigurationに変更
[kcd/KCD.git] / KCD / CoreDataCore.swift
1 //
2 //  CoreDataManager.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/02/05.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 // MARK: enum
12 enum CoreDataManagerType {
13     case reader
14     case editor
15 }
16
17 // MARK: - struct
18 struct CoreDataConfiguration {
19     let modelName: String
20     let fileName: String
21     let options: [AnyHashable: Any]
22     let type: String
23     let tryRemake: Bool
24     
25     private static let defaultOptions: [AnyHashable: Any] = [
26         NSMigratePersistentStoresAutomaticallyOption: true,
27         NSInferMappingModelAutomaticallyOption: true
28     ]
29     
30     init(_ modelName: String,
31          fileName: String? = nil,
32          options: [AnyHashable: Any] = defaultOptions,
33          type: String = NSSQLiteStoreType,
34          tryRemake: Bool = false) {
35         self.modelName = modelName
36         self.fileName = fileName ?? "\(modelName).storedata"
37         self.options = options
38         self.type = type
39         self.tryRemake = tryRemake
40     }
41 }
42
43 struct CoreDataCore {
44     let config: CoreDataConfiguration
45     let model: NSManagedObjectModel
46     let coordinator: NSPersistentStoreCoordinator
47     let parentContext: NSManagedObjectContext
48     
49     init(_ config: CoreDataConfiguration) {
50         self.config = config
51         do {
52             (model, coordinator, parentContext) = try genarate(config)
53         } catch {
54             NSApplication.shared().presentError(error)
55             fatalError("CoreDataCore: can not initialize. \(error)")
56         }
57     }
58     
59     func editorContext() -> NSManagedObjectContext {
60         let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
61         moc.parent = parentContext
62         moc.undoManager = nil
63         return moc
64     }
65 }
66
67 // MARK: - protocol
68 protocol CoreDataProvider {
69     init(type: CoreDataManagerType)
70     var core: CoreDataCore { get }
71     var context: NSManagedObjectContext { get }
72     func save()
73 }
74
75 protocol CoreDataAccessor: CoreDataProvider {
76     func insertNewObject<T>(for entity: Entity<T>) -> T?
77     func delete(_ object: NSManagedObject)
78     func object(with objectId: NSManagedObjectID) -> NSManagedObject
79     func objects<T>(with entity: Entity<T>, sortDescriptors: [NSSortDescriptor]?, predicate: NSPredicate?) throws -> [T]
80 }
81
82 protocol CoreDataManager {
83     associatedtype InstanceType = Self
84     
85     static var `default`: InstanceType { get }
86     static func oneTimeEditor() -> InstanceType
87     
88     func removeDataFile()
89 }
90
91 // MARK: - Extension
92 extension CoreDataProvider {
93     func save() {
94         if !context.commitEditing() {
95             print("\(String(describing: type(of: self))) unable to commit editing before saveing")
96             return
97         }
98         do {
99             try context.save()
100         } catch { presentOnMainThread(error) }
101         if let p = context.parent {
102             p.performAndWait {
103                 do {
104                     try p.save()
105                 } catch {
106                     self.presentOnMainThread(error)
107                 }
108             }
109         }
110     }
111     private func presentOnMainThread(_ error: Error) {
112         if Thread.isMainThread {
113             NSApp.presentError(error)
114         } else {
115             DispatchQueue.main.sync {
116                 let _ = NSApp.presentError(error)
117             }
118         }
119     }
120 }
121
122 extension CoreDataAccessor {
123     func insertNewObject<T>(for entity: Entity<T>) -> T? {
124         return NSEntityDescription.insertNewObject(forEntityName: entity.name, into: context) as? T
125     }
126     func delete(_ object: NSManagedObject) {
127         context.delete(object)
128     }
129     func object(with objectId: NSManagedObjectID) -> NSManagedObject {
130         return context.object(with: objectId)
131     }
132     func objects<T>(with entity: Entity<T>,
133                     sortDescriptors: [NSSortDescriptor]? = nil,
134                     predicate: NSPredicate? = nil) throws -> [T] {
135         let req = NSFetchRequest<T>(entityName: entity.name)
136         req.sortDescriptors = sortDescriptors
137         req.predicate = predicate
138         return try context.fetch(req)
139     }
140 }
141
142 extension CoreDataManager where Self: CoreDataProvider {
143     func removeDataFile() {
144         remove(name: core.config.fileName)
145     }
146 }