sea_query/backend/sqlite/
table.rs

1use super::*;
2
3impl TableBuilder for SqliteQueryBuilder {
4    fn prepare_column_def(&self, column_def: &ColumnDef, sql: &mut dyn SqlWriter) {
5        self.prepare_iden(&column_def.name, sql);
6
7        if let Some(column_type) = &column_def.types {
8            sql.write_str(" ").unwrap();
9            self.prepare_column_type(&column_def.spec, column_type, sql);
10        }
11
12        let mut is_primary_key = false;
13        let mut is_auto_increment = false;
14
15        for column_spec in column_def.spec.iter() {
16            if matches!(column_spec, ColumnSpec::PrimaryKey) {
17                is_primary_key = true;
18                continue;
19            }
20            if matches!(column_spec, ColumnSpec::AutoIncrement) {
21                is_auto_increment = true;
22                continue;
23            }
24            if let ColumnSpec::Comment(_) = column_spec {
25                continue;
26            }
27            sql.write_str(" ").unwrap();
28            self.prepare_column_spec(column_spec, sql);
29        }
30
31        if is_primary_key {
32            sql.write_str(" ").unwrap();
33            self.prepare_column_spec(&ColumnSpec::PrimaryKey, sql);
34        }
35        if is_auto_increment {
36            sql.write_str(" ").unwrap();
37            self.prepare_column_spec(&ColumnSpec::AutoIncrement, sql);
38        }
39    }
40
41    fn prepare_column_type(&self, column_type: &ColumnType, sql: &mut dyn SqlWriter) {
42        self.prepare_column_type(&[], column_type, sql)
43    }
44
45    fn column_spec_auto_increment_keyword(&self) -> &str {
46        "AUTOINCREMENT"
47    }
48
49    fn prepare_table_drop_opt(&self, _drop_opt: &TableDropOpt, _sql: &mut dyn SqlWriter) {
50        // Sqlite does not support table drop options
51    }
52
53    fn prepare_table_truncate_statement(
54        &self,
55        _truncate: &TableTruncateStatement,
56        _sql: &mut dyn SqlWriter,
57    ) {
58        panic!("Sqlite doesn't support TRUNCATE statement")
59    }
60
61    fn prepare_table_alter_statement(&self, alter: &TableAlterStatement, sql: &mut dyn SqlWriter) {
62        if alter.options.is_empty() {
63            panic!("No alter option found")
64        }
65        if alter.options.len() > 1 {
66            panic!("Sqlite doesn't support multiple alter options")
67        }
68        sql.write_str("ALTER TABLE ").unwrap();
69        if let Some(table) = &alter.table {
70            self.prepare_table_ref_table_stmt(table, sql);
71            sql.write_str(" ").unwrap();
72        }
73        match &alter.options[0] {
74            TableAlterOption::AddColumn(AddColumnOption {
75                column,
76                if_not_exists: _,
77            }) => {
78                sql.write_str("ADD COLUMN ").unwrap();
79                self.prepare_column_def(column, sql);
80            }
81            TableAlterOption::ModifyColumn(_) => {
82                panic!("Sqlite not support modifying table column")
83            }
84            TableAlterOption::RenameColumn(from_name, to_name) => {
85                sql.write_str("RENAME COLUMN ").unwrap();
86                self.prepare_iden(from_name, sql);
87                sql.write_str(" TO ").unwrap();
88                self.prepare_iden(to_name, sql);
89            }
90            TableAlterOption::DropColumn(col_name) => {
91                sql.write_str("DROP COLUMN ").unwrap();
92                self.prepare_iden(col_name, sql);
93            }
94            TableAlterOption::DropForeignKey(_) => {
95                panic!(
96                    "Sqlite does not support modification of foreign key constraints to existing tables"
97                );
98            }
99            TableAlterOption::AddForeignKey(_) => {
100                panic!(
101                    "Sqlite does not support modification of foreign key constraints to existing tables"
102                );
103            }
104        }
105    }
106
107    fn prepare_table_rename_statement(
108        &self,
109        rename: &TableRenameStatement,
110        sql: &mut dyn SqlWriter,
111    ) {
112        sql.write_str("ALTER TABLE ").unwrap();
113        if let Some(from_name) = &rename.from_name {
114            self.prepare_table_ref_table_stmt(from_name, sql);
115        }
116        sql.write_str(" RENAME TO ").unwrap();
117        if let Some(to_name) = &rename.to_name {
118            self.prepare_table_ref_table_stmt(to_name, sql);
119        }
120    }
121}
122
123impl SqliteQueryBuilder {
124    fn prepare_column_type(
125        &self,
126        column_specs: &[ColumnSpec],
127        column_type: &ColumnType,
128        sql: &mut dyn SqlWriter,
129    ) {
130        let is_auto_increment = column_specs
131            .iter()
132            .any(|s| matches!(s, ColumnSpec::AutoIncrement));
133        match column_type {
134            ColumnType::Char(length) => match length {
135                Some(length) => {
136                    sql.write_str("char(").unwrap();
137                    write!(sql, "{length}").unwrap();
138                    sql.write_char(')')
139                }
140                None => sql.write_str("char"),
141            },
142            ColumnType::String(length) => match length {
143                StringLen::N(length) => {
144                    sql.write_str("varchar(").unwrap();
145                    write!(sql, "{length}").unwrap();
146                    sql.write_char(')')
147                }
148                _ => sql.write_str("varchar"),
149            },
150            ColumnType::Text => sql.write_str("text"),
151            ColumnType::TinyInteger | ColumnType::TinyUnsigned => sql.write_str(integer("tinyint")),
152            ColumnType::SmallInteger | ColumnType::SmallUnsigned => {
153                sql.write_str(integer("smallint"))
154            }
155            ColumnType::Integer | ColumnType::Unsigned => sql.write_str("integer"),
156            #[allow(clippy::if_same_then_else)]
157            ColumnType::BigInteger | ColumnType::BigUnsigned => {
158                if is_auto_increment {
159                    sql.write_str("integer")
160                } else {
161                    sql.write_str(integer("bigint"))
162                }
163            }
164            ColumnType::Float => sql.write_str("float"),
165            ColumnType::Double => sql.write_str("double"),
166            ColumnType::Decimal(precision) => match precision {
167                Some((precision, scale)) => {
168                    if precision > &16 {
169                        panic!("precision cannot be larger than 16");
170                    }
171                    sql.write_str("real(").unwrap();
172                    write!(sql, "{precision}").unwrap();
173                    sql.write_str(", ").unwrap();
174                    write!(sql, "{scale}").unwrap();
175                    sql.write_char(')')
176                }
177                None => sql.write_str("real"),
178            },
179            ColumnType::DateTime => sql.write_str("datetime_text"),
180            ColumnType::Timestamp => sql.write_str("timestamp_text"),
181            ColumnType::TimestampWithTimeZone => sql.write_str("timestamp_with_timezone_text"),
182            ColumnType::Time => sql.write_str("time_text"),
183            ColumnType::Date => sql.write_str("date_text"),
184            ColumnType::Interval(_, _) => unimplemented!("Interval is not available in Sqlite."),
185            ColumnType::Binary(length) => {
186                sql.write_str("blob(").unwrap();
187                write!(sql, "{length}").unwrap();
188                sql.write_char(')')
189            }
190            ColumnType::VarBinary(length) => match length {
191                StringLen::N(length) => {
192                    sql.write_str("varbinary_blob(").unwrap();
193                    write!(sql, "{length}").unwrap();
194                    sql.write_char(')')
195                }
196                _ => sql.write_str("varbinary_blob"),
197            },
198            ColumnType::Blob => sql.write_str("blob"),
199            ColumnType::Boolean => sql.write_str("boolean"),
200            ColumnType::Money(precision) => match precision {
201                Some((precision, scale)) => {
202                    sql.write_str("real_money(").unwrap();
203                    write!(sql, "{precision}").unwrap();
204                    sql.write_str(", ").unwrap();
205                    write!(sql, "{scale}").unwrap();
206                    sql.write_char(')')
207                }
208                None => sql.write_str("real_money"),
209            },
210            ColumnType::Json => sql.write_str("json_text"),
211            ColumnType::JsonBinary => sql.write_str("jsonb_text"),
212            ColumnType::Uuid => sql.write_str("uuid_text"),
213            ColumnType::Custom(iden) => sql.write_str(&iden.0),
214            ColumnType::Enum { .. } => sql.write_str("enum_text"),
215            ColumnType::Array(_) => unimplemented!("Array is not available in Sqlite."),
216            ColumnType::Vector(_) => unimplemented!("Vector is not available in Sqlite."),
217            ColumnType::Cidr => unimplemented!("Cidr is not available in Sqlite."),
218            ColumnType::Inet => unimplemented!("Inet is not available in Sqlite."),
219            ColumnType::MacAddr => unimplemented!("MacAddr is not available in Sqlite."),
220            ColumnType::Year => unimplemented!("Year is not available in Sqlite."),
221            ColumnType::Bit(_) => unimplemented!("Bit is not available in Sqlite."),
222            ColumnType::VarBit(_) => unimplemented!("VarBit is not available in Sqlite."),
223            ColumnType::LTree => unimplemented!("LTree is not available in Sqlite."),
224        }
225        .unwrap()
226    }
227}
228
229fn integer(ty: &str) -> &str {
230    if cfg!(feature = "option-sqlite-exact-column-type") {
231        "integer"
232    } else {
233        ty
234    }
235}