         })
     }
 
+    /**
+     Export data.
+     - returns: `Data` object containing `NSKeyedArchiver` archived data from
+     the array: `[db.sqlite, db.sqlite-wal, db.sqlite-shm]`, where each item is
+     the raw `Data` from each of those files.
+     */
+    func exportData() -> Data {
+        let sqlitePath = FileManager.url(forApplicationSupportFile: String(format: "%@.sqlite", Bundle.getAppName()))
+        let sqliteWALPath = FileManager.url(forApplicationSupportFile: String(format: "%@.sqlite-wal", Bundle.getAppName()))
+        let sqliteSHMPath = FileManager.url(forApplicationSupportFile: String(format: "%@.sqlite-shm", Bundle.getAppName()))
+
+        var fileData = [String: NSData]()
+        [ sqlitePath, sqliteWALPath, sqliteSHMPath ].forEach {
+            guard let data = NSData(contentsOf: $0) else {
+                logger?.logWarning(message: String(format: "[%@] No data read from %@.", instanceType(self), String(describing: $0)))
+                return
+            }
+
+            fileData[$0.lastPathComponent] = data
+        }
+
+        return NSKeyedArchiver.archivedData(withRootObject: fileData)
+    }
+
+}
+
+// MARK: Persistence
+public extension CoreDataController {
+
+    /**
+     Save any outstanding changes to a context, logging any changes and errors.
+     - parameter context: the context to save changes in.
+     */
+    func save(context: NSManagedObjectContext) {
+        logger?.logDebug(message: String(format: "[%@] About to save changes to context <%@>.", instanceType(self), context))
+        logger?.logVerbose(message: String(format: "[%@] Changes:\ninserted: %@\ndeleted: %@\nupdated: %@, .", instanceType(self), context.insertedObjects, context.deletedObjects, context.updatedObjects))
+        if !context.hasChanges {
+            logger?.logDebug(message: String(format: "[%@] No unsaved changes in context <%@>.", instanceType(self), context))
+            return
+        }
+
+        do {
+            try context.save()
+        } catch {
+            let message = String(format: "[%@] Could not save context <%@>.", instanceType(self), context)
+            logger?.logError(message: message, error: error)
+        }
+    }
+
+}
+
+// MARK: Deletion
+public extension CoreDataController {
+
+    /**
+     Delete an entity from a context and save the change.
+     - parameters:
+     - object: the object to delete
+     - context: the context from which to remove the object
+     */
+    func delete(object: NSManagedObject, context: NSManagedObjectContext) {
+        logger?.logDebug(message: String(format: "[%@] About to delete object <%@> from context <%@>.", instanceType(self), String(describing: object), context))
+        context.delete(object)
+        save(context: context)
+    }
+    
+}
+
+private extension CoreDataController {
+
     func archivedData(sqlitePath: String, sqliteWALPath: String, sqliteSHMPath: String) -> Data {
         var fileData = [String: NSData]()
         [ sqlitePath, sqliteWALPath, sqliteSHMPath ].forEach {

     Import data from archived data on disk into Core Data.
     - parameters:
         - sqlitePath: path to the database on disk
         - completion: the confirming completion block
     */
    func importFromSQLitePath(sqlitePath: String, completion: ConfirmCompletionBlock? = nil ) {
        let shmPath = sqlitePath.appending("-shm")

    }

    /**
     Import data in memory to Core Data.
     - parameters:
         - data: the `Data` instance to unarchive
         - completion: the confirming completion block, allowing the consumer
             app to acquire permission to restart
     */
    func importData(data: Data, completion: ConfirmCompletionBlock? = nil) {
        guard let fileData = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: NSData] else {
            logger?.logWarning(message: String(format: "[%@] Could not unarchive data to recover encoded databases.", instanceType(self)))
