Skip to content

Instantly share code, notes, and snippets.

@Lavmint
Last active November 17, 2018 15:50
Show Gist options
  • Save Lavmint/b4d33ce328f48cee6eb89cbb5afde133 to your computer and use it in GitHub Desktop.
Save Lavmint/b4d33ce328f48cee6eb89cbb5afde133 to your computer and use it in GitHub Desktop.
Nice CoreData usage
import CoreData
enum db {
static let todoist: DAO = {
let container = NSPersistentContainer(name: "Todoist")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
guard let err = error else { return }
fatalError(err.localizedDescription)
})
return DAO(container: container)
}()
}
extension ProjectMO: ManagedObject {
public static func primaryKey() -> String {
return #keyPath(ProjectMO.id)
}
}
public class DAO {
private let container: NSPersistentContainer
public init(container: NSPersistentContainer) {
self.container = container
}
public func transaction(_ block: ((_ w: Transaction) throws -> Void)) throws {
try block(Transaction(ctx: container.viewContext))
}
public func backgroundTransaction(_ block: @escaping ((_ w: Transaction) throws -> Void)) throws {
container.performBackgroundTask { (ctx) in
do {
try block(Transaction(ctx: ctx))
} catch {
print(error)
}
}
}
}
public class Transaction {
fileprivate let ctx: NSManagedObjectContext
internal init(ctx: NSManagedObjectContext) {
self.ctx = ctx
}
public func objects<T: NSManagedObject>(_ type: T.Type) -> RequestBuilder<T, T> {
return RequestBuilder<T, T>(ctx: ctx)
}
public func dictionaries<T: NSManagedObject>(_ type: T.Type) -> RequestBuilder<T, NSDictionary> {
return RequestBuilder<T, NSDictionary>(ctx: ctx)
}
}
//MARK: - Write
public extension Transaction {
public func write(_ block: ((_ w: WriteTransaction) throws -> Void)) throws {
try block(WriteTransaction(ctx: ctx))
if ctx.hasChanges {
do {
try ctx.save()
} catch {
ctx.rollback()
throw error
}
}
}
}
public class WriteTransaction: Transaction {
@discardableResult
public func create<T: NSManagedObject & ManagedObject>(_ type: T.Type, id: T.PrimaryKey) throws -> T {
var obj = try objects(T.self).find(id: id) ?? T(context: ctx)
obj.id = id
return obj
}
public func update<T: NSManagedObject & ManagedObject>(_ type: T.Type, id: T.PrimaryKey, kyedValues: [String: Any], createIfNotExists: Bool = false) throws {
if createIfNotExists {
let obj = try create(type, id: id)
obj.setValuesForKeys(kyedValues)
} else {
guard let obj = try objects(T.self).find(id: id) else { return }
obj.setValuesForKeys(kyedValues)
}
}
}
public class RequestBuilder<Object: NSManagedObject & ManagedObject, Result: NSFetchRequestResult> {
public private(set) var request: NSFetchRequest<Result>
private let ctx: NSManagedObjectContext
internal init(ctx: NSManagedObjectContext) {
self.ctx = ctx
request = NSFetchRequest<Result>()
request.entity = Object.entity()
if Result.self == NSDictionary.self {
request.resultType = .dictionaryResultType
}
}
public func find(id: Object.PrimaryKey) throws -> Result? {
let p = id is NSNumber ? "%d" : "%@"
_ = filter(predicate: NSPredicate(format: "\(Object.primaryKey()) == \(p)", id))
request.fetchLimit = 1
return try ctx.fetch(request).first
}
public func filter(predicate: NSPredicate) -> Self {
request.predicate = predicate
return self
}
public func filter(_ query: String) -> Self {
return filter(predicate: NSPredicate(format: query))
}
public func sort(by descriptors: [NSSortDescriptor]) -> Self {
request.sortDescriptors? = descriptors
return self
}
public func sort(by descriptor: NSSortDescriptor) -> Self {
return sort(by: [descriptor])
}
public func frc(sectionNameKeyPath: String? = nil, cacheName: String? = nil) -> NSFetchedResultsController<Result> {
return NSFetchedResultsController(fetchRequest: request, managedObjectContext: ctx, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName)
}
}
public extension RequestBuilder where Result: NSDictionary {
public func fetch<T: Decodable>(_ decodable: T.Type) throws -> [T] {
let dicts = try ctx.fetch(request)
let data = try JSONSerialization.data(withJSONObject: dicts)
let decoder = JSONDecoder()
return try decoder.decode([T].self, from: data)
}
}
public extension RequestBuilder where Result: NSManagedObject {
public func fetch() throws -> [Result] {
return try ctx.fetch(request)
}
}
public protocol ManagedObject {
associatedtype PrimaryKey: CVarArg
static func primaryKey() -> String
var id: PrimaryKey { get set }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment