1.8 KiB
1.8 KiB
Migrations
LocalData supports lazy and proactive migrations to move data from legacy keys to modern keys.
Lazy migrations (on read)
Attach a migration to a key. If the destination is missing, StorageRouter.get(_:) will run it.
extension StorageKey where Value == String {
static let legacyToken = StorageKey(
name: "legacy_token",
domain: .userDefaults(suite: nil),
security: .none,
owner: "Auth",
description: "Legacy token."
)
static let userToken = StorageKey(
name: "user_token",
domain: .keychain(service: "com.myapp"),
owner: "Auth",
description: "Modern token.",
migration: { destination in
AnyStorageMigration(
SimpleLegacyMigration(
destinationKey: destination,
sourceKey: .key(StorageKey.legacyToken)
)
)
}
)
}
Proactive sweeps
Run migrations at startup to drain legacy values:
try await StorageRouter.shared.registerCatalog(AuthCatalog(), migrateImmediately: true)
Transforming migrations
Use DefaultTransformingMigration when types change.
let migration = DefaultTransformingMigration(
destinationKey: StorageKey.userAge,
sourceKey: StorageKey.legacyAgeString
) { value in
guard let intValue = Int(value) else {
throw MigrationError.transformationFailed("Invalid age")
}
return intValue
}
Aggregating migrations
Combine multiple legacy values into one destination:
let migration = DefaultAggregatingMigration(
destinationKey: StorageKey.profileSummary,
sourceKeys: [.key(StorageKey.firstName), .key(StorageKey.lastName)]
) { sources in
let parts = sources.compactMap { $0.value as? String }
return parts.joined(separator: " ")
}