use thisversion::traits::{IntoModel, IntoSchema};
use thisversion::{VersionBoundary, VersionFamily};
#[derive(VersionFamily)]
enum DocumentVersions {
V1(DocumentV1),
V2(DocumentV2),
}
struct DocumentV1 {
title: String,
content: ContentV2,
}
#[derive(VersionBoundary)]
#[thisversion(model = Document)]
struct DocumentV2 {
title: String,
#[thisversion(nested = ContentVersions)]
content: ContentV2,
}
impl From<DocumentV1> for DocumentV2 {
fn from(previous: DocumentV1) -> Self {
Self {
title: previous.title,
content: previous.content,
}
}
}
#[derive(VersionFamily)]
enum ContentVersions {
V1(ContentV1),
V2(ContentV2),
V3(ContentV3),
}
struct ContentV1 {
text: String,
}
struct ContentV2 {
paragraphs: Vec<String>,
}
#[derive(VersionBoundary)]
#[thisversion(model = Content)]
struct ContentV3 {
paragraphs: Vec<String>,
reviewed: bool,
}
impl From<ContentV1> for ContentV2 {
fn from(previous: ContentV1) -> Self {
Self {
paragraphs: vec![previous.text],
}
}
}
impl From<ContentV2> for ContentV3 {
fn from(previous: ContentV2) -> Self {
Self {
paragraphs: previous.paragraphs,
reviewed: false,
}
}
}
impl From<ContentV3> for ContentV2 {
fn from(latest: ContentV3) -> Self {
Self {
paragraphs: latest.paragraphs,
}
}
}
#[derive(Debug)]
struct Content {
paragraphs: Vec<String>,
reviewed: bool,
}
#[derive(Debug)]
struct Document {
title: String,
content: Content,
}
fn main() {
let stored = DocumentVersions::V1(DocumentV1 {
title: "Pinned document".to_owned(),
content: ContentV2 {
paragraphs: vec!["Stored as V2".to_owned()],
},
});
let mut model: Document = stored.into_model();
assert_eq!(model.content.paragraphs, ["Stored as V2"]);
assert!(!model.content.reviewed);
model.content.reviewed = true;
let persisted: DocumentVersions = model.into_schema();
assert!(matches!(
persisted,
DocumentVersions::V2(DocumentV2 {
content: ContentV2 { paragraphs },
..
}) if paragraphs == ["Stored as V2"]
));
}