Persisted data often outlives the code that wrote it. As an application evolves, its stored fields and their meanings change too. I built thisversion to keep that history in versioned schema types, while letting application code use one current model.
The idea for this library came from my place of work, where managing backwards compatibility became increasingly burdensome as our types accumulated changes over the years. I cleaned up and documented the approach so it could be useful to other Rust projects too.
With thisversion, you define a type for each schema version and write conversions between versions. Derives connect the schema history to your current application type, so Rust checks the connection when the model changes.
use thisversion::{VersionBoundary, VersionFamily}; use thisversion::traits::{IntoModel, IntoSchema}; #[derive(VersionFamily)] enum SettingsVersions { V1(SettingsV1), V2(SettingsV2), V3(SettingsV3), } // Historical schemas each have their own shape. struct SettingsV1 { /* older schema */ } struct SettingsV2 { /* newer fields */ } #[derive(VersionBoundary)] #[thisversion(model = Settings)] struct SettingsV3 { /* current persisted schema */ } // Migrations connect each historical schema to the next. impl From<SettingsV1> for SettingsV2 { /* ... */ } impl From<SettingsV2> for SettingsV3 { /* ... */ } #[derive(VersionBoundary)] #[thisversion(model = Settings)] struct SettingsV3 { /* current persisted schema */ } // Application code uses a completely isolated type. struct Settings { /* current application model */ } // Decode any stored version, then migrate it into the current model. let versions: SettingsVersions = decode_from_somewhere(...); let settings: Settings = versions.into_model(); // Convert back to the latest schema for persistence. let schema: SettingsVersions = settings.into_schema(); The crate is no_std by default. Optional Serde adapters are available, but the migration layer does not require Serde or prescribe a storage system or wire format.
Links: crates.io · documentation · repository and examples
I'd love to get this to 1.0, but need some adoption and feedback before I feel comfortable committing to a 1.0 release.
The name is an homage thiserror and this is my first ever publication to crates.io!
1 post - 1 participant