Skip to main content

mendes_models/
lib.rs

1use std::borrow::Cow;
2use std::fmt;
3
4pub use mendes_macros::model;
5
6pub struct Table {
7    pub name: Cow<'static, str>,
8    pub columns: Vec<Column>,
9    pub constraints: Vec<Constraint>,
10}
11
12impl fmt::Display for Table {
13    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
14        write!(fmt, "CREATE TABLE {} (", self.name)?;
15        for (i, col) in self.columns.iter().enumerate() {
16            if i > 0 {
17                write!(fmt, ", ")?;
18            }
19            write!(fmt, "{}", col)?;
20        }
21        for constraint in self.constraints.iter() {
22            write!(fmt, ", {}", constraint)?;
23        }
24        write!(fmt, ")")
25    }
26}
27
28pub struct Column {
29    pub name: Cow<'static, str>,
30    pub ty: Cow<'static, str>,
31    pub null: bool,
32    pub default: Option<Cow<'static, str>>,
33}
34
35impl fmt::Display for Column {
36    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(fmt, "{} {}", self.name, self.ty)?;
38        if !self.null {
39            write!(fmt, " NOT NULL")?;
40        }
41        Ok(())
42    }
43}
44
45pub enum Constraint {
46    PrimaryKey {
47        name: Cow<'static, str>,
48        columns: Vec<Cow<'static, str>>,
49    },
50}
51
52impl fmt::Display for Constraint {
53    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Constraint::PrimaryKey { name, columns } => {
56                write!(fmt, "CONSTRAINT {} PRIMARY KEY (", name)?;
57                for (i, col) in columns.iter().enumerate() {
58                    if i > 0 {
59                        write!(fmt, ", ")?;
60                    }
61                    write!(fmt, "{}", col)?;
62                }
63                write!(fmt, ")")
64            }
65        }
66    }
67}
68
69pub struct Serial<T>(T);
70
71pub trait Model<S: System> {
72    fn table() -> Table;
73}
74
75pub trait ToColumn<T>: System {
76    fn to_column(name: Cow<'static, str>, params: &[(&str, &str)]) -> Column;
77}
78
79impl ToColumn<Serial<i32>> for PostgreSQL {
80    fn to_column(name: Cow<'static, str>, _: &[(&str, &str)]) -> Column {
81        Column {
82            name,
83            ty: "serial".into(),
84            null: false,
85            default: None,
86        }
87    }
88}
89
90impl ToColumn<i32> for PostgreSQL {
91    fn to_column(name: Cow<'static, str>, _: &[(&str, &str)]) -> Column {
92        Column {
93            name,
94            ty: "integer".into(),
95            null: false,
96            default: None,
97        }
98    }
99}
100
101impl ToColumn<i64> for PostgreSQL {
102    fn to_column(name: Cow<'static, str>, _: &[(&str, &str)]) -> Column {
103        Column {
104            name,
105            ty: "bigint".into(),
106            null: false,
107            default: None,
108        }
109    }
110}
111
112impl ToColumn<String> for PostgreSQL {
113    fn to_column(name: Cow<'static, str>, _: &[(&str, &str)]) -> Column {
114        Column {
115            name,
116            ty: "text".into(),
117            null: false,
118            default: None,
119        }
120    }
121}
122
123#[cfg(feature = "chrono")]
124impl ToColumn<chrono::NaiveDate> for PostgreSQL {
125    fn to_column(name: Cow<'static, str>, _: &[(&str, &str)]) -> Column {
126        Column {
127            name,
128            ty: "date".into(),
129            null: false,
130            default: None,
131        }
132    }
133}
134
135pub struct PostgreSQL {}
136
137impl System for PostgreSQL {}
138
139pub trait System: Sized {
140    fn table<M: Model<Self>>() -> Table {
141        M::table()
142    }
143}