Created
June 20, 2016 20:05
-
-
Save kean/28439b29532993b620497621a4545789 to your computer and use it in GitHub Desktop.
Core Data Progressive Migration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The MIT License (MIT) | |
// | |
// Copyright (c) 2016 Alexander Grebenyuk (github.com/kean). | |
import Foundation | |
import CoreData | |
enum MigrationError: ErrorProtocol { | |
case IncompatibleModels | |
} | |
// moms: [mom_v1, mom_v2, ... , mom_vN] | |
func migrateStore(at storeURL: URL, moms: [NSManagedObjectModel]) throws { | |
let idx = try indexOfCompatibleMom(at: storeURL, moms: moms) | |
let remaining = moms.suffix(from: (idx + 1)) | |
guard remaining.count > 0 else { | |
return // migration not necessary | |
} | |
_ = try remaining.reduce(moms[idx]) { smom, dmom in | |
try migrateStore(at: storeURL, from: smom, to: dmom) | |
return dmom | |
} | |
} | |
func indexOfCompatibleMom(at storeURL: URL, moms: [NSManagedObjectModel]) throws -> Int { | |
let meta = try NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL) | |
guard let idx = moms.index(where: { $0.isConfiguration(withName: nil, compatibleWithStoreMetadata: meta) }) else { | |
throw MigrationError.IncompatibleModels | |
} | |
return idx | |
} | |
func migrateStore(at storeURL: URL, from smom: NSManagedObjectModel, to dmom: NSManagedObjectModel) throws { | |
// Prepare temp directory | |
let dir = try URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) | |
try FileManager.default().createDirectory(at: dir, withIntermediateDirectories: true, attributes: nil) | |
defer { | |
_ = try? FileManager.default().removeItem(at: dir) | |
} | |
// Perform migration | |
let mapping = try findMapping(from: smom, to: dmom) | |
let destURL = try dir.appendingPathComponent(storeURL.lastPathComponent!) | |
let manager = NSMigrationManager(sourceModel: smom, destinationModel: dmom) | |
try autoreleasepool { | |
try manager.migrateStore( | |
from: storeURL, | |
sourceType: NSSQLiteStoreType, | |
options: nil, | |
with: mapping, | |
toDestinationURL: destURL, | |
destinationType: NSSQLiteStoreType, | |
destinationOptions: nil | |
) | |
} | |
// Replace source store | |
let psc = NSPersistentStoreCoordinator(managedObjectModel: dmom) | |
try psc.replacePersistentStore( | |
at: storeURL, | |
destinationOptions: nil, | |
withPersistentStoreFrom: destURL, | |
sourceOptions: nil, | |
ofType: NSSQLiteStoreType | |
) | |
} | |
func findMapping(from smom: NSManagedObjectModel, to dmom: NSManagedObjectModel) throws -> NSMappingModel { | |
if let mapping = NSMappingModel(from: Bundle.allBundles(), forSourceModel: smom, destinationModel: dmom) { | |
return mapping // found custom mapping | |
} | |
return try NSMappingModel.inferredMappingModel(forSourceModel: smom, destinationModel: dmom) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment