Skip to content

feat(schema): Implement Algebraic Schema Migration System#1221

Open
DakodaStemen wants to merge 3 commits intozio:mainfrom
DakodaStemen:schema-migration
Open

feat(schema): Implement Algebraic Schema Migration System#1221
DakodaStemen wants to merge 3 commits intozio:mainfrom
DakodaStemen:schema-migration

Conversation

@DakodaStemen
Copy link

@DakodaStemen DakodaStemen commented Mar 14, 2026

Closes #519
/claim #519

Summary

This PR implements a pure, algebraic schema migration system for ZIO Blocks. The architecture shifts
migration validation from runtime to compile time, ensuring mathematically sound shape equivalence
between schema versions.

Architecture

Pure data core. Migrations are modelled as a MigrationAction ADT — no closures, opaque functions,
or reflection. Every migration is fully serialisable.

Selector macro API. Custom macros for Scala 2.13 (scala-reflect) and Scala 3 (scala.quoted)
extract S => A selector lambdas into DynamicOptic paths at compile time. The developer-facing API is
identical across both versions:

MigrationBuilder[PersonV1, PersonV2]
  .renameField(_.name, _.fullName)
  .build

Two-layer design.

  • DynamicMigration — untyped, serialisable core operating on DynamicValue
  • Migration[A, B] — typed façade with Schema-driven encode/decode

Compile-Time Validation

The .build macro performs a symbolic dry-run of the builder AST against structural Refinement types,
proving shape equivalence at compile time. A missing or misaligned field is a compiler error, not a
runtime failure. Structural types (e.g. type PersonV0 = { def firstName: String }) are natively
supported for past schema versions without requiring concrete case classes.

Cross-version AST stability is maintained across Scala 3.3.x and 3.7.x — the SelectorMacro intercepts
both Ident and Select patterns arising from reflectiveSelectableFromLangReflectiveCalls desugaring.
End-to-end proof is in jvm/src/test/scala-3/.../StructuralTypeMigrationSpec.scala.

Algebraic Laws

MigrationLawsSpec verifies the following invariants via property-based testing:

  • Identityempty.apply(v) == Right(v) for any Record or Variant
  • Associativity(m1 ++ m2) ++ m3 and m1 ++ (m2 ++ m3) produce identical results
  • Reversibilitym.reverse.reverse.actions.length == m.actions.length; round-trips recover the
    original value for all invertible operations

44 tests pass across Scala 2.13, 3.3, and 3.7 on both JVM and JS targets.

zio-519-demo.mp4

@DakodaStemen DakodaStemen reopened this Mar 15, 2026
@DakodaStemen DakodaStemen changed the title Implement Algebraic Schema Migration System feat(schema): Implement Algebraic Schema Migration System Mar 16, 2026
@DakodaStemen DakodaStemen reopened this Mar 16, 2026
@DakodaStemen DakodaStemen reopened this Mar 18, 2026
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