Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for state migrations in
infer
(#215)
Adds support for state migrations in the `infer` provider. Resources opt into state migrations when they implement the `infer.CustomStateMigrations[O]` interface: ```go type CustomStateMigrations[O any] interface { // StateMigrations is the list of know migrations. // // Each migration should return a valid State object. // // The first migration to return a non-nil Result will be used. StateMigrations(ctx p.Context) []StateMigrationFunc[O] } // StateMigrationFunc represents a stateless mapping from an old state shape to a new // state shape. Each StateMigrationFunc is parameterized by the shape of the type it // produces, ensuring that all successful migrations end up in a valid state. // // To create a StateMigrationFunc, use [StateMigration]. type StateMigrationFunc[New any] interface {} // Sealed // StateMigration creates a mapping from an old state shape (type Old) to a new state // shape (type New). // // If Old = [resource.PropertyMap], then the migration is always run. // // Example: // // type MyResource struct{} // // type MyInput struct{} // // type MyStateV1 struct { // SomeInt *int `pulumi:"someInt,optional"` // } // // type MyStateV2 struct { // AString string `pulumi:"aString"` // AInt *int `pulumi:"aInt,optional"` // } // // func migrateFromV1(ctx p.Context, v1 StateV1) (infer.MigrationResult[MigrateStateV2], error) { // return infer.MigrationResult[MigrateStateV2]{ // Result: &MigrateStateV2{ // AString: "default-string", // Add a new required field // AInt: v1.SomeInt, // Rename an existing field // }, // }, nil // } // // // Associate your migration with the resource it encapsulates. // func (*MyResource) StateMigrations(p.Context) []infer.StateMigrationFunc[MigrateStateV2] { // return []infer.StateMigrationFunc[MigrateStateV2]{ // infer.StateMigration(migrateFromV1), // } // } func StateMigration[Old, New any, F func(p.Context, Old) (MigrationResult[New], error)](f F) StateMigrationFunc[New] { ... } // MigrationResult represents the result of a migration. type MigrationResult[T any] struct { // Result is the result of the migration. // // If Result is nil, then the migration is considered to have been unnecessary. // // If Result is non-nil, then the migration is considered to have completed and // the new value state value will be *Result. Result *T } ``` This allows each resource to define a list of (possibly typed) migrations from old to new state. This design makes the common case of migrating from StateV1 to StateV2 fully typed, but permits an untyped to typed escape hatch. Fixes #193
- Loading branch information