Skip to main content

postgrest_parser/ast/
schema.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
4pub struct Table {
5    pub schema: String,
6    pub name: String,
7    pub columns: Vec<Column>,
8    pub primary_key: Vec<String>,
9    pub is_view: bool,
10}
11
12impl Table {
13    pub fn new(schema: impl Into<String>, name: impl Into<String>) -> Self {
14        Self {
15            schema: schema.into(),
16            name: name.into(),
17            columns: Vec::new(),
18            primary_key: Vec::new(),
19            is_view: false,
20        }
21    }
22
23    pub fn with_columns(mut self, columns: Vec<Column>) -> Self {
24        self.columns = columns;
25        self
26    }
27
28    pub fn with_primary_key(mut self, primary_key: Vec<String>) -> Self {
29        self.primary_key = primary_key;
30        self
31    }
32
33    pub fn as_view(mut self) -> Self {
34        self.is_view = true;
35        self
36    }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub struct Column {
41    pub name: String,
42    pub type_: String,
43    pub nullable: bool,
44    pub has_default: bool,
45    pub position: usize,
46}
47
48impl Column {
49    pub fn new(name: impl Into<String>, type_: impl Into<String>) -> Self {
50        Self {
51            name: name.into(),
52            type_: type_.into(),
53            nullable: false,
54            has_default: false,
55            position: 0,
56        }
57    }
58
59    pub fn with_position(mut self, position: usize) -> Self {
60        self.position = position;
61        self
62    }
63
64    pub fn nullable(mut self, nullable: bool) -> Self {
65        self.nullable = nullable;
66        self
67    }
68
69    pub fn with_default(mut self, has_default: bool) -> Self {
70        self.has_default = has_default;
71        self
72    }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
76#[serde(rename_all = "snake_case")]
77pub enum Cardinality {
78    ManyToOne,
79    OneToMany,
80    OneToOne,
81    ManyToMany,
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct Junction {
86    pub schema: String,
87    pub table: String,
88    pub source_columns: Vec<String>,
89    pub target_columns: Vec<String>,
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct Relationship {
94    pub constraint_name: String,
95    pub source_schema: String,
96    pub source_table: String,
97    pub source_columns: Vec<String>,
98    pub target_schema: String,
99    pub target_table: String,
100    pub target_columns: Vec<String>,
101    pub cardinality: Cardinality,
102    pub junction: Option<Junction>,
103}
104
105impl Relationship {
106    pub fn new(
107        constraint_name: impl Into<String>,
108        source_schema: impl Into<String>,
109        source_table: impl Into<String>,
110        target_schema: impl Into<String>,
111        target_table: impl Into<String>,
112        cardinality: Cardinality,
113    ) -> Self {
114        Self {
115            constraint_name: constraint_name.into(),
116            source_schema: source_schema.into(),
117            source_table: source_table.into(),
118            source_columns: Vec::new(),
119            target_schema: target_schema.into(),
120            target_table: target_table.into(),
121            target_columns: Vec::new(),
122            cardinality,
123            junction: None,
124        }
125    }
126
127    pub fn with_source_columns(mut self, columns: Vec<String>) -> Self {
128        self.source_columns = columns;
129        self
130    }
131
132    pub fn with_target_columns(mut self, columns: Vec<String>) -> Self {
133        self.target_columns = columns;
134        self
135    }
136
137    pub fn with_junction(mut self, junction: Junction) -> Self {
138        self.junction = Some(junction);
139        self
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn test_table_new() {
149        let table = Table::new("public", "users");
150        assert_eq!(table.schema, "public");
151        assert_eq!(table.name, "users");
152    }
153
154    #[test]
155    fn test_table_with_columns() {
156        let columns = vec![Column::new("id", "integer"), Column::new("name", "text")];
157        let table = Table::new("public", "users").with_columns(columns);
158        assert_eq!(table.columns.len(), 2);
159    }
160
161    #[test]
162    fn test_table_as_view() {
163        let table = Table::new("public", "user_stats").as_view();
164        assert!(table.is_view);
165    }
166
167    #[test]
168    fn test_column_new() {
169        let column = Column::new("id", "integer");
170        assert_eq!(column.name, "id");
171        assert_eq!(column.type_, "integer");
172    }
173
174    #[test]
175    fn test_relationship_new() {
176        let rel = Relationship::new(
177            "fk_user_client",
178            "public",
179            "users",
180            "public",
181            "clients",
182            Cardinality::ManyToOne,
183        );
184        assert_eq!(rel.source_table, "users");
185        assert_eq!(rel.target_table, "clients");
186        assert_eq!(rel.cardinality, Cardinality::ManyToOne);
187    }
188
189    #[test]
190    fn test_relationship_with_junction() {
191        let junction = Junction {
192            schema: "public".to_string(),
193            table: "post_tags".to_string(),
194            source_columns: vec!["post_id".to_string()],
195            target_columns: vec!["tag_id".to_string()],
196        };
197
198        let rel = Relationship::new(
199            "pk_post_tags",
200            "public",
201            "posts",
202            "public",
203            "tags",
204            Cardinality::ManyToMany,
205        )
206        .with_junction(junction);
207
208        assert!(rel.junction.is_some());
209    }
210
211    #[test]
212    fn test_table_serialization() {
213        let table = Table::new("public", "users");
214        let json = serde_json::to_string(&table).unwrap();
215        assert!(json.contains("users"));
216    }
217
218    #[test]
219    fn test_relationship_serialization() {
220        let rel = Relationship::new(
221            "fk",
222            "public",
223            "users",
224            "public",
225            "clients",
226            Cardinality::ManyToOne,
227        );
228        let json = serde_json::to_string(&rel).unwrap();
229        assert!(json.contains("many_to_one"));
230    }
231}