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 {
97 let prev_version = schema.version - 1;
98 let check = self
99 .check_compatibility(&schema.name, prev_version, schema.version, mode)
100 .await?;
101
102 if !check.compatible {
103 return Err(Mecha10Error::Other(format!(
104 "Schema compatibility check failed: {:?}",
105 check.incompatibilities
106 )));
107 }
108
109 self.register_schema(schema).await?;
110
111 Ok(check)
112 } else {
113 self.register_schema(schema).await?;
114
115 Ok(CompatibilityCheck {
116 compatible: true,
117 incompatibilities: Vec::new(),
118 evolutions: Vec::new(),
119 warnings: Vec::new(),
120 })
121 }
122 }
123
124 async fn get_version_info(&self, name: &str) -> Result<Option<MessageVersionInfo>> {
125 let latest = self.get_latest_schema(name).await?;
126
127 if let Some(latest_schema) = latest {
128 let deprecated = latest_schema.metadata.contains_key("deprecated");
129 let deprecation_message = latest_schema.metadata.get("deprecation_message").cloned();
130 let min_supported = latest_schema
131 .metadata
132 .get("min_supported_version")
133 .and_then(|v| v.parse().ok())
134 .unwrap_or(1);
135
136 let compatibility_mode = latest_schema
137 .metadata
138 .get("compatibility_mode")
139 .and_then(|m| serde_json::from_str(m).ok())
140 .unwrap_or(CompatibilityMode::Backward);
141
142 Ok(Some(MessageVersionInfo {
143 name: name.to_string(),
144 current_version: latest_schema.version,
145 latest_version: latest_schema.version,
146 deprecated,
147 deprecation_message,
148 min_supported_version: min_supported,
149 compatibility_mode,
150 }))
151 } else {
152 Ok(None)
153 }
154 }
155
156 async fn deprecate_version(&self, name: &str, version: u32, message: String) -> Result<()> {
157 let mut schema = self
158 .get_schema(name, version)
159 .await?
160 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, version)))?;
161
162 schema.metadata.insert("deprecated".to_string(), "true".to_string());
163 schema.metadata.insert("deprecation_message".to_string(), message);
164
165 self.register_schema(&schema).await
166 }
167
168 async fn is_version_deprecated(&self, name: &str, version: u32) -> Result<bool> {
169 let schema = self
170 .get_schema(name, version)
171 .await?
172 .ok_or_else(|| Mecha10Error::Other(format!("Schema {} v{} not found", name, version)))?;
173
174 Ok(schema.metadata.contains_key("deprecated"))
175 }
176}