Skip to main content

shelly_data/
schema.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
4#[serde(rename_all = "snake_case")]
5pub enum FieldType {
6    String,
7    Text,
8    Integer,
9    Float,
10    Boolean,
11    Date,
12    DateTime,
13    Json,
14    Uuid,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct Field {
19    pub name: String,
20    pub field_type: FieldType,
21    pub required: bool,
22}
23
24impl Field {
25    pub fn new(name: impl Into<String>, field_type: FieldType) -> Self {
26        Self {
27            name: name.into(),
28            field_type,
29            required: false,
30        }
31    }
32
33    pub fn required(mut self) -> Self {
34        self.required = true;
35        self
36    }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct Schema {
41    pub name: String,
42    pub table: String,
43    pub fields: Vec<Field>,
44}
45
46impl Schema {
47    pub fn new(name: impl Into<String>, table: impl Into<String>) -> Self {
48        Self {
49            name: name.into(),
50            table: table.into(),
51            fields: Vec::new(),
52        }
53    }
54
55    pub fn with_field(mut self, field: Field) -> Self {
56        self.fields.push(field);
57        self
58    }
59}
60
61pub trait SchemaDefinition {
62    fn schema() -> Schema;
63}
64
65#[cfg(test)]
66mod tests {
67    use super::{Field, FieldType, Schema, SchemaDefinition};
68
69    #[test]
70    fn required_marks_field_as_required() {
71        let field = Field::new("title", FieldType::String).required();
72        assert_eq!(field.name, "title");
73        assert_eq!(field.field_type, FieldType::String);
74        assert!(field.required);
75    }
76
77    #[test]
78    fn schema_builder_collects_fields() {
79        let schema = Schema::new("Post", "posts")
80            .with_field(Field::new("id", FieldType::Integer).required())
81            .with_field(Field::new("title", FieldType::String));
82
83        assert_eq!(schema.name, "Post");
84        assert_eq!(schema.table, "posts");
85        assert_eq!(schema.fields.len(), 2);
86        assert_eq!(schema.fields[0].name, "id");
87        assert!(schema.fields[0].required);
88    }
89
90    #[test]
91    fn schema_definition_trait_can_expose_schema() {
92        struct PostSchema;
93
94        impl SchemaDefinition for PostSchema {
95            fn schema() -> Schema {
96                Schema::new("Post", "posts")
97                    .with_field(Field::new("id", FieldType::Integer).required())
98                    .with_field(Field::new("title", FieldType::String).required())
99            }
100        }
101
102        let schema = PostSchema::schema();
103        assert_eq!(schema.name, "Post");
104        assert_eq!(schema.fields.len(), 2);
105        assert!(schema.fields.iter().all(|field| field.required));
106    }
107}