sea_orm/schema/
json.rs

1use crate::{ColumnTrait, ColumnType, EntityTrait, Iden, Iterable, Schema};
2use serde_json::{Map, Value};
3
4impl Schema {
5    /// Construct a schema description in json for the given Entity.
6    pub fn json_schema_from_entity<E>(&self, entity: E) -> Value
7    where
8        E: EntityTrait,
9    {
10        json_schema_from_entity(entity)
11    }
12}
13
14pub(crate) fn json_schema_from_entity<E>(entity: E) -> Value
15where
16    E: EntityTrait,
17{
18    let mut obj = Map::new();
19    let mut cols = Vec::new();
20
21    if let Some(comment) = entity.comment() {
22        obj.insert("comment".to_owned(), Value::String(comment.to_owned()));
23    }
24
25    for column in E::Column::iter() {
26        let col = json_schema_from_entity_column::<E>(column);
27        cols.push(col);
28    }
29    obj.insert("columns".to_owned(), Value::Array(cols));
30
31    let mut pk = Vec::new();
32    for col in E::PrimaryKey::iter() {
33        pk.push(Value::String(col.to_string()));
34    }
35    obj.insert("primary_key".to_owned(), Value::Array(pk));
36
37    Value::Object(obj)
38}
39
40fn json_schema_from_entity_column<E>(column: E::Column) -> Value
41where
42    E: EntityTrait,
43{
44    let mut obj = Map::new();
45
46    let column_def = column.def();
47    obj.insert("name".to_owned(), Value::String(column.to_string()));
48    obj.insert(
49        "type".to_owned(),
50        type_def_from_column_def(&column_def.col_type),
51    );
52    obj.insert("nullable".to_owned(), Value::Bool(column_def.null));
53    if column_def.unique {
54        obj.insert("unique".to_owned(), Value::Bool(true));
55    }
56    if let Some(comment) = column_def.comment {
57        obj.insert("comment".to_owned(), Value::String(comment));
58    }
59
60    Value::Object(obj)
61}
62
63fn type_def_from_column_def(column_type: &ColumnType) -> Value {
64    match column_type {
65        ColumnType::Char(_) | ColumnType::String(_) | ColumnType::Text => {
66            Value::String("string".to_owned())
67        }
68        ColumnType::TinyInteger
69        | ColumnType::SmallInteger
70        | ColumnType::Integer
71        | ColumnType::BigInteger
72        | ColumnType::TinyUnsigned
73        | ColumnType::SmallUnsigned
74        | ColumnType::Unsigned
75        | ColumnType::BigUnsigned => Value::String("integer".to_owned()),
76        ColumnType::Float | ColumnType::Double => Value::String("real".to_owned()),
77        ColumnType::Decimal(_) | ColumnType::Money(_) => Value::String("decimal".to_owned()),
78        ColumnType::DateTime | ColumnType::Timestamp | ColumnType::TimestampWithTimeZone => {
79            Value::String("datetime".to_owned())
80        }
81        ColumnType::Time => Value::String("time".to_owned()),
82        ColumnType::Date => Value::String("date".to_owned()),
83        ColumnType::Year => Value::String("year".to_owned()),
84        ColumnType::Binary(_)
85        | ColumnType::VarBinary(_)
86        | ColumnType::Bit(_)
87        | ColumnType::VarBit(_) => Value::String("binary".to_owned()),
88        ColumnType::Boolean => Value::String("bool".to_owned()),
89        ColumnType::Json | ColumnType::JsonBinary => Value::String("json".to_owned()),
90        ColumnType::Uuid => Value::String("uuid".to_owned()),
91        ColumnType::Custom(typename) => Value::String(typename.to_string()),
92        ColumnType::Enum { name, variants } => {
93            let mut enum_def = Map::new();
94            enum_def.insert("name".to_owned(), Value::String(name.to_string()));
95            let variants: Vec<Value> = variants
96                .iter()
97                .map(|v| Value::String(v.to_string()))
98                .collect();
99            enum_def.insert("variants".to_owned(), Value::Array(variants));
100            Value::Object(enum_def)
101        }
102        ColumnType::Array(inner) => {
103            let mut obj = Map::new();
104            obj.insert("array".to_owned(), type_def_from_column_def(inner));
105            Value::Object(obj)
106        }
107        _ => Value::String("other".to_owned()),
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use super::*;
114    use crate::{
115        DbBackend,
116        tests_cfg::{cake, lunch_set},
117    };
118
119    #[test]
120    fn test_json_schema_from_entity() {
121        let json = Schema::new(DbBackend::MySql).json_schema_from_entity(cake::Entity);
122        println!("{}", serde_json::to_string_pretty(&json).unwrap());
123        assert_eq!(
124            json,
125            serde_json::from_str::<Value>(
126                r#"{
127                "columns": [
128                    {
129                        "name": "id",
130                        "nullable": false,
131                        "type": "integer"
132                    },
133                    {
134                        "name": "name",
135                        "nullable": false,
136                        "type": "string"
137                    }
138                ],
139                "primary_key": [
140                    "id"
141                ]
142            }"#
143            )
144            .unwrap()
145        );
146
147        let json = Schema::new(DbBackend::MySql).json_schema_from_entity(lunch_set::Entity);
148        println!("{}", serde_json::to_string_pretty(&json).unwrap());
149        assert_eq!(
150            json,
151            serde_json::from_str::<Value>(
152                r#"{
153                "columns": [
154                    {
155                        "name": "id",
156                        "nullable": false,
157                        "type": "integer"
158                    },
159                    {
160                        "name": "name",
161                        "nullable": false,
162                        "type": "string"
163                    },
164                    {
165                        "name": "tea",
166                        "nullable": false,
167                        "type": {
168                            "name": "tea",
169                            "variants": [
170                                "EverydayTea",
171                                "BreakfastTea"
172                            ]
173                        }
174                    }
175                ],
176                "primary_key": [
177                    "id"
178                ]
179            }"#
180            )
181            .unwrap()
182        );
183    }
184}