Skip to main content

allsource_core/application/use_cases/
manage_schema.rs

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