//! Frozen schema4 review envelopes. Other model records are unchanged in schema5. use crate::language::ParseLimits; use crate::persistence::{DecodeResult, FileError, MigrationReport, SemanticDefault}; use crate::*; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct TraceBaseline4 { pub oa: TracedProperties, pub sa: TracedProperties, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Trace4 { pub id: Id, pub alias: String, pub name: String, pub description: String, pub oa: Id, pub sa: Id, pub kind: TraceKind, pub baseline: Option, } impl From for Trace { fn from(old: Trace4) -> Self { Self { id: old.id, alias: old.alias, name: old.name, description: old.description, oa: old.oa, sa: old.sa, kind: old.kind, baseline: old.baseline.map(|baseline| TraceBaseline { oa: baseline.oa, sa: baseline.sa, semantic: None, }), } } } #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct Project4 { pub schema_version: u32, pub id: Id, pub alias: String, pub name: String, pub description: String, #[serde(deserialize_with = "crate::unique_id_map")] pub elements: BTreeMap, #[serde(deserialize_with = "crate::unique_id_map")] pub relations: BTreeMap, #[serde(deserialize_with = "crate::unique_id_map")] pub diagrams: BTreeMap, #[serde(deserialize_with = "crate::unique_id_map")] pub artifact_links: BTreeMap, #[serde(deserialize_with = "crate::unique_id_map")] pub traces: BTreeMap, } impl Project4 { pub(crate) fn into_current(self) -> Result { if self.schema_version != 4 { return Err(FileError::Invalid("Expected schema_version 4.".into())); } crate::persistence::check_pre6_relations(self.relations.values())?; crate::persistence::check_pre6_elements(self.elements.values())?; Ok(Project { schema_version: SCHEMA_VERSION, id: self.id, alias: self.alias, name: self.name, description: self.description, elements: self.elements, relations: self.relations, diagrams: self.diagrams, artifact_links: self.artifact_links, traces: self .traces .into_iter() .map(|(id, trace)| (id, trace.into())) .collect(), }) } } pub(crate) fn review_defaults(project: &Project, report: &mut MigrationReport) { report.semantic_defaults.extend( project .traces .values() .filter(|trace| trace.baseline.is_some()) .map(|trace| SemanticDefault { object: trace.id, field: "baseline.semantic".into(), description: "Original prose review preserved; semantic facets remain unreviewed." .into(), }), ); } pub(crate) fn finish(mut project: Project, limits: ParseLimits) -> Result { crate::persistence::check_pre6_relations(project.relations.values())?; crate::persistence::check_pre6_elements(project.elements.values())?; project.schema_version = SCHEMA_VERSION; limits.check_model(&project).map_err(FileError::Limit)?; let mut report = MigrationReport::data_upgrade(4); review_defaults(&project, &mut report); Ok(DecodeResult { project, migration: Some(report), }) } pub(crate) fn migrate(old: Project4, limits: ParseLimits) -> Result { finish(old.into_current()?, limits) }