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}