-
Notifications
You must be signed in to change notification settings - Fork 121
[Core Data] Make new Core Data migration path. Remove models below 30 #15987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
5466c91
b23e5e9
8804c6c
d72dd96
1bd0ede
5f4e8fe
67ba1af
5439a99
65144c7
91088d0
41ffc50
d1d463b
66da437
dc6431f
6080964
08de9bf
f544d68
35a6fd2
644059f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -59,6 +59,17 @@ final class CoreDataIterativeMigrator { | |||||||||||||||||||||||||||
| // Find the current model used by the store. | ||||||||||||||||||||||||||||
| let sourceModel = try model(for: sourceMetadata) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // Check if we should nuke the DB entirely based on the oldest supported data model. | ||||||||||||||||||||||||||||
| // We will attempt to either move the merchant to the latest model version, or perform an iterative migration | ||||||||||||||||||||||||||||
| // The persistent store coordinator will automatically create a fresh store with the current model as needed. | ||||||||||||||||||||||||||||
| if shouldDestroyPersistentStore(for: sourceModel) { | ||||||||||||||||||||||||||||
| do { | ||||||||||||||||||||||||||||
| try destroyPersistentStore(sourceStoreURL: sourceStoreURL, storeType: storeType) | ||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||
| DDLogError("[CoreDataIterativeMigrator] Direct migration failed. Error: \(error). Falling back to iterative migration.") | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // Get the steps to perform the migration. | ||||||||||||||||||||||||||||
| let steps = try MigrationStep.steps(using: modelsInventory, source: sourceModel, target: targetModel) | ||||||||||||||||||||||||||||
| guard !steps.isEmpty else { | ||||||||||||||||||||||||||||
|
|
@@ -176,4 +187,37 @@ private extension CoreDataIterativeMigrator { | |||||||||||||||||||||||||||
| .appendingPathComponent("migration_\(UUID().uuidString)") | ||||||||||||||||||||||||||||
| .appendingPathExtension("sqlite") | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| func shouldDestroyPersistentStore(for sourceModel: NSManagedObjectModel) -> Bool { | ||||||||||||||||||||||||||||
| guard let sourceVersion = CoreDataMigratorUtils.findSourceVersion(for: sourceModel, in: modelsInventory) else { | ||||||||||||||||||||||||||||
| DDLogInfo("Could not determine source model version. Using iterative migration.") | ||||||||||||||||||||||||||||
| return false | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| // If the merchant is on a model version older than this, nuke the DB and migrate them to the latest one without iterative process | ||||||||||||||||||||||||||||
| let oldestModelThreshold = Constants.oldestSupportedDataModel | ||||||||||||||||||||||||||||
| let versionNumber = CoreDataMigratorUtils.extractVersionNumber(from: sourceVersion.name) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
| guard let sourceVersion = CoreDataMigratorUtils.findSourceVersion(for: sourceModel, in: modelsInventory) else { | |
| DDLogInfo("Could not determine source model version. Using iterative migration.") | |
| return false | |
| } | |
| // If the merchant is on a model version older than this, nuke the DB and migrate them to the latest one without iterative process | |
| let oldestModelThreshold = Constants.oldestSupportedDataModel | |
| let versionNumber = CoreDataMigratorUtils.extractVersionNumber(from: sourceVersion.name) | |
| guard let versionNumber = CoreDataMigratorUtils.findSourceVersionNumber(for: sourceModel, in: modelsInventory) else { | |
| DDLogInfo("Could not determine source model version. Using iterative migration.") | |
| return false | |
| } | |
| // If the merchant is on a model version older than this, nuke the DB and migrate them to the latest one without iterative process | |
| let oldestModelThreshold = Constants.oldestSupportedDataModel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I'd prefer to keep these separated, but with the simplification you suggested on 6080964 we can also remove extractVersionNumber entirely.
jaclync marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import CoreData | ||
|
|
||
| struct CoreDataMigratorUtils { | ||
| /// Finds the ModelVersion that corresponds to the given NSManagedObjectModel | ||
| static func findSourceVersion(for sourceModel: NSManagedObjectModel, | ||
| in modelsInventory: ManagedObjectModelsInventory) -> ManagedObjectModelsInventory.ModelVersion? { | ||
| do { | ||
| let allModels = try modelsInventory.models(for: modelsInventory.versions) | ||
| for (index, model) in allModels.enumerated() { | ||
| if model.isEqual(sourceModel) { | ||
| return modelsInventory.versions[index] | ||
| } | ||
| } | ||
|
Comment on lines
+8
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Trying to ensure that it can return a deleted version. When I printed out If it's not possible, I think the code can be simplified by not having to compare with the oldest model version constant, since the available models in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a very good catch, and excellent suggestion. We can just rely on the existence of the model rather than having to check the version, which simplifies the logic and allows us to remove some. Updated here: 6080964 |
||
| } catch { | ||
| DDLogError("[CoreDataMigratorUtils] Error loading models for version detection: \(error)") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| /// Extract version number from model version name | ||
| /// Examples: "Model" -> 0, "Model 10" -> 10, "Model 124" -> 124 | ||
| static func extractVersionNumber(from versionName: String) -> Int { | ||
| // Handle the base "Model" case (version 0) | ||
| if versionName == "Model" { | ||
| return 0 | ||
| } | ||
|
|
||
| // Extract number from "Model N" pattern | ||
| let components = versionName.components(separatedBy: " ") | ||
| if components.count == 2, let versionNumber = Int(components[1]) { | ||
| return versionNumber | ||
| } | ||
|
|
||
| // Fallback: couldn't parse version, assume it's very old (version 0) | ||
| DDLogWarn("[CoreDataMigratorUtils] Could not parse version number from '\(versionName)'. Assuming version 0.") | ||
| return 0 | ||
iamgabrielma marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.