/claim #519
Adds a pure, serializable migration system for ZIO Schema 2, built on top of the existing DynamicValue and DynamicOptic infrastructure. The design follows the same architectural pattern as the existing Patch/DynamicPatch system — typed wrapper over an untyped core, path-based actions, sequential composition.
MigrationAction — sealed ADT with 12 action types:
AddField, DropField, RenameField, TransformValue, Mandate, Optionalize, ChangeFieldTypeRenameCase, TransformCaseTransformElements, TransformKeys, TransformValuesEvery action carries a DynamicOptic path and implements reverse for structural inversion.
DynamicMigration — the untyped core. A Vector[MigrationAction] applied sequentially to a DynamicValue. Fully serializable (no closures, no reflection). Supports ++ composition and reverse.
Migration[A, B] — typed wrapper with sourceSchema and targetSchema. Converts A → DynamicValue → apply actions → DynamicValue → B. Supports ++/andThen composition and reverse.
MigrationBuilder[A, B] — fluent builder with convenience methods for all operations. DynamicOptic-based overloads for the underlying implementation, plus typed convenience methods (e.g. addField("age", 0), changeFieldType("total", "Long", "Int")).
MigrationError — error type with DynamicOptic path info for diagnostics.
Migration.identity[A].apply(a) == Right(a)(m1 ++ m2) ++ m3 produces the same result as m1 ++ (m2 ++ m3)m.reverse.reverse == mm.apply(a) == Right(b) => m.reverse.apply(b) == Right(a) when sufficient info exists42 tests covering:
PersonV1 → PersonV2, composition chains A → B → C)Cross-compiled and tested on Scala 3.7.4 (JVM).
https://github.com/user-attachments/assets/placeholder
case class PersonV1(firstName: String, lastName: String)
case class PersonV2(firstName: String, lastName: String, age: Int)
val migration = Migration.newBuilder[PersonV1, PersonV2]
.addField("age", 0)
.build
migration(PersonV1("John", "Doe"))
// Right(PersonV2("John", "Doe", 0))
migration.reverse(PersonV2("John", "Doe", 42))
// Right(PersonV1("John", "Doe"))
This is the foundation. Future work to complete the full spec includes:
_.name, _.address.street) for the builder methodsSchema.structural[T] for refinement/structural typesSchemaExpr integration for richer transformsJoin/Split actions.build validation (checking source fields are fully accounted for)legendary658
@legendary658
marianaguzmanguerrero16-dev
@marianaguzmanguerrero16-dev
ZIO
@ZIO