rorm_sql/
create_table.rs

1use std::fmt::Write;
2
3use crate::create_column::{CreateColumn, CreateColumnImpl};
4use crate::error::Error;
5use crate::Value;
6
7/**
8The trait representing a create table builder
9*/
10pub trait CreateTable<'until_build, 'post_build> {
11    /**
12    Add a column to the table.
13     */
14    fn add_column(self, column: CreateColumnImpl<'until_build, 'post_build>) -> Self;
15
16    /**
17    Sets the IF NOT EXISTS trait on the table
18     */
19    fn if_not_exists(self) -> Self;
20
21    /**
22    This method is used to convert the current state for the given dialect in a
23    list of tuples.
24
25    Each tuple consists of the query string and the corresponding bind parameters.
26     */
27    fn build(self) -> Result<Vec<(String, Vec<Value<'post_build>>)>, Error>;
28}
29
30/**
31The representation of an create table operation.
32*/
33pub struct CreateTableData<'until_build, 'post_build> {
34    pub(crate) name: &'until_build str,
35    pub(crate) columns: Vec<CreateColumnImpl<'until_build, 'post_build>>,
36    pub(crate) if_not_exists: bool,
37    pub(crate) lookup: Vec<Value<'post_build>>,
38    pub(crate) pre_statements: Vec<(String, Vec<Value<'post_build>>)>,
39    pub(crate) statements: Vec<(String, Vec<Value<'post_build>>)>,
40}
41
42/**
43The implementation of the [CreateTable] trait for different database dialects.
44
45This should only be constructed via [crate::DBImpl::create_table].
46*/
47pub enum CreateTableImpl<'until_build, 'post_build> {
48    /**
49    SQLite representation of the CREATE TABLE operation.
50     */
51    #[cfg(feature = "sqlite")]
52    SQLite(CreateTableData<'until_build, 'post_build>),
53    /**
54    MySQL representation of the CREATE TABLE operation.
55     */
56    #[cfg(feature = "mysql")]
57    MySQL(CreateTableData<'until_build, 'post_build>),
58    /**
59    Postgres representation of the CREATE TABLE operation.
60     */
61    #[cfg(feature = "postgres")]
62    Postgres(CreateTableData<'until_build, 'post_build>),
63}
64
65impl<'until_build, 'post_build> CreateTable<'until_build, 'post_build>
66    for CreateTableImpl<'until_build, 'post_build>
67{
68    fn add_column(mut self, column: CreateColumnImpl<'until_build, 'post_build>) -> Self {
69        match self {
70            #[cfg(feature = "sqlite")]
71            CreateTableImpl::SQLite(ref mut d) => d.columns.push(column),
72            #[cfg(feature = "mysql")]
73            CreateTableImpl::MySQL(ref mut d) => d.columns.push(column),
74            #[cfg(feature = "postgres")]
75            CreateTableImpl::Postgres(ref mut d) => d.columns.push(column),
76        }
77        self
78    }
79
80    fn if_not_exists(mut self) -> Self {
81        match self {
82            #[cfg(feature = "sqlite")]
83            CreateTableImpl::SQLite(ref mut d) => d.if_not_exists = true,
84            #[cfg(feature = "mysql")]
85            CreateTableImpl::MySQL(ref mut d) => d.if_not_exists = true,
86            #[cfg(feature = "postgres")]
87            CreateTableImpl::Postgres(ref mut d) => d.if_not_exists = true,
88        }
89        self
90    }
91
92    fn build(self) -> Result<Vec<(String, Vec<Value<'post_build>>)>, Error> {
93        match self {
94            #[cfg(feature = "sqlite")]
95            CreateTableImpl::SQLite(mut d) => {
96                let mut s = format!(
97                    "CREATE TABLE{} \"{}\" (",
98                    if d.if_not_exists {
99                        " IF NOT EXISTS"
100                    } else {
101                        ""
102                    },
103                    d.name
104                );
105
106                let columns_len = d.columns.len() - 1;
107                for (idx, mut x) in d.columns.into_iter().enumerate() {
108                    #[cfg(any(feature = "mysql", feature = "postgres"))]
109                    if let CreateColumnImpl::SQLite(ref mut cci) = x {
110                        cci.statements = Some(&mut d.statements)
111                    }
112                    #[cfg(not(any(feature = "mysql", feature = "postgres")))]
113                    {
114                        let CreateColumnImpl::SQLite(ref mut cci) = x;
115                        cci.statements = Some(&mut d.statements);
116                    }
117
118                    x.build(&mut s)?;
119
120                    if idx != columns_len {
121                        write!(s, ", ").unwrap();
122                    }
123                }
124
125                write!(s, ") STRICT; ").unwrap();
126
127                let mut statements = vec![(s, d.lookup)];
128                statements.extend(d.statements);
129
130                Ok(statements)
131            }
132            #[cfg(feature = "mysql")]
133            CreateTableImpl::MySQL(mut d) => {
134                let mut s = format!(
135                    "CREATE TABLE{} `{}` (",
136                    if d.if_not_exists {
137                        " IF NOT EXISTS"
138                    } else {
139                        ""
140                    },
141                    d.name
142                );
143
144                let columns_len = d.columns.len() - 1;
145                for (idx, mut x) in d.columns.into_iter().enumerate() {
146                    #[cfg(any(feature = "postgres", feature = "sqlite"))]
147                    if let CreateColumnImpl::MySQL(ref mut cci) = x {
148                        cci.statements = Some(&mut d.statements);
149                    }
150                    #[cfg(not(any(feature = "postgres", feature = "sqlite")))]
151                    {
152                        let CreateColumnImpl::MySQL(ref mut cci) = x;
153                        cci.statements = Some(&mut d.statements);
154                    }
155
156                    x.build(&mut s)?;
157
158                    if idx != columns_len {
159                        write!(s, ", ").unwrap();
160                    }
161                }
162
163                write!(s, "); ").unwrap();
164
165                let mut statements = vec![(s, d.lookup)];
166                statements.extend(d.statements);
167
168                Ok(statements)
169            }
170            #[cfg(feature = "postgres")]
171            CreateTableImpl::Postgres(mut d) => {
172                let mut s = format!(
173                    "CREATE TABLE{} \"{}\" (",
174                    if d.if_not_exists {
175                        " IF NOT EXISTS"
176                    } else {
177                        ""
178                    },
179                    d.name
180                );
181
182                let columns_len = d.columns.len() - 1;
183                for (idx, mut x) in d.columns.into_iter().enumerate() {
184                    #[cfg(any(feature = "sqlite", feature = "mysql"))]
185                    if let CreateColumnImpl::Postgres(ref mut cci) = x {
186                        cci.pre_statements = Some(&mut d.pre_statements);
187                        cci.statements = Some(&mut d.statements);
188                    }
189                    #[cfg(not(any(feature = "sqlite", feature = "mysql")))]
190                    {
191                        let CreateColumnImpl::Postgres(ref mut cci) = x;
192                        cci.pre_statements = Some(&mut d.pre_statements);
193                        cci.statements = Some(&mut d.statements);
194                    }
195
196                    x.build(&mut s)?;
197
198                    if idx != columns_len {
199                        write!(s, ", ").unwrap();
200                    }
201                }
202
203                write!(s, "); ").unwrap();
204
205                let mut statements = d.pre_statements;
206                statements.push((s, d.lookup));
207                statements.extend(d.statements);
208
209                Ok(statements)
210            }
211        }
212    }
213}