LocalData/Documentation/Migration.md
Matt Bruce 70534f647b Update Migrations, Models, Protocols (+2 more) and tests, docs
Summary:
- Sources: update Migrations, Models, Protocols (+2 more)
- Tests: update tests for AnyStorageKeyTests.swift, MigrationAdditionalTests.swift, MigrationIntegrationTests.swift (+3 more)
- Docs: update docs for Migration, Migration_Refactor_Plan_Clean, Proposal (+1 more)

Stats:
- 31 files changed, 2820 insertions(+), 80 deletions(-)
2026-01-18 13:43:10 -06:00

65 lines
2.0 KiB
Markdown

# LocalData Migration Guide
## Overview
`LocalData` provides protocol-based migration support to move data from legacy storage locations to modern `StorageKey` definitions.
## Automatic Migration
When calling `get(_:)` on a key, the `StorageRouter` automatically:
1. Checks the primary location.
2. If not found, evaluates `migration` defined on the key.
3. If data is found in a source:
- Unsecures it using the source's old policy.
- Re-secures it using the destination key's policy.
- Stores it in the new location.
- Deletes the legacy data.
- Returns the value.
## Proactive Migration (Sweep)
You can trigger a sweep of all registered keys at app launch:
```swift
try await StorageRouter.shared.registerCatalog(MyCatalog(), migrateImmediately: true)
```
This iterates through all keys in the catalog and calls `forceMigration(for:)` on each, ensuring all legacy data is consolidated.
## Defining Migration Sources
### Simple Legacy Migration
For 1:1 migrations, attach a `SimpleLegacyMigration`:
```swift
struct MyNewKey: StorageKey {
// ...
var migration: AnyStorageMigration? {
AnyStorageMigration(
SimpleLegacyMigration(
destinationKey: self,
sourceKey: .key(LegacyKey(name: "old_key_name", domain: .userDefaults(suite: nil)))
)
)
}
}
```
### Protocol-Based Migration
For complex scenarios, attach an explicit migration:
```swift
struct MyMigration: StorageMigration {
typealias DestinationKey = MyNewKey
let destinationKey = MyNewKey()
func shouldMigrate(using router: StorageRouter, context: MigrationContext) async throws -> Bool {
try await router.exists(destinationKey)
}
func migrate(using router: StorageRouter, context: MigrationContext) async throws -> MigrationResult {
// Custom migration logic
MigrationResult(success: true)
}
}
extension MyNewKey {
var migration: AnyStorageMigration? {
AnyStorageMigration(MyMigration())
}
}
```