this implementation uses a hierarchical structure in MigrationStep.Record:
final case class Record(
fieldActions: Vector[FieldAction], // Bottom level: add/remove/update at THIS depth
nestedFields: Map[String, MigrationStep] // Top level: how deep (recursion)
)
Sample for migrating nested structures:
// Source: Person(name, address: Address(street, city, zip))
// Target: Person(name, address: Address(street, city, postalCode), age)
Record(
fieldActions = Vector(Add("age", default)), // depth 0: Person level
nestedFields = Map(
"address" -> Record(
fieldActions = Vector(Rename("zip", "postalCode")), // depth 1: Address level
nestedFields = Map.empty
)
)
)
String-based API (Scala 2 & 3):
MigrationBuilder.from[PersonV1].to[PersonV2]
.renameField("name", "fullName")
.addField("email", DynamicValue.Primitive("unknown", StandardType.StringType))
.build
Selector-based API (Scala 3):
MigrationBuilder.from[PersonV1].to[PersonV2]
.rename(_.name, _.fullName)
.add(_.email, DynamicValue.Primitive("unknown", StandardType.StringType))
.buildValidated
Nested paths:
MigrationBuilder.from[OrderV1].to[OrderV2]
.addField("customer.loyaltyPoints", default)
.renameField("customer.address.zip", "customer.address.postalCode")
.build
Closes #519 /claim #519
Helmy LuqmanulHakim
@elskow
ZIO
@ZIO