barrel/backend/
sqlite3.rs

1//! Sqlite3 implementation of a generator
2
3use super::SqlGenerator;
4use crate::{
5    functions::AutogenFunction,
6    types::{BaseType, ReferentialAction, Type, WrappedDefault},
7};
8
9/// A simple macro that will generate a schema prefix if it exists
10macro_rules! prefix {
11    ($schema:expr) => {
12        $schema
13            .map(|s| format!("\"{}\".", s))
14            .unwrap_or_else(|| String::new())
15    };
16}
17
18/// We call this struct Sqlite instead of Sqlite3 because we hope not
19/// to have to break the API further down the road
20pub struct Sqlite;
21impl SqlGenerator for Sqlite {
22    fn create_table(name: &str, schema: Option<&str>) -> String {
23        format!("CREATE TABLE {}\"{}\"", prefix!(schema), name)
24    }
25
26    fn create_table_if_not_exists(name: &str, schema: Option<&str>) -> String {
27        format!("CREATE TABLE IF NOT EXISTS {}\"{}\"", prefix!(schema), name)
28    }
29
30    fn drop_table(name: &str, schema: Option<&str>) -> String {
31        format!("DROP TABLE {}\"{}\"", prefix!(schema), name)
32    }
33
34    fn drop_table_if_exists(name: &str, schema: Option<&str>) -> String {
35        format!("DROP TABLE IF EXISTS {}\"{}\"", prefix!(schema), name)
36    }
37
38    fn rename_table(old: &str, new: &str, schema: Option<&str>) -> String {
39        let schema = prefix!(schema);
40        format!("ALTER TABLE {}\"{}\" RENAME TO \"{}\"", schema, old, new)
41    }
42
43    fn alter_table(name: &str, schema: Option<&str>) -> String {
44        format!("ALTER TABLE {}\"{}\"", prefix!(schema), name)
45    }
46
47    fn add_column(ex: bool, _: Option<&str>, name: &str, tt: &Type) -> String {
48        let bt: BaseType = tt.get_inner();
49        let btc = bt.clone();
50        use self::BaseType::*;
51        let primary_definition = match tt.primary {
52            true => " PRIMARY KEY",
53            false => "",
54        };
55        let default_definition = match (&tt.default).as_ref() {
56            Some(ref m) => match m {
57                WrappedDefault::Function(ref fun) => match fun {
58                    AutogenFunction::CurrentTimestamp => format!(" DEFAULT CURRENT_TIMESTAMP"),
59                },
60                WrappedDefault::Null => format!(" DEFAULT NULL"),
61                WrappedDefault::AnyText(ref val) => format!(" DEFAULT '{}'", val),
62                WrappedDefault::UUID(ref val) => format!(" DEFAULT '{}'", val),
63                WrappedDefault::Date(ref val) => format!(" DEFAULT '{:?}'", val),
64                WrappedDefault::Boolean(val) => format!(" DEFAULT {}", if *val { 1 } else { 0 }),
65                WrappedDefault::Custom(ref val) => format!(" DEFAULT '{}'", val),
66                _ => format!(" DEFAULT {}", m),
67            },
68            _ => format!(""),
69        };
70        let nullable_definition = match tt.nullable {
71            true => "",
72            false => " NOT NULL",
73        };
74        let unique_definition = match tt.unique {
75            true => " UNIQUE",
76            false => "",
77        };
78        #[cfg_attr(rustfmt, rustfmt_skip)] /* This shouldn't be formatted. It's too long */
79        let base_type_definition = match bt {
80            Text => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
81            Varchar(_) => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
82            Char(_) => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
83            Primary => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
84            Integer => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
85            Serial => panic!("SQLite has no serials for non-primary key columns"),
86            Float => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
87            Double => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
88            UUID => panic!("`UUID` not supported by Sqlite3. Use `Text` instead!"),
89            Json => panic!("`Json` not supported by Sqlite3. Use `Text` instead!"),
90            Boolean => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
91            Date => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
92            Time => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
93            DateTime => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
94            Binary => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
95            Foreign(_, _, _, _, _) => format!("{}\"{}\" INTEGER{} REFERENCES {}", Sqlite::prefix(ex), name, nullable_definition, Sqlite::print_type(bt)),
96            Custom(_) => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(bt)),
97            Array(it) => format!("{}\"{}\" {}", Sqlite::prefix(ex), name, Sqlite::print_type(Array(Box::new(*it)))),
98            Index(_) => unreachable!("Indices are handled via custom builder"),
99            Constraint(_, _) => unreachable!("Constraints are handled via custom builder"),
100        };
101
102        match btc {
103            Foreign(_, _, _, _, _) => {
104                format!(
105                    "{}{}{}{}",
106                    base_type_definition, primary_definition, default_definition, unique_definition,
107                )
108            }
109            _ => {
110                format!(
111                    "{}{}{}{}{}",
112                    base_type_definition,
113                    primary_definition,
114                    default_definition,
115                    nullable_definition,
116                    unique_definition,
117                )
118            }
119        }
120        //#[cfg_attr(rustfmt, rustfmt_skip)] /* This shouldn't be formatted. It's too long */
121        //format!(
122        //    // SQL base - default - nullable - unique
123        //    "{}{}{}{}{}",
124        //    base_type_definition,
125        //    primary_definition,
126        //    default_definition,
127        //    nullable_definition,
128        //    unique_definition
129        //)
130    }
131
132    /// Create a multi-column index
133    fn create_index(table: &str, schema: Option<&str>, name: &str, _type: &Type) -> String {
134        format!(
135            "CREATE {} INDEX {}\"{}\" ON \"{}\" ({})",
136            match _type.unique {
137                true => "UNIQUE",
138                false => "",
139            },
140            prefix!(schema),
141            name,
142            table,
143            match _type.inner {
144                BaseType::Index(ref cols) => cols
145                    .iter()
146                    .map(|col| format!("\"{}\"", col))
147                    .collect::<Vec<_>>()
148                    .join(", "),
149                _ => unreachable!(),
150            }
151        )
152    }
153
154    fn create_constraint(name: &str, _type: &Type) -> String {
155        let (r#type, columns) = match _type.inner {
156            BaseType::Constraint(ref r#type, ref columns) => (
157                r#type.clone(),
158                columns
159                    .iter()
160                    .map(|col| format!("\"{}\"", col))
161                    .collect::<Vec<_>>(),
162            ),
163            _ => unreachable!(),
164        };
165
166        format!(
167            "CONSTRAINT \"{}\" {} ({})",
168            name,
169            r#type,
170            columns.join(", "),
171        )
172    }
173
174    /// Drop a multi-column index
175    fn drop_index(name: &str) -> String {
176        format!("DROP INDEX \"{}\"", name)
177    }
178
179    fn drop_column(_: &str) -> String {
180        panic!("Sqlite does not support dropping columns!")
181    }
182
183    fn rename_column(_: &str, _: &str) -> String {
184        panic!("Sqlite does not support renaming columns!")
185    }
186
187    fn add_foreign_key(
188        columns: &[String],
189        table: &str,
190        relation_columns: &[String],
191        _: Option<&str>,
192    ) -> String {
193        let columns: Vec<_> = columns.into_iter().map(|c| format!("\"{}\"", c)).collect();
194
195        let relation_columns: Vec<_> = relation_columns
196            .into_iter()
197            .map(|c| format!("\"{}\"", c))
198            .collect();
199
200        format!(
201            "FOREIGN KEY({}) REFERENCES \"{}\"({})",
202            columns.join(","),
203            table,
204            relation_columns.join(","),
205        )
206    }
207
208    fn add_primary_key(columns: &[String]) -> String {
209        let columns: Vec<_> = columns.into_iter().map(|c| format!("\"{}\"", c)).collect();
210        format!("PRIMARY KEY ({})", columns.join(","))
211    }
212}
213
214impl Sqlite {
215    fn prefix(ex: bool) -> String {
216        match ex {
217            true => format!("ADD COLUMN "),
218            false => format!(""),
219        }
220    }
221
222    fn print_type(t: BaseType) -> String {
223        use self::BaseType::*;
224        match t {
225            Text => format!("TEXT"),
226            Varchar(l) => match l {
227                0 => format!("VARCHAR"), // For "0" remove the limit
228                _ => format!("VARCHAR({})", l),
229            },
230            Char(l) => format!("CHAR({})", l),
231            Primary => format!("INTEGER NOT NULL PRIMARY KEY"),
232            Serial => panic!("SQLite has no serials for non-primary key columns"),
233            Integer => format!("INTEGER"),
234            Float => format!("REAL"),
235            Double => format!("DOUBLE"),
236            UUID => unimplemented!(),
237            Boolean => format!("BOOLEAN"),
238            Date => format!("DATE"),
239            Time => format!("TIME"),
240            DateTime => format!("DATETIME"),
241            Json => panic!("Json is not supported by Sqlite3"),
242            Binary => format!("BINARY"),
243            Foreign(_, t, refs, on_update, on_delete) => {
244                let d = match on_delete {
245                    ReferentialAction::Unset => String::from(""),
246                    _ => format!(" {}", on_delete.on_delete()),
247                };
248                let u = match on_update {
249                    ReferentialAction::Unset => String::from(""),
250                    _ => format!(" {}", on_update.on_update()),
251                };
252                format!("{}({}){}{}", t, refs.0.join(","), u, d)
253            }
254            Custom(t) => format!("{}", t),
255            Array(meh) => format!("{}[]", Sqlite::print_type(*meh)),
256            Index(_) => unimplemented!(),
257            Constraint(_, _) => unreachable!("Constraints are handled via custom builder"),
258        }
259    }
260}