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        column_def.name.prepare(sql.as_writer(), self.quote());
6
7        if let Some(column_type) = &column_def.types {
8            write!(sql, " ").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 let ColumnSpec::PrimaryKey = column_spec {
17                is_primary_key = true;
18                continue;
19            }
20            if let ColumnSpec::AutoIncrement = column_spec {
21                is_auto_increment = true;
22                continue;
23            }
24            if let ColumnSpec::Comment(_) = column_spec {
25                continue;
26            }
27            write!(sql, " ").unwrap();
28            self.prepare_column_spec(column_spec, sql);
29        }
30
31        if is_primary_key {
32            write!(sql, " ").unwrap();
33            self.prepare_column_spec(&ColumnSpec::PrimaryKey, sql);
34        }
35        if is_auto_increment {
36            write!(sql, " ").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        write!(sql, "ALTER TABLE ").unwrap();
69        if let Some(table) = &alter.table {
70            self.prepare_table_ref_table_stmt(table, sql);
71            write!(sql, " ").unwrap();
72        }
73        match &alter.options[0] {
74            TableAlterOption::AddColumn(AddColumnOption {
75                column,
76                if_not_exists: _,
77            }) => {
78                write!(sql, "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                write!(sql, "RENAME COLUMN ").unwrap();
86                from_name.prepare(sql.as_writer(), self.quote());
87                write!(sql, " TO ").unwrap();
88                to_name.prepare(sql.as_writer(), self.quote());
89            }
90            TableAlterOption::DropColumn(col_name) => {
91                write!(sql, "DROP COLUMN ").unwrap();
92                col_name.prepare(sql.as_writer(), self.quote());
93            }
94            TableAlterOption::DropForeignKey(_) => {
95                panic!("Sqlite does not support modification of foreign key constraints to existing tables");
96            }
97            TableAlterOption::AddForeignKey(_) => {
98                panic!("Sqlite does not support modification of foreign key constraints to existing tables");
99            }
100        }
101    }
102
103    fn prepare_table_rename_statement(
104        &self,
105        rename: &TableRenameStatement,
106        sql: &mut dyn SqlWriter,
107    ) {
108        write!(sql, "ALTER TABLE ").unwrap();
109        if let Some(from_name) = &rename.from_name {
110            self.prepare_table_ref_table_stmt(from_name, sql);
111        }
112        write!(sql, " RENAME TO ").unwrap();
113        if let Some(to_name) = &rename.to_name {
114            self.prepare_table_ref_table_stmt(to_name, sql);
115        }
116    }
117}
118
119impl SqliteQueryBuilder {
120    fn prepare_column_type(
121        &self,
122        column_specs: &[ColumnSpec],
123        column_type: &ColumnType,
124        sql: &mut dyn SqlWriter,
125    ) {
126        let is_auto_increment = column_specs
127            .iter()
128            .any(|s| matches!(s, ColumnSpec::AutoIncrement));
129        write!(
130            sql,
131            "{}",
132            match column_type {
133                ColumnType::Char(length) => match length {
134                    Some(length) => format!("char({length})"),
135                    None => "char".into(),
136                },
137                ColumnType::String(length) => match length {
138                    StringLen::N(length) => format!("varchar({length})"),
139                    _ => "varchar".into(),
140                },
141                ColumnType::Text => "text".into(),
142                ColumnType::TinyInteger | ColumnType::TinyUnsigned => integer("tinyint").into(),
143                ColumnType::SmallInteger | ColumnType::SmallUnsigned => integer("smallint").into(),
144                ColumnType::Integer | ColumnType::Unsigned => "integer".into(),
145                #[allow(clippy::if_same_then_else)]
146                ColumnType::BigInteger | ColumnType::BigUnsigned => if is_auto_increment {
147                    "integer"
148                } else {
149                    integer("bigint")
150                }
151                .into(),
152                ColumnType::Float => "float".into(),
153                ColumnType::Double => "double".into(),
154                ColumnType::Decimal(precision) => match precision {
155                    Some((precision, scale)) => {
156                        if precision > &16 {
157                            panic!("precision cannot be larger than 16");
158                        }
159                        format!("real({precision}, {scale})")
160                    }
161                    None => "real".into(),
162                },
163                ColumnType::DateTime => "datetime_text".into(),
164                ColumnType::Timestamp => "timestamp_text".into(),
165                ColumnType::TimestampWithTimeZone => "timestamp_with_timezone_text".into(),
166                ColumnType::Time => "time_text".into(),
167                ColumnType::Date => "date_text".into(),
168                ColumnType::Interval(_, _) =>
169                    unimplemented!("Interval is not available in Sqlite."),
170                ColumnType::Binary(length) => format!("blob({length})"),
171                ColumnType::VarBinary(length) => match length {
172                    StringLen::N(length) => format!("varbinary_blob({length})"),
173                    _ => "varbinary_blob".into(),
174                },
175                ColumnType::Blob => "blob".into(),
176                ColumnType::Boolean => "boolean".into(),
177                ColumnType::Money(precision) => match precision {
178                    Some((precision, scale)) => format!("real_money({precision}, {scale})"),
179                    None => "real_money".into(),
180                },
181                ColumnType::Json => "json_text".into(),
182                ColumnType::JsonBinary => "jsonb_text".into(),
183                ColumnType::Uuid => "uuid_text".into(),
184                ColumnType::Custom(iden) => iden.to_string(),
185                ColumnType::Enum { .. } => "enum_text".into(),
186                ColumnType::Array(_) => unimplemented!("Array is not available in Sqlite."),
187                ColumnType::Vector(_) => unimplemented!("Vector is not available in Sqlite."),
188                ColumnType::Cidr => unimplemented!("Cidr is not available in Sqlite."),
189                ColumnType::Inet => unimplemented!("Inet is not available in Sqlite."),
190                ColumnType::MacAddr => unimplemented!("MacAddr is not available in Sqlite."),
191                ColumnType::Year => unimplemented!("Year is not available in Sqlite."),
192                ColumnType::Bit(_) => unimplemented!("Bit is not available in Sqlite."),
193                ColumnType::VarBit(_) => unimplemented!("VarBit is not available in Sqlite."),
194                ColumnType::LTree => unimplemented!("LTree is not available in Sqlite."),
195            }
196        )
197        .unwrap()
198    }
199}
200
201fn integer(ty: &str) -> &str {
202    if cfg!(feature = "option-sqlite-exact-column-type") {
203        "integer"
204    } else {
205        ty
206    }
207}