Closes #519
/claim #519
Greeting @jdegoes,
Here’s my implementation of the purely algebraic Schema Migration System. I focused on building a reliable, serializable, and reversible system for handling structural schema transformations.
Overview of the Approach
- Core Data Layer (Untyped & Serializable)
- I introduced MigrationError to provide clear error messages with proper path tracing.
- Implemented MigrationAction, which covers all 14 required path based transformations (using DynamicOptic). Each action also supports a structural reverse operation.
- Built DynamicMigration as the core engine that ties everything together. It follows important properties like identity, associativity, and reversibility.
- Typed API for Users
- Created Migration[A, B] to safely handle transformations from one type to another (A → DynamicValue → B) using schemas.
- Added a MigrationBuilder to collect and apply actions. For now, it works directly with DynamicOptic.
Design Decisions
As mentioned in the issue, I’ve intentionally deferred macro-based selectors (like _.address.street).
Supporting macros that work properly across both Scala 2.13 and Scala 3 is quite complex and deserves its own focused effort. Instead, I prioritized building a solid and fully serializable foundation first (DynamicMigration + DynamicOptic).
This ensures we have a strong core system in place, and it will be easier to add macro based syntax on top later.
Testing & Validation
- Added around 70 test cases across:
- MigrationActionSpec
- DynamicMigrationSpec
- MigrationSpec
- Verified key properties like identity, associativity, and reversibility
- Confirmed that the code works on both Scala 2.13 and Scala 3.7+