Skip to content

Commit 708636a

Browse files
committed
Added testing functions for Store Model Version
1 parent 526fd32 commit 708636a

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

Sources/RCDataKit/Basic Protocols/ModelVersion.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,55 @@ extension ModelVersion {
154154
result.label = label
155155
return result
156156
}
157+
158+
/// Tests an existing Persistent Store for which model version it uses.
159+
///
160+
/// Use this function on a Persistent Store file that isn't necessarily currently being used, in order to determine
161+
/// which version of your `ModelVersion` the store is configured for. This can be used for debugging
162+
/// staged migrations.
163+
///
164+
/// - Parameters:
165+
/// - type: The type of store at the given location.
166+
/// - storeUrl: The location of the store.
167+
/// - configuration: Optionally, the configuration of the data model to use.
168+
///
169+
/// - Returns: An array of versions that are compatible with the store (there should only be zero or
170+
/// one versions in the resulting array).
171+
public static func versionsForStore(
172+
type: NSPersistentStore.StoreType,
173+
at storeUrl: URL,
174+
configuration: String? = nil
175+
) -> [Self] {
176+
// using https://williamboles.com/progressive-core-data-migration/
177+
// to find which version of the model is currently used for the store
178+
guard let storeMetadata = try? NSPersistentStoreCoordinator
179+
.metadataForPersistentStore(type: type, at: storeUrl)
180+
else {
181+
return []
182+
}
183+
184+
let bundle = ModelFile.bundle
185+
let modelName = ModelFile.modelName
186+
let res = allCases.filter { version in
187+
if let testModel = NSManagedObjectModel.named(modelName, in: bundle, versionName: version.versionName) {
188+
if testModel.isConfiguration(withName: configuration, compatibleWithStoreMetadata: storeMetadata) {
189+
return true
190+
}
191+
}
192+
return false
193+
}
194+
return res
195+
}
196+
197+
/// Tests a `NSPersistentStoreCoordinator` to determine which version of the model it is using.
198+
///
199+
/// - Parameter coordinator: The persistent store coordinator to test.
200+
///
201+
/// - Returns: An array of versions that are compatible with the store (there should only be zero or
202+
/// one versions in the resulting array).
203+
public static func versionsForStore(coordinator: NSPersistentStoreCoordinator) -> [Self] {
204+
allCases.filter { version in
205+
coordinator.managedObjectModel == version.modelVersion
206+
}
207+
}
157208
}

Tests/RCDataKitTests/XCTests/System Tests/StagedMigrationTest.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,42 @@ final class StagedMigrationTest: XCTestCase {
1616
try await super.tearDown()
1717
}
1818

19+
func testStackModelChecks() throws {
20+
let oldName = "oldSchoolStore"
21+
let oldStack = try TestingStacks.oldModelStack(uniqueName: oldName)
22+
23+
let oldStackUrl = try XCTUnwrap(oldStack.container.persistentStoreDescriptions.first?.url)
24+
let oldStackVersions = ModelVersions.versionsForStore(type: .sqlite, at: oldStackUrl)
25+
XCTAssertEqual(oldStackVersions, [.v1])
26+
27+
let oldStackVersions2 = ModelVersions.versionsForStore(coordinator: oldStack.container.persistentStoreCoordinator)
28+
XCTAssertEqual(oldStackVersions2, [.v1])
29+
30+
let oldStackModel = oldStack.container.managedObjectModel
31+
XCTAssertEqual(oldStackModel.versionChecksum, ModelVersions.v1.versionChecksum)
32+
33+
let oldCoordinatorModel = oldStack.container.persistentStoreCoordinator.managedObjectModel
34+
XCTAssertEqual(oldCoordinatorModel, ModelVersions.v1.modelVersion)
35+
XCTAssertNotEqual(oldCoordinatorModel, ModelVersions.v3.modelVersion)
36+
37+
let newName = "newStore"
38+
let newStack = try TestingStacks.temporaryStack(uniqueName: newName)
39+
40+
let newStackUrl = try XCTUnwrap(newStack.container.persistentStoreDescriptions.first?.url)
41+
let newStackVersions = ModelVersions.versionsForStore(type: .sqlite, at: newStackUrl)
42+
XCTAssertEqual(newStackVersions, [.v4])
43+
44+
let newStackVersions2 = ModelVersions.versionsForStore(coordinator: newStack.container.persistentStoreCoordinator)
45+
XCTAssertEqual(newStackVersions2, [.v4])
46+
47+
let newStackModel = newStack.container.managedObjectModel
48+
XCTAssertEqual(newStackModel.versionChecksum, ModelVersions.v4.versionChecksum)
49+
50+
let newCoordinatorModel = newStack.container.persistentStoreCoordinator.managedObjectModel
51+
XCTAssertEqual(newCoordinatorModel, ModelVersions.v4.modelVersion)
52+
XCTAssertNotEqual(newCoordinatorModel, ModelVersions.v2.modelVersion)
53+
}
54+
1955
func testStackUsingOldModel() throws {
2056
let name = "oldSchoolStore"
2157
let stack = try TestingStacks.oldModelStack(uniqueName: name)

0 commit comments

Comments
 (0)