data_modelling_sdk/export/
json_schema.rs1use super::{ExportError, ExportResult};
4use crate::models::{DataModel, Table};
5use serde_json::{Value, json};
6
7pub struct JSONSchemaExporter;
9
10impl JSONSchemaExporter {
11 pub fn export(&self, tables: &[Table]) -> Result<ExportResult, ExportError> {
37 let schema = Self::export_model_from_tables(tables);
38 Ok(ExportResult {
39 content: serde_json::to_string_pretty(&schema)
40 .map_err(|e| ExportError::SerializationError(e.to_string()))?,
41 format: "json_schema".to_string(),
42 })
43 }
44
45 fn export_model_from_tables(tables: &[Table]) -> serde_json::Value {
46 let mut definitions = serde_json::Map::new();
47 for table in tables {
48 let schema = Self::export_table(table);
49 definitions.insert(table.name.clone(), schema);
50 }
51 let mut root = serde_json::Map::new();
52 root.insert(
53 "$schema".to_string(),
54 serde_json::json!("http://json-schema.org/draft-07/schema#"),
55 );
56 root.insert("type".to_string(), serde_json::json!("object"));
57 root.insert("definitions".to_string(), serde_json::json!(definitions));
58 serde_json::json!(root)
59 }
60
61 pub fn export_table(table: &Table) -> Value {
87 let mut properties = serde_json::Map::new();
88
89 for column in &table.columns {
90 let mut property = serde_json::Map::new();
91
92 let (json_type, format) = Self::map_data_type_to_json_schema(&column.data_type);
94 property.insert("type".to_string(), json!(json_type));
95
96 if let Some(fmt) = format {
97 property.insert("format".to_string(), json!(fmt));
98 }
99
100 if !column.nullable {
101 }
103
104 if !column.description.is_empty() {
105 property.insert("description".to_string(), json!(column.description));
106 }
107
108 properties.insert(column.name.clone(), json!(property));
109 }
110
111 let mut schema = serde_json::Map::new();
112 schema.insert(
113 "$schema".to_string(),
114 json!("http://json-schema.org/draft-07/schema#"),
115 );
116 schema.insert("type".to_string(), json!("object"));
117 schema.insert("title".to_string(), json!(table.name));
118 schema.insert("properties".to_string(), json!(properties));
119
120 let required: Vec<String> = table
122 .columns
123 .iter()
124 .filter(|c| !c.nullable)
125 .map(|c| c.name.clone())
126 .collect();
127
128 if !required.is_empty() {
129 schema.insert("required".to_string(), json!(required));
130 }
131
132 json!(schema)
133 }
134
135 pub fn export_model(model: &DataModel, table_ids: Option<&[uuid::Uuid]>) -> Value {
137 let mut definitions = serde_json::Map::new();
138
139 let tables_to_export: Vec<&Table> = if let Some(ids) = table_ids {
140 model
141 .tables
142 .iter()
143 .filter(|t| ids.contains(&t.id))
144 .collect()
145 } else {
146 model.tables.iter().collect()
147 };
148
149 for table in tables_to_export {
150 let schema = Self::export_table(table);
151 definitions.insert(table.name.clone(), schema);
152 }
153
154 let mut root = serde_json::Map::new();
155 root.insert(
156 "$schema".to_string(),
157 json!("http://json-schema.org/draft-07/schema#"),
158 );
159 root.insert("title".to_string(), json!(model.name));
160 root.insert("type".to_string(), json!("object"));
161 root.insert("definitions".to_string(), json!(definitions));
162
163 json!(root)
164 }
165
166 fn map_data_type_to_json_schema(data_type: &str) -> (String, Option<String>) {
168 let dt_lower = data_type.to_lowercase();
169
170 match dt_lower.as_str() {
171 "int" | "integer" | "bigint" | "smallint" | "tinyint" => ("integer".to_string(), None),
172 "float" | "double" | "real" | "decimal" | "numeric" => ("number".to_string(), None),
173 "boolean" | "bool" => ("boolean".to_string(), None),
174 "date" => ("string".to_string(), Some("date".to_string())),
175 "time" => ("string".to_string(), Some("time".to_string())),
176 "timestamp" | "datetime" => ("string".to_string(), Some("date-time".to_string())),
177 "uuid" => ("string".to_string(), Some("uuid".to_string())),
178 "uri" | "url" => ("string".to_string(), Some("uri".to_string())),
179 "email" => ("string".to_string(), Some("email".to_string())),
180 _ => {
181 ("string".to_string(), None)
184 }
185 }
186 }
187}