From fcd34140e3a26cbab6a76c3172a2b1c91fddc845 Mon Sep 17 00:00:00 2001 From: Chris McGraw <2454408+wargcm@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:48:22 -0500 Subject: [PATCH 1/3] Add options to migrate the imported WordPress database automatically --- WordPress/Classes/Utility/CoreDataHelper.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/Utility/CoreDataHelper.swift b/WordPress/Classes/Utility/CoreDataHelper.swift index 9413094aa517..bf7ec0b5aafa 100644 --- a/WordPress/Classes/Utility/CoreDataHelper.swift +++ b/WordPress/Classes/Utility/CoreDataHelper.swift @@ -255,9 +255,12 @@ extension CoreDataStack { let databaseReplaced = replaceDatabase(from: databaseLocation, to: currentDatabaseLocation) do { + let options = [NSMigratePersistentStoresAutomaticallyOption: true, + NSInferMappingModelAutomaticallyOption: true] try storeCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, - at: currentDatabaseLocation) + at: currentDatabaseLocation, + options: options) if databaseReplaced { // The database was replaced successfully and the store added with no errors so we From c811a1e717d644f7855cdbecc970d79d8b20d5d3 Mon Sep 17 00:00:00 2001 From: Chris McGraw <2454408+wargcm@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:54:08 -0500 Subject: [PATCH 2/3] Fix migration logic in `migrateDataModelsIfNecessary` Ref: https://github.com/wordpress-mobile/WordPress-iOS/blob/24db036f22c493ef847c9e6f4fc14d9f9fbd1144/WordPress/Classes/Utility/ContextManager.m#L219 --- WordPress/Classes/Utility/ContextManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/Utility/ContextManager.swift b/WordPress/Classes/Utility/ContextManager.swift index dd6c899e8d68..d1aa17eeded9 100644 --- a/WordPress/Classes/Utility/ContextManager.swift +++ b/WordPress/Classes/Utility/ContextManager.swift @@ -243,7 +243,7 @@ private extension ContextManager { } guard let metadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL), - objectModel.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + !objectModel.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) else { return } From 6c833d6fdb4da59508f0b8ce295fd44f76ebb7b7 Mon Sep 17 00:00:00 2001 From: Chris McGraw <2454408+wargcm@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:02:43 -0500 Subject: [PATCH 3/3] Attempt to manually migrate the imported database before using it --- .../Classes/Utility/ContextManager.swift | 69 ++++++++++--------- .../Classes/Utility/CoreDataHelper.swift | 10 +++ 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/WordPress/Classes/Utility/ContextManager.swift b/WordPress/Classes/Utility/ContextManager.swift index d1aa17eeded9..4ade7fbf0555 100644 --- a/WordPress/Classes/Utility/ContextManager.swift +++ b/WordPress/Classes/Utility/ContextManager.swift @@ -135,6 +135,41 @@ public class ContextManager: NSObject, CoreDataStack, CoreDataStackSwift { save(context, .asynchronously) } } + + static func migrateDataModelsIfNecessary(storeURL: URL, objectModel: NSManagedObjectModel) throws { + guard FileManager.default.fileExists(atPath: storeURL.path) else { + DDLogInfo("No store exists at \(storeURL). Skipping migration.") + return + } + + guard let metadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL), + !objectModel.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + else { + return + } + + DDLogWarn("Migration required for persistent store.") + + guard let modelFileURL = Bundle.main.url(forResource: "WordPress", withExtension: "momd") else { + fatalError("Can't find WordPress.momd") + } + + guard let versionInfo = NSDictionary(contentsOf: modelFileURL.appendingPathComponent("VersionInfo.plist")) else { + fatalError("Can't get the object model's version info") + } + + guard let modelNames = (versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject])?.keys else { + fatalError("Can't parse the model versions") + } + + let sortedModelNames = modelNames.sorted { $0.compare($1, options: .numeric) == .orderedAscending } + try CoreDataIterativeMigrator.iterativeMigrate( + sourceStore: storeURL, + storeType: NSSQLiteStoreType, + to: objectModel, + using: sortedModelNames + ) + } } // MARK: - Private methods @@ -236,40 +271,6 @@ private extension ContextManager { return persistentContainer } - static func migrateDataModelsIfNecessary(storeURL: URL, objectModel: NSManagedObjectModel) throws { - guard FileManager.default.fileExists(atPath: storeURL.path) else { - DDLogInfo("No store exists at \(storeURL). Skipping migration.") - return - } - - guard let metadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore(ofType: NSSQLiteStoreType, at: storeURL), - !objectModel.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) - else { - return - } - - DDLogWarn("Migration required for persistent store.") - - guard let modelFileURL = Bundle.main.url(forResource: "WordPress", withExtension: "momd") else { - fatalError("Can't find WordPress.momd") - } - - guard let versionInfo = NSDictionary(contentsOf: modelFileURL.appendingPathComponent("VersionInfo.plist")) else { - fatalError("Can't get the object model's version info") - } - - guard let modelNames = (versionInfo["NSManagedObjectModel_VersionHashes"] as? [String: AnyObject])?.keys else { - fatalError("Can't parse the model versions") - } - - let sortedModelNames = modelNames.sorted { $0.compare($1, options: .numeric) == .orderedAscending } - try CoreDataIterativeMigrator.iterativeMigrate( - sourceStore: storeURL, - storeType: NSSQLiteStoreType, - to: objectModel, - using: sortedModelNames - ) - } } extension ContextManager { diff --git a/WordPress/Classes/Utility/CoreDataHelper.swift b/WordPress/Classes/Utility/CoreDataHelper.swift index bf7ec0b5aafa..00b6bbe948ea 100644 --- a/WordPress/Classes/Utility/CoreDataHelper.swift +++ b/WordPress/Classes/Utility/CoreDataHelper.swift @@ -250,6 +250,8 @@ extension CoreDataStack { throw ContextManager.ContextManagerError.missingDatabase } + try? migrateDatabaseIfNecessary(at: databaseLocation) + mainContext.reset() try storeCoordinator.remove(store) let databaseReplaced = replaceDatabase(from: databaseLocation, to: currentDatabaseLocation) @@ -330,4 +332,12 @@ extension CoreDataStack { _ = try? FileManager.default.replaceItemAt(locationShm, withItemAt: shmBackup) _ = try? FileManager.default.replaceItemAt(locationWal, withItemAt: walBackup) } + + private func migrateDatabaseIfNecessary(at databaseLocation: URL) throws { + guard let modelFileURL = Bundle.main.url(forResource: "WordPress", withExtension: "momd"), + let objectModel = NSManagedObjectModel(contentsOf: modelFileURL) else { + return + } + try ContextManager.migrateDataModelsIfNecessary(storeURL: databaseLocation, objectModel: objectModel) + } }