mecha10_core/schema/
versioning.rs1use super::{CompatibilityCheck, CompatibilityMode, MessageSchema, SchemaRegistryExt};
4use crate::context::Context;
5use crate::error::{Mecha10Error, Result};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct MessageVersionInfo {
11 pub name: String,
13
14 pub current_version: u32,
16
17 pub latest_version: u32,
19
20 pub deprecated: bool,
22
23 pub deprecation_message: Option<String>,
25
26 pub min_supported_version: u32,
28
29 pub compatibility_mode: CompatibilityMode,
31}
32
33pub trait SchemaVersioningExt: SchemaRegistryExt {
35 fn check_compatibility(
37 &self,
38 name: &str,
39 old_version: u32,
40 new_version: u32,
41 mode: CompatibilityMode,
42 ) -> impl std::future::Future<Output = Result<CompatibilityCheck>> + Send;
43
44 fn register_versioned_schema(
46 &self,
47 schema: &MessageSchema,
48 mode: CompatibilityMode,
49 ) -> impl std::future::Future<Output = Result<CompatibilityCheck>> + Send;
50
51 fn get_version_info(
53 &self,
54 name: &str,
55 ) -> impl std::future::Future<Output = Result<Option<MessageVersionInfo>>> + Send;
56
57 fn deprecate_version(
59 &self,
60 name: &str,
61 version: u32,
62 message: String,
63 ) -> impl std::future::Future<Output = Result<()>> + Send;
64
65 fn is_version_deprecated(&self, name: &str, version: u32)
67 -> impl std::future::Future<Output = Result<bool>> + Send;
68}
69
70impl SchemaVersioningExt for Context {
71 async fn check_compatibility(
72 &self,
73 name: &str,
74 old_version: u32,
75 new_version: u32,
76 mode: CompatibilityMode,
77 ) -> Result<CompatibilityCheck> {
78 let old_schema = self
79 .get_schema(name, old_version)
80 .await?
81 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, old_version)))?;
82
83 let new_schema = self
84 .get_schema(name, new_version)
85 .await?
86 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, new_version)))?;
87
88 Ok(CompatibilityCheck::check(&old_schema, &new_schema, mode))
89 }
90
91 async fn register_versioned_schema(
92 &self,
93 schema: &MessageSchema,
94 mode: CompatibilityMode,
95 ) -> Result<CompatibilityCheck> {
96 if schema.version > 1 {
98 let prev_version = schema.version - 1;
99 let check = self
100 .check_compatibility(&schema.name, prev_version, schema.version, mode)
101 .await?;
102
103 if !check.compatible {
104 return Err(Mecha10Error::Other(format!(
105 "Schema compatibility check failed: {:?}",
106 check.incompatibilities
107 )));
108 }
109
110 self.register_schema(schema).await?;
112
113 Ok(check)
114 } else {
115 self.register_schema(schema).await?;
117
118 Ok(CompatibilityCheck {
119 compatible: true,
120 incompatibilities: Vec::new(),
121 evolutions: Vec::new(),
122 warnings: Vec::new(),
123 })
124 }
125 }
126
127 async fn get_version_info(&self, name: &str) -> Result<Option<MessageVersionInfo>> {
128 let latest = self.get_latest_schema(name).await?;
129
130 if let Some(latest_schema) = latest {
131 let deprecated = latest_schema.metadata.contains_key("deprecated");
133 let deprecation_message = latest_schema.metadata.get("deprecation_message").cloned();
134 let min_supported = latest_schema
135 .metadata
136 .get("min_supported_version")
137 .and_then(|v| v.parse().ok())
138 .unwrap_or(1);
139
140 let compatibility_mode = latest_schema
141 .metadata
142 .get("compatibility_mode")
143 .and_then(|m| serde_json::from_str(m).ok())
144 .unwrap_or(CompatibilityMode::Backward);
145
146 Ok(Some(MessageVersionInfo {
147 name: name.to_string(),
148 current_version: latest_schema.version,
149 latest_version: latest_schema.version,
150 deprecated,
151 deprecation_message,
152 min_supported_version: min_supported,
153 compatibility_mode,
154 }))
155 } else {
156 Ok(None)
157 }
158 }
159
160 async fn deprecate_version(&self, name: &str, version: u32, message: String) -> Result<()> {
161 let mut schema = self
162 .get_schema(name, version)
163 .await?
164 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, version)))?;
165
166 schema.metadata.insert("deprecated".to_string(), "true".to_string());
167 schema.metadata.insert("deprecation_message".to_string(), message);
168
169 self.register_schema(&schema).await
170 }
171
172 async fn is_version_deprecated(&self, name: &str, version: u32) -> Result<bool> {
173 let schema = self
174 .get_schema(name, version)
175 .await?
176 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, version)))?;
177
178 Ok(schema.metadata.contains_key("deprecated"))
179 }
180}