1use crate::*;
2use std::fmt::Write;
3
4pub trait SqlWriter:
16 SqlCoreWriter + SqlValueWriter + SqlExpressionWriter + SqlFragmentWriter
17{
18 fn write_select<'a, Data>(&self, out: &mut DynQuery, query: &impl SelectQuery<Data>)
20 where
21 Self: Sized,
22 Data: Dataset + 'a,
23 {
24 let Some(from) = query.get_from() else {
25 log::error!("The query does not have the FROM clause");
26 return;
27 };
28 let columns = query.get_select();
29 let columns_count = columns.clone().into_iter().count();
30 out.buffer().reserve(128 + columns_count * 32);
31 if !out.is_empty() {
32 out.push('\n');
33 }
34 out.push_str("SELECT ");
35 let mut context = Context::new(Fragment::SqlSelect, Data::qualified_columns());
36 if columns_count != 0 {
37 separated_by(
38 out,
39 columns.clone(),
40 |out, col| {
41 col.write_query(self, &mut context, out);
42 },
43 ", ",
44 );
45 } else {
46 out.push('*');
47 }
48 out.push_str("\nFROM ");
49 from.write_table_name(
50 self,
51 &mut context.switch_fragment(Fragment::SqlSelectFrom).current,
52 out,
53 );
54 if let Some(condition) = query.get_where()
55 && !condition.accept_visitor(&mut IsTrue, self, &mut context, out)
56 {
57 out.push_str("\nWHERE ");
58 condition.write_query(
59 self,
60 &mut context.switch_fragment(Fragment::SqlSelectWhere).current,
61 out,
62 );
63 }
64 let mut group_by = query.get_group_by().peekable();
65 if group_by.peek().is_some() {
66 out.push_str("\nGROUP BY ");
67 let mut context = context.switch_fragment(Fragment::SqlSelectGroupBy);
68 separated_by(
69 out,
70 group_by,
71 |out, col| {
72 col.write_query(self, &mut context.current, out);
73 },
74 ", ",
75 );
76 }
77 if let Some(having) = query.get_having() {
78 out.push_str("\nHAVING ");
79 having.write_query(
80 self,
81 &mut context.switch_fragment(Fragment::SqlSelectHaving).current,
82 out,
83 );
84 }
85 let mut order_by = query.get_order_by().peekable();
86 if order_by.peek().is_some() {
87 out.push_str("\nORDER BY ");
88 let mut context = context.switch_fragment(Fragment::SqlSelectOrderBy);
89 separated_by(
90 out,
91 order_by,
92 |out, col| {
93 col.write_query(self, &mut context.current, out);
94 },
95 ", ",
96 );
97 }
98 if let Some(limit) = query.get_limit() {
99 let _ = write!(out, "\nLIMIT {limit}");
100 }
101 out.push(';');
102 }
103
104 fn write_insert<It>(&self, out: &mut DynQuery, entities: It, update: bool)
106 where
107 Self: Sized,
108 It: IntoIterator,
109 It::Item: AsEntity,
110 {
111 type E<It> = <<It as IntoIterator>::Item as AsEntity>::Entity;
112 let table = E::<It>::table();
113 let mut entities = entities.into_iter().peekable();
114 if entities.peek().is_none() {
115 return;
116 };
117 let cols = E::<It>::columns().len();
118 out.buffer().reserve(128 + cols * 32);
119 if !out.is_empty() {
120 out.push('\n');
121 }
122 out.push_str("INSERT INTO ");
123 let mut context = Context::new(Fragment::SqlInsertInto, E::<It>::qualified_columns());
124 self.write_table_ref(&mut context, out, table);
125 out.push_str(" (");
126 separated_by(
127 out,
128 E::<It>::columns().iter(),
129 |out, col| {
130 self.write_identifier(&mut context, out, col.name(), true);
131 },
132 ", ",
133 );
134 out.push_str(") VALUES");
135 let mut context = context.switch_fragment(Fragment::SqlInsertIntoValues);
136 separated_by(
137 out,
138 entities,
139 |out, entity| {
140 out.push_str("\n(");
141 entity
142 .as_entity()
143 .write_query(self.as_dyn(), &mut context.current, out);
144 out.push(')');
145 },
146 ",",
147 );
148 if update {
149 self.write_insert_update_fragment::<E<It>>(
150 &mut context.current,
151 out,
152 E::<It>::columns().iter(),
153 );
154 }
155 out.push(';');
156 }
157
158 fn write_delete<E>(&self, out: &mut DynQuery, condition: impl Expression)
160 where
161 Self: Sized,
162 E: Entity,
163 {
164 let table = E::table();
165 out.buffer().reserve(128);
166 if !out.is_empty() {
167 out.push('\n');
168 }
169 out.push_str("DELETE FROM ");
170 let mut context = Context::new(Fragment::SqlDeleteFrom, E::qualified_columns());
171 self.write_table_ref(&mut context, out, table);
172 out.push_str("\nWHERE ");
173 condition.write_query(
174 self,
175 &mut context
176 .switch_fragment(Fragment::SqlDeleteFromWhere)
177 .current,
178 out,
179 );
180 out.push(';');
181 }
182
183 fn write_create_schema<E>(&self, out: &mut DynQuery, if_not_exists: bool)
185 where
186 Self: Sized,
187 E: Entity,
188 {
189 let table = E::table();
190 out.buffer().reserve(32 + table.schema.len());
191 if !out.is_empty() {
192 out.push('\n');
193 }
194 out.push_str("CREATE SCHEMA ");
195 let mut context = Context::new(Fragment::SqlCreateSchema, E::qualified_columns());
196 if if_not_exists {
197 out.push_str("IF NOT EXISTS ");
198 }
199 self.write_identifier(&mut context, out, &table.schema, true);
200 out.push(';');
201 }
202
203 fn write_drop_schema<E>(&self, out: &mut DynQuery, if_exists: bool)
205 where
206 Self: Sized,
207 E: Entity,
208 {
209 let mut context = Context::new(Fragment::SqlDropSchema, E::qualified_columns());
210 let table = E::table();
211 out.buffer().reserve(32 + table.schema.len());
212 if !out.is_empty() {
213 out.push('\n');
214 }
215 out.push_str("DROP SCHEMA ");
216 if if_exists {
217 out.push_str("IF EXISTS ");
218 }
219 self.write_identifier(&mut context, out, &table.schema, true);
220 out.push(';');
221 }
222
223 fn write_create_table<E>(&self, out: &mut DynQuery, if_not_exists: bool)
225 where
226 Self: Sized,
227 E: Entity,
228 {
229 let mut context = Context::new(Fragment::SqlCreateTable, E::qualified_columns());
230 let table = E::table();
231 let estimated = 128 + E::columns().len() * 64 + E::primary_key_def().len() * 24;
232 out.buffer().reserve(estimated);
233 if !out.is_empty() {
234 out.push('\n');
235 }
236 out.push_str("CREATE TABLE ");
237 if if_not_exists {
238 out.push_str("IF NOT EXISTS ");
239 }
240 self.write_table_ref(&mut context, out, table);
241 out.push_str(" (\n");
242 separated_by(
243 out,
244 E::columns(),
245 |out, col| {
246 self.write_create_table_column_fragment(&mut context, out, col);
247 },
248 ",\n",
249 );
250 let pk = E::primary_key_def();
251 if pk.len() > 1 {
252 self.write_create_table_primary_key_fragment(&mut context, out, pk.iter().map(|v| *v));
253 }
254 for unique in E::unique_defs() {
255 if unique.len() > 0 {
256 out.push_str(",\nUNIQUE (");
257 separated_by(
258 out,
259 unique,
260 |out, col| {
261 self.write_identifier(
262 &mut context
263 .switch_fragment(Fragment::SqlCreateTableUnique)
264 .current,
265 out,
266 col.name(),
267 true,
268 );
269 },
270 ", ",
271 );
272 out.push(')');
273 }
274 }
275 let foreign_keys = E::columns().iter().filter(|c| c.references.is_some());
276 separated_by(
277 out,
278 foreign_keys,
279 |out, column| {
280 let references = column.references.as_ref().unwrap();
281 out.push_str(",\nFOREIGN KEY (");
282 self.write_identifier(&mut context, out, &column.name(), true);
283 out.push_str(") REFERENCES ");
284 self.write_table_ref(&mut context, out, &references.table());
285 out.push('(');
286 self.write_column_ref(&mut context, out, references);
287 out.push(')');
288 if let Some(on_delete) = &column.on_delete {
289 out.push_str(" ON DELETE ");
290 self.write_create_table_references_action_fragment(
291 &mut context,
292 out,
293 on_delete,
294 );
295 }
296 if let Some(on_update) = &column.on_update {
297 out.push_str(" ON UPDATE ");
298 self.write_create_table_references_action_fragment(
299 &mut context,
300 out,
301 on_update,
302 );
303 }
304 },
305 "",
306 );
307 out.push_str(");");
308 self.write_column_comments_statements_fragment::<E>(&mut context, out);
309 }
310
311 fn write_drop_table<E>(&self, out: &mut DynQuery, if_exists: bool)
313 where
314 Self: Sized,
315 E: Entity,
316 {
317 let table = E::table();
318 out.buffer()
319 .reserve(24 + table.schema.len() + table.name.len());
320 if !out.is_empty() {
321 out.push('\n');
322 }
323 out.push_str("DROP TABLE ");
324 let mut context = Context::new(Fragment::SqlDropTable, E::qualified_columns());
325 if if_exists {
326 out.push_str("IF EXISTS ");
327 }
328 self.write_table_ref(&mut context, out, table);
329 out.push(';');
330 }
331
332 fn write_transaction_begin(&self, out: &mut DynQuery) {
334 out.push_str("BEGIN;");
335 }
336
337 fn write_transaction_commit(&self, out: &mut DynQuery) {
339 out.push_str("COMMIT;");
340 }
341
342 fn write_transaction_rollback(&self, out: &mut DynQuery) {
344 out.push_str("ROLLBACK;");
345 }
346}
347
348pub struct GenericSqlWriter;
350impl GenericSqlWriter {
351 pub fn new() -> Self {
353 Self {}
354 }
355}
356impl SqlCoreWriter for GenericSqlWriter {
357 fn as_dyn(&self) -> &dyn SqlWriter {
358 self
359 }
360}
361impl SqlValueWriter for GenericSqlWriter {}
362impl SqlExpressionWriter for GenericSqlWriter {}
363impl SqlFragmentWriter for GenericSqlWriter {}
364impl SqlWriter for GenericSqlWriter {}