Skip to content

Instantly share code, notes, and snippets.

@rpapallas
Last active March 7, 2018 23:11
Show Gist options
  • Save rpapallas/3b71a291801430b8140d0a98532ef7dc to your computer and use it in GitHub Desktop.
Save rpapallas/3b71a291801430b8140d0a98532ef7dc to your computer and use it in GitHub Desktop.
DatabaseManager class for CoreData
// This work is licensed under a Creative Commons
// Attribution-ShareAlike 4.0 International License.
// © 2016 Rafael Papallas and www.computingstories.com
import Foundation
import CoreData
class DatabaseManager {
/// Implements the Singleton Design Pattern
static let instance = DatabaseManager()
// MARK: - Database Level Properties
/// Managed Context for Core Data
func managedObjectContext() -> NSManagedObjectContext {
return persistentContainer.viewContext
}
/// Persistent Container because we don't have initialised this project with
/// Core Data.
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Model")
print(container.persistentStoreDescriptions)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error), \(error._userInfo)")
}
})
return container
}()
// MARK: - API Level Properties
/// Returns all the available contexts in the database if any (nil if there
/// are no contexts or something went wrong with the database).
var allContexts: [Context]? {
return getAllEntries(for: "Context") as? [Context]
}
/// Returns all the available tasks in the database if any (nil if there
/// are no tasks or something went wrong with the database).
var allTasks: [Task]? {
return getAllEntries(for: "Task") as? [Task]
}
/// Returns an empty Context object to be populated with data using standard
/// syntax and then to be saved to the database:
///
/// ```
/// let emptyContext = DatabaseManager.instance.getEmptyContextInstance
/// emptyContext.name = "Some name"
/// DatabaseManager.instance.saveOrUpdateInstance(emptyContext)
/// ```
var getEmptyContextInstance: Context {
return getEntityDescriptionNewObject(withEntityName: "Context") as! Context
}
/// Returns an empty Task object to be populated with data using standard
/// syntax and then to be saved to the database:
///
/// ```
/// let emptyTask = DatabaseManager.instance.getEmptyContextInstance
/// emptyTask.title = "Some title"
/// DatabaseManager.instance.saveOrUpdateInstance(emptyTask)
/// ```
var getEmptyTaskInstance: Task {
return getEntityDescriptionNewObject(withEntityName: "Task") as! Task
}
// MARK: - General purpose functions exposed to the programmer
/// Saves or Updates the given instance to the database.
///
/// If you retrieved a class instance from this class and you edit it's
/// attributes and then used this function, then this method will perform
/// update.
///
/// If you however, requested an empty class instance from this class and you
/// added data to it's attributes, then this method will perform insertion.
///
/// - Attributes:
/// - instance: The instance to be added/updated.
///
/// - Returns: True if the operation was successful, false otherwise.
func saveOrUpdate(instance: NSManagedObject) -> Bool {
do {
try instance.managedObjectContext?.save()
return true
} catch {
fatalError("Failed: \(error)")
}
return false
}
/// Returns all the tasks that their estimated time is less than the given
/// estimated time.
///
/// - Parameters:
/// - withEstimatedTimeLessThan: The estimated time to be filtered with
///
/// - Returns: A list of tasks which meet the predicate.
func filteredTasks(withEstimatedTimeLessThan estimatedTime: Int) -> [Task]? {
let tasksFetch: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Task")
tasksFetch.predicate = NSPredicate(format: "estimatedTime <= %@", "\(estimatedTime)")
do {
let fetchedTasks = try managedObjectContext().fetch(tasksFetch)
return fetchedTasks as? [Task]
}
catch {
fatalError("Failed to fetch tasks: \(error)")
}
return nil
}
/// Returns a list of tasks for the given context (if any).
///
/// - Parameters:
/// - context: Context to filter the tasks from.
///
/// - Returns: A list of tasks that have the given location assigned to it.
func tasksBy(context: Context) -> [Task]? {
let tasksFetch: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Task")
tasksFetch.predicate = NSPredicate(format: "hasContext == %@", context)
do {
let fetchedTasks = try managedObjectContext().fetch(tasksFetch)
return fetchedTasks as? [Task]
}
catch {
fatalError("Failed to fetch tasks: \(error)")
}
return nil
}
/// Deletes the given instance from the database.
///
///
/// An instance provided as an argument is going to be deleted
/// and then the rest of the instances would be saved
///
/// - Attributes:
/// - instance: The instance to be deleted.
///
/// - Returns: True if the operation was successful, false otherwise.
func delete(instance: NSManagedObject) -> Bool {
self.managedObjectContext().delete(instance)
do{
try self.managedObjectContext().save()
return true
}
catch{
fatalError("Failed to save the tasks: \(error)")
}
return false
}
// MARK: - Private methods for the purpose of this class.
/// This will return a new `insertNewObject` instance of type NSManagedObject
/// that can be casted down into Context, Location or Task and then to be
/// used to create a new record to the database.
private func getEntityDescriptionNewObject(withEntityName name: String) -> NSManagedObject {
return NSEntityDescription.insertNewObject(forEntityName: name, into: managedObjectContext())
}
/// Function used to retrieve all the available records of the given Entity.
/// This code is applicable to allContexts, allTasks and allLocations therefore
/// wrapped into a single method for reuse.
///
/// - Parameters:
/// - for: The name of the Entity to query.
///
/// - Returns: Results (Any) or nil if nothing found or something went wrong
private func getAllEntries(for name: String) -> Any? {
let fetch: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: name)
do {
return try managedObjectContext().fetch(fetch)
}
catch {
fatalError("Failed to fetch tasks: \(error)")
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment