use thisversion::traits::{IntoModel, IntoSchema};
use thisversion::{VersionBoundary, VersionFamily};
#[derive(VersionFamily)]
pub enum DocumentVersions {
V1(DocumentV1),
V2(DocumentV2),
V3(DocumentV3),
}
pub struct DocumentV1 {
pub title: String,
pub body: String,
}
pub struct DocumentV2 {
pub title: String,
pub content: ContentVersions,
}
impl From<DocumentV1> for DocumentV2 {
fn from(previous: DocumentV1) -> Self {
Self {
title: previous.title,
content: ContentVersions::V1(ContentV1 {
text: previous.body,
}),
}
}
}
#[derive(VersionBoundary)]
#[thisversion(model = Document)]
pub struct DocumentV3 {
pub title: String,
#[thisversion(nested)]
pub content: ContentVersions,
pub archived: bool,
}
impl From<DocumentV2> for DocumentV3 {
fn from(previous: DocumentV2) -> Self {
Self {
title: previous.title,
content: previous.content,
archived: false,
}
}
}
#[derive(VersionFamily)]
pub enum ContentVersions {
V1(ContentV1),
V2(ContentV2),
}
pub struct ContentV1 {
pub text: String,
}
#[derive(VersionBoundary)]
#[thisversion(model = Content)]
pub struct ContentV2 {
pub paragraphs: Vec<String>,
}
impl From<ContentV1> for ContentV2 {
fn from(previous: ContentV1) -> Self {
Self {
paragraphs: vec![previous.text],
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Document {
pub title: String,
pub content: Content,
pub archived: bool,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Content {
pub paragraphs: Vec<String>,
}
fn main() {
let old = DocumentVersions::V1(DocumentV1 {
title: "First document".to_owned(),
body: "Written before structured content.".to_owned(),
});
assert_eq!(
old.into_model(),
Document {
title: "First document".to_owned(),
content: Content {
paragraphs: vec!["Written before structured content.".to_owned()]
},
archived: false,
}
);
let current = DocumentVersions::V3(DocumentV3 {
title: "Archived document".to_owned(),
content: ContentVersions::V1(ContentV1 {
text: "Still plain text.".to_owned(),
}),
archived: true,
});
let model = current.into_model();
assert_eq!(
model,
Document {
title: "Archived document".to_owned(),
content: Content {
paragraphs: vec!["Still plain text.".to_owned()]
},
archived: true,
}
);
let persisted: DocumentVersions = model.into_schema();
assert!(matches!(
persisted,
DocumentVersions::V3(DocumentV3 {
content: ContentVersions::V2(_),
..
})
));
}