Skip to main content

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    Postgres representation of the CREATE TABLE operation.
55     */
56    #[cfg(feature = "postgres")]
57    Postgres(CreateTableData<'until_build, 'post_build>),
58}
59
60impl<'until_build, 'post_build> CreateTable<'until_build, 'post_build>
61    for CreateTableImpl<'until_build, 'post_build>
62{
63    fn add_column(mut self, column: CreateColumnImpl<'until_build, 'post_build>) -> Self {
64        match self {
65            #[cfg(feature = "sqlite")]
66            CreateTableImpl::SQLite(ref mut d) => d.columns.push(column),
67            #[cfg(feature = "postgres")]
68            CreateTableImpl::Postgres(ref mut d) => d.columns.push(column),
69        }
70        self
71    }
72
73    fn if_not_exists(mut self) -> Self {
74        match self {
75            #[cfg(feature = "sqlite")]
76            CreateTableImpl::SQLite(ref mut d) => d.if_not_exists = true,
77            #[cfg(feature = "postgres")]
78            CreateTableImpl::Postgres(ref mut d) => d.if_not_exists = true,
79        }
80        self
81    }
82
83    fn build(self) -> Result<Vec<(String, Vec<Value<'post_build>>)>, Error> {
84        match self {
85            #[cfg(feature = "sqlite")]
86            CreateTableImpl::SQLite(mut d) => {
87                let mut s = format!(
88                    "CREATE TABLE{} \"{}\" (",
89                    if d.if_not_exists {
90                        " IF NOT EXISTS"
91                    } else {
92                        ""
93                    },
94                    d.name
95                );
96
97                let columns_len = d.columns.len() - 1;
98                for (idx, mut x) in d.columns.into_iter().enumerate() {
99                    if let CreateColumnImpl::SQLite(cci) = &mut x {
100                        cci.statements = Some(&mut d.statements)
101                    }
102
103                    x.build(&mut s)?;
104
105                    if idx != columns_len {
106                        write!(s, ", ").unwrap();
107                    }
108                }
109
110                write!(s, ") STRICT; ").unwrap();
111
112                let mut statements = vec![(s, d.lookup)];
113                statements.extend(d.statements);
114
115                Ok(statements)
116            }
117            #[cfg(feature = "postgres")]
118            CreateTableImpl::Postgres(mut d) => {
119                let mut s = format!(
120                    "CREATE TABLE{} \"{}\" (",
121                    if d.if_not_exists {
122                        " IF NOT EXISTS"
123                    } else {
124                        ""
125                    },
126                    d.name
127                );
128
129                let columns_len = d.columns.len() - 1;
130                for (idx, mut x) in d.columns.into_iter().enumerate() {
131                    #[allow(irrefutable_let_patterns)]
132                    if let CreateColumnImpl::Postgres(cci) = &mut x {
133                        cci.pre_statements = Some(&mut d.pre_statements);
134                        cci.statements = Some(&mut d.statements);
135                    }
136
137                    x.build(&mut s)?;
138
139                    if idx != columns_len {
140                        write!(s, ", ").unwrap();
141                    }
142                }
143
144                write!(s, "); ").unwrap();
145
146                let mut statements = d.pre_statements;
147                statements.push((s, d.lookup));
148                statements.extend(d.statements);
149
150                Ok(statements)
151            }
152        }
153    }
154}