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}