limbo_sqlite3_parser/to_sql_string/stmt/
create_table.rs1use std::fmt::Display;
2
3use crate::{ast, to_sql_string::ToSqlString};
4
5impl ToSqlString for ast::CreateTableBody {
6 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
7 match self {
8 Self::AsSelect(select) => format!("AS {}", select.to_sql_string(context)),
9 Self::ColumnsAndConstraints {
10 columns,
11 constraints,
12 options,
13 } => {
14 format!(
15 "({}{}){}",
16 columns
17 .iter()
18 .map(|(_, col)| col.to_sql_string(context))
19 .collect::<Vec<_>>()
20 .join(", "),
21 constraints
22 .as_ref()
23 .map_or("".to_string(), |constraints| format!(
24 ", {}",
25 constraints
26 .iter()
27 .map(|constraint| constraint.to_sql_string(context))
28 .collect::<Vec<_>>()
29 .join(", ")
30 )),
31 options
32 )
33 }
34 }
35 }
36}
37
38impl ToSqlString for ast::NamedTableConstraint {
39 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
40 if let Some(name) = &self.name {
41 format!(
42 "CONSTRAINT {} {}",
43 name.0,
44 self.constraint.to_sql_string(context)
45 )
46 } else {
47 format!("{}", self.constraint.to_sql_string(context))
48 }
49 }
50}
51
52impl ToSqlString for ast::TableConstraint {
53 fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
54 match self {
55 Self::Check(expr) => format!("CHECK ({})", expr.to_sql_string(context)),
56 Self::ForeignKey {
57 columns,
58 clause,
59 deref_clause,
60 } => format!(
61 "FOREIGN KEY ({}) {}{}",
62 columns
63 .iter()
64 .map(|col| col.to_string())
65 .collect::<Vec<_>>()
66 .join(", "),
67 clause,
68 if let Some(deref) = deref_clause {
69 deref.to_string()
70 } else {
71 "".to_string()
72 }
73 ),
74 Self::PrimaryKey {
75 columns,
76 auto_increment,
77 conflict_clause,
78 } => format!(
79 "PRIMARY KEY ({}){}{}",
80 columns
81 .iter()
82 .map(|col| col.to_sql_string(context))
83 .collect::<Vec<_>>()
84 .join(", "),
85 conflict_clause.map_or("".to_string(), |conflict| format!(" {}", conflict)),
86 auto_increment.then_some(" AUTOINCREMENT").unwrap_or("")
87 ),
88 Self::Unique {
89 columns,
90 conflict_clause,
91 } => format!(
92 "UNIQUE ({}){}",
93 columns
94 .iter()
95 .map(|col| col.to_sql_string(context))
96 .collect::<Vec<_>>()
97 .join(", "),
98 conflict_clause.map_or("".to_string(), |conflict| format!(" {}", conflict))
99 ),
100 }
101 }
102}
103
104impl Display for ast::TableOptions {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(
107 f,
108 "{}",
109 if *self == Self::NONE {
110 ""
111 } else if *self == Self::STRICT {
112 " STRICT"
113 } else {
114 " WITHOUT ROWID"
115 }
116 )
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use crate::to_sql_string_test;
123
124 to_sql_string_test!(
125 test_create_table_simple,
126 "CREATE TABLE t (a INTEGER, b TEXT);"
127 );
128
129 to_sql_string_test!(
130 test_create_table_primary_key,
131 "CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT);"
132 );
133
134 to_sql_string_test!(
135 test_create_table_multi_primary_key,
136 "CREATE TABLE t (a INTEGER, b TEXT, PRIMARY KEY (a, b));"
137 );
138
139 to_sql_string_test!(
140 test_create_table_data_types,
141 "CREATE TABLE t (a INTEGER, b TEXT, c REAL, d BLOB, e NUMERIC);"
142 );
143
144 to_sql_string_test!(
145 test_create_table_foreign_key,
146 "CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id));"
147 );
148
149 to_sql_string_test!(
150 test_create_table_foreign_key_cascade,
151 "CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id) ON DELETE CASCADE);"
152 );
153
154 to_sql_string_test!(
155 test_create_table_unique,
156 "CREATE TABLE t (a INTEGER UNIQUE, b TEXT);"
157 );
158
159 to_sql_string_test!(
160 test_create_table_not_null,
161 "CREATE TABLE t (a INTEGER NOT NULL, b TEXT);"
162 );
163
164 to_sql_string_test!(
165 test_create_table_check,
166 "CREATE TABLE t (a INTEGER CHECK (a > 0), b TEXT);"
167 );
168
169 to_sql_string_test!(
170 test_create_table_default,
171 "CREATE TABLE t (a INTEGER DEFAULT 0, b TEXT);"
172 );
173
174 to_sql_string_test!(
175 test_create_table_multiple_constraints,
176 "CREATE TABLE t (a INTEGER NOT NULL UNIQUE, b TEXT DEFAULT 'default');"
177 );
178
179 to_sql_string_test!(
180 test_create_table_generated_column,
181 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b));"
182 );
183
184 to_sql_string_test!(
185 test_create_table_generated_stored,
186 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) STORED);"
187 );
188
189 to_sql_string_test!(
190 test_create_table_generated_virtual,
191 "CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) VIRTUAL);"
192 );
193
194 to_sql_string_test!(
195 test_create_table_quoted_columns,
196 "CREATE TABLE t (\"select\" INTEGER, \"from\" TEXT);"
197 );
198
199 to_sql_string_test!(
200 test_create_table_quoted_table,
201 "CREATE TABLE \"my table\" (a INTEGER);"
202 );
203
204 to_sql_string_test!(
205 test_create_table_if_not_exists,
206 "CREATE TABLE IF NOT EXISTS t (a INTEGER);"
207 );
208
209 to_sql_string_test!(test_create_temp_table, "CREATE TEMP TABLE t (a INTEGER);");
210
211 to_sql_string_test!(
212 test_create_table_without_rowid,
213 "CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID;"
214 );
215
216 to_sql_string_test!(
217 test_create_table_named_primary_key,
218 "CREATE TABLE t (a INTEGER CONSTRAINT pk_a PRIMARY KEY);"
219 );
220
221 to_sql_string_test!(
222 test_create_table_named_unique,
223 "CREATE TABLE t (a INTEGER, CONSTRAINT unique_a UNIQUE (a));"
224 );
225
226 to_sql_string_test!(
227 test_create_table_named_foreign_key,
228 "CREATE TABLE t2 (id INTEGER, t_id INTEGER, CONSTRAINT fk_t FOREIGN KEY (t_id) REFERENCES t(id));"
229 );
230
231 to_sql_string_test!(
232 test_create_table_complex,
233 "CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER NOT NULL, b TEXT DEFAULT 'default', c INTEGER AS (a * 2), CONSTRAINT unique_a UNIQUE (a));"
234 );
235
236 to_sql_string_test!(
237 test_create_table_multiple_foreign_keys,
238 "CREATE TABLE t3 (id INTEGER PRIMARY KEY, t1_id INTEGER, t2_id INTEGER, FOREIGN KEY (t1_id) REFERENCES t1(id), FOREIGN KEY (t2_id) REFERENCES t2(id));"
239 );
240}