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