Skip to content

Schema Migration for zio-blocks#959

Open
Nanashi-lab wants to merge 47 commits intozio:mainfrom
Nanashi-lab:migrationbounty
Open

Schema Migration for zio-blocks#959
Nanashi-lab wants to merge 47 commits intozio:mainfrom
Nanashi-lab:migrationbounty

Conversation

@Nanashi-lab
Copy link
Contributor

@Nanashi-lab Nanashi-lab commented Feb 2, 2026

/claim #519
/closes #519

Compile Time Validation

Both Scala 2 and Scala 3 have compile time validation. They extract the ShapeTree of SchemaA and SchemaB, and do a Tree.diff which returns added and removed, of the form List[List[Segement]]

Segement

private[migration] object Segment {
  case class Field(name: String) extends Segment
  case class Case(name: String)  extends Segment
  case object Element            extends Segment
  case object Key                extends Segment
  case object Value              extends Segment
  case object Wrapped            extends Segment
}

When .build is run, as we go through MigrationAction, each migration action collects Handled and Provided, which is also of the form List[List[Segement]] , which are then compared against added and removed. On success we compile.

Example of List[List[Segement]] : List((Field("address"), Field("city")), Field("age")) -> It has two path address.city and age.

Note - This is a different List of Lists, rather than encoding level and field. I though having a clear path to the field which was added or removed was a better decision.

Selector Syntax

Support for Selector Syntax for _.field, _.nested.field, _.case.when[Batman]. _.field.each. Also includes support for bare Literal SchemaExpr, so it is easier to write migration code.

Deviations

Joint and Split for nested fields.

_.address.street + _.address.city → _.address.fullAddress -> this is done

_.address.street + _.origin.country → _.address.fullAddress -> This gets complex since now we have to extract values from multiple nested source paths, combine to targeted nested path, remove the nested source fields, and rebuilt the whole structure immutability.

So if the parent is not the same, it gracefully errors out at both runtime (if .buildpartial was used) and during compile validation (if .build was used)

Serialization

Added Serialization - Using a new DynamicSchemaExpr a serializable version of SchemaExpr . Manually derived schema for all things which make up DynamicMigration

final case class SchemaExpr[A, B](
  dynamic: DynamicSchemaExpr,
  inputSchema: Schema[A],
  outputSchema: Schema[B]
)

Structural Support

Added Structural tests, to showcase the structural can be migrated properly. Deviation is they are not supported via compile time validation. During .build they fall through and are parsed as a PrimitiveNode. All the tests currently used .buildPartial. Maybe fixable by adding a check to see if they are refinement type and exploring their structure at compile time in both 2 and 3.

@Nanashi-lab Nanashi-lab marked this pull request as draft February 10, 2026 11:20
@Nanashi-lab
Copy link
Contributor Author

Nanashi-lab commented Feb 10, 2026

Rebased, Updated the PR Message, Thank you for your review.

@Nanashi-lab Nanashi-lab marked this pull request as ready for review February 10, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Schema Migration System for ZIO Schema 2

1 participant