allsource_core/application/use_cases/
manage_schema.rs

1use crate::application::dto::{
2    CompatibilityModeDto, ListSchemasResponse, RegisterSchemaRequest, RegisterSchemaResponse,
3    SchemaDto, UpdateSchemaRequest,
4};
5use crate::domain::entities::{CompatibilityMode, Schema};
6use crate::error::Result;
7
8/// Use Case: Register Schema
9///
10/// Registers a new schema or creates a new version of an existing schema.
11pub struct RegisterSchemaUseCase;
12
13impl RegisterSchemaUseCase {
14    pub fn execute(request: RegisterSchemaRequest) -> Result<RegisterSchemaResponse> {
15        // Determine compatibility mode (default to None)
16        let compatibility_mode = request
17            .compatibility_mode
18            .map(CompatibilityMode::from)
19            .unwrap_or(CompatibilityMode::None);
20
21        // Create schema (version 1)
22        let mut schema = Schema::new_v1(request.subject, request.schema, compatibility_mode)?;
23
24        // Set description if provided
25        if let Some(description) = request.description {
26            schema.set_description(description)?;
27        }
28
29        // Add tags if provided
30        if let Some(tags) = request.tags {
31            for tag in tags {
32                schema.add_tag(tag)?;
33            }
34        }
35
36        Ok(RegisterSchemaResponse {
37            schema: SchemaDto::from(&schema),
38        })
39    }
40}
41
42/// Use Case: Create Next Schema Version
43///
44/// Creates a new version of an existing schema.
45pub struct CreateNextSchemaVersionUseCase;
46
47impl CreateNextSchemaVersionUseCase {
48    pub fn execute(
49        current_schema: &Schema,
50        new_schema_definition: serde_json::Value,
51        description: Option<String>,
52    ) -> Result<SchemaDto> {
53        // Create next version
54        let mut next_schema = current_schema.create_next_version(new_schema_definition)?;
55
56        // Set description if provided
57        if let Some(desc) = description {
58            next_schema.set_description(desc)?;
59        }
60
61        // Copy tags from previous version
62        for tag in current_schema.tags() {
63            next_schema.add_tag(tag.clone())?;
64        }
65
66        Ok(SchemaDto::from(&next_schema))
67    }
68}
69
70/// Use Case: Update Schema Metadata
71///
72/// Updates schema description and tags (doesn't change the schema itself).
73pub struct UpdateSchemaMetadataUseCase;
74
75impl UpdateSchemaMetadataUseCase {
76    pub fn execute(mut schema: Schema, request: UpdateSchemaRequest) -> Result<SchemaDto> {
77        // Update description if provided
78        if let Some(description) = request.description {
79            if description.is_empty() {
80                schema.clear_description();
81            } else {
82                schema.set_description(description)?;
83            }
84        }
85
86        // Update tags if provided
87        if let Some(tags) = request.tags {
88            // Clear existing tags and add new ones
89            for existing_tag in schema.tags().to_vec() {
90                schema.remove_tag(&existing_tag);
91            }
92            for tag in tags {
93                schema.add_tag(tag)?;
94            }
95        }
96
97        Ok(SchemaDto::from(&schema))
98    }
99}
100
101/// Use Case: List Schemas
102///
103/// Returns a list of all schemas for a subject.
104pub struct ListSchemasUseCase;
105
106impl ListSchemasUseCase {
107    pub fn execute(schemas: Vec<Schema>) -> ListSchemasResponse {
108        let schema_dtos: Vec<SchemaDto> = schemas.iter().map(SchemaDto::from).collect();
109        let count = schema_dtos.len();
110
111        ListSchemasResponse {
112            schemas: schema_dtos,
113            count,
114        }
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use serde_json::json;
122
123    #[test]
124    fn test_register_schema() {
125        let request = RegisterSchemaRequest {
126            subject: "user.created".to_string(),
127            schema: json!({
128                "type": "object",
129                "properties": {
130                    "name": {"type": "string"},
131                    "email": {"type": "string"}
132                }
133            }),
134            compatibility_mode: Some(CompatibilityModeDto::Backward),
135            description: Some("User creation event schema".to_string()),
136            tags: Some(vec!["user".to_string(), "core".to_string()]),
137        };
138
139        let response = RegisterSchemaUseCase::execute(request);
140        assert!(response.is_ok());
141
142        let response = response.unwrap();
143        assert_eq!(response.schema.subject, "user.created");
144        assert_eq!(response.schema.version, 1);
145        assert_eq!(response.schema.tags.len(), 2);
146        assert_eq!(
147            response.schema.compatibility_mode,
148            CompatibilityModeDto::Backward
149        );
150    }
151
152    #[test]
153    fn test_create_next_version() {
154        let schema = Schema::new_v1(
155            "order.placed".to_string(),
156            json!({"type": "object"}),
157            CompatibilityMode::None,
158        )
159        .unwrap();
160
161        let new_schema = json!({
162            "type": "object",
163            "properties": {
164                "amount": {"type": "number"}
165            }
166        });
167
168        let result = CreateNextSchemaVersionUseCase::execute(
169            &schema,
170            new_schema,
171            Some("Version 2".to_string()),
172        );
173
174        assert!(result.is_ok());
175        let next = result.unwrap();
176        assert_eq!(next.version, 2);
177        assert_eq!(next.subject, "order.placed");
178    }
179
180    #[test]
181    fn test_update_schema_metadata() {
182        let mut schema = Schema::new_v1(
183            "test.event".to_string(),
184            json!({"type": "object"}),
185            CompatibilityMode::None,
186        )
187        .unwrap();
188
189        schema.add_tag("old-tag".to_string()).unwrap();
190
191        let request = UpdateSchemaRequest {
192            description: Some("Updated description".to_string()),
193            tags: Some(vec!["new-tag".to_string()]),
194            compatibility_mode: None,
195        };
196
197        let result = UpdateSchemaMetadataUseCase::execute(schema, request);
198        assert!(result.is_ok());
199
200        let updated = result.unwrap();
201        assert_eq!(updated.description, Some("Updated description".to_string()));
202        assert_eq!(updated.tags, vec!["new-tag".to_string()]);
203    }
204
205    #[test]
206    fn test_list_schemas() {
207        let schemas = vec![
208            Schema::new_v1(
209                "event.one".to_string(),
210                json!({"type": "object"}),
211                CompatibilityMode::None,
212            )
213            .unwrap(),
214            Schema::new_v1(
215                "event.two".to_string(),
216                json!({"type": "object"}),
217                CompatibilityMode::Backward,
218            )
219            .unwrap(),
220        ];
221
222        let response = ListSchemasUseCase::execute(schemas);
223        assert_eq!(response.count, 2);
224        assert_eq!(response.schemas.len(), 2);
225    }
226}