tank_core/writer/
sql_writer.rs

1use crate::{
2    Action, BinaryOp, BinaryOpType, ColumnDef, ColumnRef, DataSet, EitherIterator, Entity,
3    Expression, Fragment, Interval, Join, JoinType, Operand, Order, Ordered, PrimaryKeyType,
4    TableRef, UnaryOp, UnaryOpType, Value, possibly_parenthesized, separated_by, writer::Context,
5};
6use futures::future::Either;
7use std::{collections::HashMap, fmt::Write};
8use time::{Date, Time};
9
10macro_rules! write_integer {
11    ($buff:ident, $value:expr) => {{
12        let mut buffer = itoa::Buffer::new();
13        $buff.push_str(buffer.format($value));
14    }};
15}
16macro_rules! write_float {
17    ($this:ident, $context:ident,$buff:ident, $value:expr) => {{
18        if $value.is_infinite() {
19            $this.write_value_infinity($context, $buff, $value.is_sign_negative());
20        } else {
21            let mut buffer = ryu::Buffer::new();
22            $buff.push_str(buffer.format($value));
23        }
24    }};
25}
26
27pub trait SqlWriter {
28    fn as_dyn(&self) -> &dyn SqlWriter;
29
30    fn alias_declaration(&self, context: &mut Context) -> bool {
31        match context.fragment {
32            Fragment::SqlSelectFrom | Fragment::SqlJoin => true,
33            _ => false,
34        }
35    }
36
37    fn write_escaped(
38        &self,
39        _context: &mut Context,
40        buff: &mut String,
41        value: &str,
42        search: char,
43        replace: &str,
44    ) {
45        let mut position = 0;
46        for (i, c) in value.char_indices() {
47            if c == search {
48                buff.push_str(&value[position..i]);
49                buff.push_str(replace);
50                position = i + 1;
51            }
52        }
53        buff.push_str(&value[position..]);
54    }
55
56    fn write_identifier_quoted(&self, context: &mut Context, buff: &mut String, value: &str) {
57        buff.push('"');
58        self.write_escaped(context, buff, value, '"', r#""""#);
59        buff.push('"');
60    }
61
62    fn write_table_ref(&self, context: &mut Context, buff: &mut String, value: &TableRef) {
63        if self.alias_declaration(context) || value.alias.is_empty() {
64            if !value.schema.is_empty() {
65                self.write_identifier_quoted(context, buff, &value.schema);
66                buff.push('.');
67            }
68            self.write_identifier_quoted(context, buff, &value.name);
69        }
70        if !value.alias.is_empty() {
71            let _ = write!(buff, " {}", value.alias);
72        }
73    }
74
75    fn write_column_ref(&self, context: &mut Context, buff: &mut String, value: &ColumnRef) {
76        if context.qualify_columns && !value.table.is_empty() {
77            if !value.schema.is_empty() {
78                self.write_identifier_quoted(context, buff, &value.schema);
79                buff.push('.');
80            }
81            self.write_identifier_quoted(context, buff, &value.table);
82            buff.push('.');
83        }
84        self.write_identifier_quoted(context, buff, &value.name);
85    }
86
87    fn write_column_type(&self, context: &mut Context, buff: &mut String, value: &Value) {
88        match value {
89            Value::Boolean(..) => buff.push_str("BOOLEAN"),
90            Value::Int8(..) => buff.push_str("TINYINT"),
91            Value::Int16(..) => buff.push_str("SMALLINT"),
92            Value::Int32(..) => buff.push_str("INTEGER"),
93            Value::Int64(..) => buff.push_str("BIGINT"),
94            Value::Int128(..) => buff.push_str("HUGEINT"),
95            Value::UInt8(..) => buff.push_str("UTINYINT"),
96            Value::UInt16(..) => buff.push_str("USMALLINT"),
97            Value::UInt32(..) => buff.push_str("UINTEGER"),
98            Value::UInt64(..) => buff.push_str("UBIGINT"),
99            Value::UInt128(..) => buff.push_str("UHUGEINT"),
100            Value::Float32(..) => buff.push_str("FLOAT"),
101            Value::Float64(..) => buff.push_str("DOUBLE"),
102            Value::Decimal(.., precision, scale) => {
103                buff.push_str("DECIMAL");
104                if (precision, scale) != (&0, &0) {
105                    let _ = write!(buff, "({},{})", precision, scale);
106                }
107            }
108            Value::Char(..) => buff.push_str("CHAR(1)"),
109            Value::Varchar(..) => buff.push_str("VARCHAR"),
110            Value::Blob(..) => buff.push_str("BLOB"),
111            Value::Date(..) => buff.push_str("DATE"),
112            Value::Time(..) => buff.push_str("TIME"),
113            Value::Timestamp(..) => buff.push_str("TIMESTAMP"),
114            Value::TimestampWithTimezone(..) => buff.push_str("TIMESTAMP WITH TIME ZONE"),
115            Value::Interval(..) => buff.push_str("INTERVAL"),
116            Value::Uuid(..) => buff.push_str("UUID"),
117            Value::Array(.., inner, size) => {
118                self.write_column_type(context, buff, inner);
119                let _ = write!(buff, "[{}]", size);
120            }
121            Value::List(.., inner) => {
122                self.write_column_type(context, buff, inner);
123                buff.push_str("[]");
124            }
125            Value::Map(.., key, value) => {
126                buff.push_str("MAP(");
127                self.write_column_type(context, buff, key);
128                buff.push(',');
129                self.write_column_type(context, buff, value);
130                buff.push(')');
131            }
132            _ => log::error!(
133                "Unexpected tank::Value, variant {:?} is not supported",
134                value
135            ),
136        };
137    }
138
139    fn write_value(&self, context: &mut Context, buff: &mut String, value: &Value) {
140        match value {
141            v if v.is_null() => self.write_value_none(context, buff),
142            Value::Boolean(Some(v), ..) => self.write_value_bool(context, buff, *v),
143            Value::Int8(Some(v), ..) => write_integer!(buff, *v),
144            Value::Int16(Some(v), ..) => write_integer!(buff, *v),
145            Value::Int32(Some(v), ..) => write_integer!(buff, *v),
146            Value::Int64(Some(v), ..) => write_integer!(buff, *v),
147            Value::Int128(Some(v), ..) => write_integer!(buff, *v),
148            Value::UInt8(Some(v), ..) => write_integer!(buff, *v),
149            Value::UInt16(Some(v), ..) => write_integer!(buff, *v),
150            Value::UInt32(Some(v), ..) => write_integer!(buff, *v),
151            Value::UInt64(Some(v), ..) => write_integer!(buff, *v),
152            Value::UInt128(Some(v), ..) => write_integer!(buff, *v),
153            Value::Float32(Some(v), ..) => write_float!(self, context, buff, *v),
154            Value::Float64(Some(v), ..) => write_float!(self, context, buff, *v),
155            Value::Decimal(Some(v), ..) => drop(write!(buff, "{}", v)),
156            Value::Char(Some(v), ..) => {
157                buff.push('\'');
158                buff.push(*v);
159                buff.push('\'');
160            }
161            Value::Varchar(Some(v), ..) => self.write_value_string(context, buff, v),
162            Value::Blob(Some(v), ..) => self.write_value_blob(context, buff, v.as_ref()),
163            Value::Date(Some(v), ..) => {
164                buff.push('\'');
165                self.write_value_date(context, buff, v);
166                buff.push('\'');
167            }
168            Value::Time(Some(v), ..) => {
169                buff.push('\'');
170                self.write_value_time(context, buff, v);
171                buff.push('\'');
172            }
173            Value::Timestamp(Some(v), ..) => {
174                buff.push('\'');
175                self.write_value_date(context, buff, &v.date());
176                buff.push('T');
177                self.write_value_time(context, buff, &v.time());
178                buff.push('\'');
179            }
180            Value::TimestampWithTimezone(Some(v), ..) => {
181                buff.push('\'');
182                self.write_value_date(context, buff, &v.date());
183                buff.push('T');
184                self.write_value_time(context, buff, &v.time());
185                let _ = write!(
186                    buff,
187                    "{:+02}:{:02}",
188                    v.offset().whole_hours(),
189                    v.offset().whole_minutes()
190                );
191                buff.push('\'');
192            }
193            Value::Interval(Some(v), ..) => self.write_value_interval(context, buff, v),
194            Value::Uuid(Some(v), ..) => drop(write!(buff, "'{}'", v)),
195            Value::Array(Some(..), ..) | Value::List(Some(..), ..) => match value {
196                Value::Array(Some(v), ..) => {
197                    self.write_value_list(context, buff, Either::Left(v), value)
198                }
199                Value::List(Some(v), ..) => {
200                    self.write_value_list(context, buff, Either::Right(v), value)
201                }
202                _ => unreachable!(),
203            },
204            Value::Map(Some(v), ..) => self.write_value_map(context, buff, v),
205            Value::Struct(Some(_v), ..) => {
206                todo!()
207            }
208            _ => {
209                log::error!("Cannot write {:?}", value);
210            }
211        };
212    }
213
214    fn write_value_none(&self, _context: &mut Context, buff: &mut String) {
215        buff.push_str("NULL");
216    }
217
218    fn write_value_bool(&self, _context: &mut Context, buff: &mut String, value: bool) {
219        buff.push_str(["false", "true"][value as usize]);
220    }
221
222    fn write_value_infinity(&self, context: &mut Context, buff: &mut String, negative: bool) {
223        let mut buffer = ryu::Buffer::new();
224        self.write_expression_binary_op(
225            context,
226            buff,
227            &BinaryOp {
228                op: BinaryOpType::Cast,
229                lhs: &Operand::LitStr(buffer.format(if negative {
230                    f64::NEG_INFINITY
231                } else {
232                    f64::INFINITY
233                })),
234                rhs: &Operand::Type(Value::Float64(None)),
235            },
236        );
237    }
238
239    fn write_value_string(&self, _context: &mut Context, buff: &mut String, value: &str) {
240        buff.push('\'');
241        let mut position = 0;
242        for (i, c) in value.char_indices() {
243            if c == '\'' {
244                buff.push_str(&value[position..i]);
245                buff.push_str("''");
246                position = i + 1;
247            } else if c == '\n' {
248                buff.push_str(&value[position..i]);
249                buff.push_str("\\n");
250                position = i + 1;
251            }
252        }
253        buff.push_str(&value[position..]);
254        buff.push('\'');
255    }
256
257    fn write_value_blob(&self, _context: &mut Context, buff: &mut String, value: &[u8]) {
258        buff.push('\'');
259        for b in value {
260            let _ = write!(buff, "\\x{:X}", b);
261        }
262        buff.push('\'');
263    }
264
265    fn write_value_date(&self, _context: &mut Context, buff: &mut String, value: &Date) {
266        let _ = write!(
267            buff,
268            "{:04}-{:02}-{:02}",
269            value.year(),
270            value.month() as u8,
271            value.day()
272        );
273    }
274
275    fn write_value_time(&self, _context: &mut Context, buff: &mut String, value: &Time) {
276        let mut subsecond = value.nanosecond();
277        let mut width = 9;
278        while width > 1 && subsecond % 10 == 0 {
279            subsecond /= 10;
280            width -= 1;
281        }
282        let _ = write!(
283            buff,
284            "{:02}:{:02}:{:02}.{:0width$}",
285            value.hour(),
286            value.minute(),
287            value.second(),
288            subsecond
289        );
290    }
291
292    fn value_interval_units(&self) -> &[(&str, i128)] {
293        static UNITS: &[(&str, i128)] = &[
294            ("DAY", Interval::NANOS_IN_DAY),
295            ("HOUR", Interval::NANOS_IN_SEC * 3600),
296            ("MINUTE", Interval::NANOS_IN_SEC * 60),
297            ("SECOND", Interval::NANOS_IN_SEC),
298            ("MICROSECOND", 1_000),
299            ("NANOSECOND", 1),
300        ];
301        UNITS
302    }
303
304    fn write_value_interval(&self, _context: &mut Context, buff: &mut String, value: &Interval) {
305        buff.push_str("INTERVAL ");
306        if value.is_zero() {
307            buff.push_str("0 SECONDS");
308            return;
309        }
310        macro_rules! write_unit {
311            ($buff:ident, $val:expr, $unit:expr) => {
312                let _ = write!(
313                    $buff,
314                    "{} {}{}",
315                    $val,
316                    $unit,
317                    if $val != 1 { "S" } else { "" }
318                );
319            };
320        }
321        let months = value.months;
322        let nanos = value.nanos + value.days as i128 * Interval::NANOS_IN_DAY;
323        let multiple_units = nanos != 0 && value.months != 0;
324        if multiple_units {
325            buff.push('\'');
326        }
327        if months != 0 {
328            if months % 12 == 0 {
329                write_unit!(buff, months / 12, "YEAR");
330            } else {
331                write_unit!(buff, months, "MONTH");
332            }
333        }
334        for &(name, factor) in self.value_interval_units() {
335            if nanos % factor == 0 {
336                let value = nanos / factor;
337                if value != 0 {
338                    if months != 0 {
339                        buff.push(' ');
340                    }
341                    write_unit!(buff, value, name);
342                    break;
343                }
344            }
345        }
346        if multiple_units {
347            buff.push('\'');
348        }
349    }
350
351    fn write_value_list<'a>(
352        &self,
353        context: &mut Context,
354        buff: &mut String,
355        value: Either<&Box<[Value]>, &Vec<Value>>,
356        _ty: &Value,
357    ) {
358        buff.push('[');
359        separated_by(
360            buff,
361            match value {
362                Either::Left(v) => v.iter(),
363                Either::Right(v) => v.iter(),
364            },
365            |buff, v| {
366                self.write_value(context, buff, v);
367            },
368            ",",
369        );
370        buff.push(']');
371    }
372
373    fn write_value_map(
374        &self,
375        context: &mut Context,
376        buff: &mut String,
377        value: &HashMap<Value, Value>,
378    ) {
379        buff.push('{');
380        separated_by(
381            buff,
382            value,
383            |buff, (k, v)| {
384                self.write_value(context, buff, k);
385                buff.push(':');
386                self.write_value(context, buff, v);
387            },
388            ",",
389        );
390        buff.push('}');
391    }
392
393    fn expression_unary_op_precedence<'a>(&self, value: &UnaryOpType) -> i32 {
394        match value {
395            UnaryOpType::Negative => 1250,
396            UnaryOpType::Not => 250,
397        }
398    }
399
400    fn expression_binary_op_precedence<'a>(&self, value: &BinaryOpType) -> i32 {
401        match value {
402            BinaryOpType::Or => 100,
403            BinaryOpType::And => 200,
404            BinaryOpType::Equal => 300,
405            BinaryOpType::NotEqual => 300,
406            BinaryOpType::Less => 300,
407            BinaryOpType::Greater => 300,
408            BinaryOpType::LessEqual => 300,
409            BinaryOpType::GreaterEqual => 300,
410            BinaryOpType::Is => 400,
411            BinaryOpType::IsNot => 400,
412            BinaryOpType::Like => 400,
413            BinaryOpType::NotLike => 400,
414            BinaryOpType::Regexp => 400,
415            BinaryOpType::NotRegexp => 400,
416            BinaryOpType::Glob => 400,
417            BinaryOpType::NotGlob => 400,
418            BinaryOpType::BitwiseOr => 500,
419            BinaryOpType::BitwiseAnd => 600,
420            BinaryOpType::ShiftLeft => 700,
421            BinaryOpType::ShiftRight => 700,
422            BinaryOpType::Subtraction => 800,
423            BinaryOpType::Addition => 800,
424            BinaryOpType::Multiplication => 900,
425            BinaryOpType::Division => 900,
426            BinaryOpType::Remainder => 900,
427            BinaryOpType::Indexing => 1000,
428            BinaryOpType::Cast => 1100,
429            BinaryOpType::Alias => 1200,
430        }
431    }
432
433    fn write_expression_operand(&self, context: &mut Context, buff: &mut String, value: &Operand) {
434        match value {
435            Operand::LitBool(v) => self.write_value_bool(context, buff, *v),
436            Operand::LitFloat(v) => write_float!(self, context, buff, *v),
437            Operand::LitIdent(v) => drop(buff.push_str(v)),
438            Operand::LitField(v) => separated_by(buff, *v, |buff, v| buff.push_str(v), "."),
439            Operand::LitInt(v) => write_integer!(buff, *v),
440            Operand::LitStr(v) => self.write_value_string(context, buff, v),
441            Operand::LitArray(v) => {
442                buff.push('[');
443                separated_by(
444                    buff,
445                    *v,
446                    |buff, v| {
447                        v.write_query(self.as_dyn(), context, buff);
448                    },
449                    ", ",
450                );
451                buff.push(']');
452            }
453            Operand::Null => drop(buff.push_str("NULL")),
454            Operand::Type(v) => self.write_column_type(context, buff, v),
455            Operand::Variable(v) => self.write_value(context, buff, v),
456            Operand::Call(f, args) => {
457                buff.push_str(f);
458                buff.push('(');
459                separated_by(
460                    buff,
461                    *args,
462                    |buff, v| {
463                        v.write_query(self.as_dyn(), context, buff);
464                    },
465                    ",",
466                );
467                buff.push(')');
468            }
469            Operand::Asterisk => drop(buff.push('*')),
470            Operand::QuestionMark => self.write_expression_operand_question_mark(context, buff),
471        };
472    }
473
474    fn write_expression_operand_question_mark(&self, _context: &mut Context, buff: &mut String) {
475        buff.push('?');
476    }
477
478    fn write_expression_unary_op(
479        &self,
480        context: &mut Context,
481        buff: &mut String,
482        value: &UnaryOp<&dyn Expression>,
483    ) {
484        match value.op {
485            UnaryOpType::Negative => buff.push('-'),
486            UnaryOpType::Not => buff.push_str("NOT "),
487        };
488        possibly_parenthesized!(
489            buff,
490            value.arg.precedence(self.as_dyn()) <= self.expression_unary_op_precedence(&value.op),
491            value.arg.write_query(self.as_dyn(), context, buff)
492        );
493    }
494
495    fn write_expression_binary_op(
496        &self,
497        context: &mut Context,
498        buff: &mut String,
499        value: &BinaryOp<&dyn Expression, &dyn Expression>,
500    ) {
501        let (prefix, infix, suffix, lhs_parenthesized, rhs_parenthesized) = match value.op {
502            BinaryOpType::Indexing => ("", "[", "]", false, true),
503            BinaryOpType::Cast => ("CAST(", " AS ", ")", true, true),
504            BinaryOpType::Multiplication => ("", " * ", "", false, false),
505            BinaryOpType::Division => ("", " / ", "", false, false),
506            BinaryOpType::Remainder => ("", " % ", "", false, false),
507            BinaryOpType::Addition => ("", " + ", "", false, false),
508            BinaryOpType::Subtraction => ("", " - ", "", false, false),
509            BinaryOpType::ShiftLeft => ("", " << ", "", false, false),
510            BinaryOpType::ShiftRight => ("", " >> ", "", false, false),
511            BinaryOpType::BitwiseAnd => ("", " & ", "", false, false),
512            BinaryOpType::BitwiseOr => ("", " | ", "", false, false),
513            BinaryOpType::Is => ("", " Is ", "", false, false),
514            BinaryOpType::IsNot => ("", " IS NOT ", "", false, false),
515            BinaryOpType::Like => ("", " LIKE ", "", false, false),
516            BinaryOpType::NotLike => ("", " NOT LIKE ", "", false, false),
517            BinaryOpType::Regexp => ("", " REGEXP ", "", false, false),
518            BinaryOpType::NotRegexp => ("", " NOT REGEXP ", "", false, false),
519            BinaryOpType::Glob => ("", " GLOB ", "", false, false),
520            BinaryOpType::NotGlob => ("", " NOT GLOB ", "", false, false),
521            BinaryOpType::Equal => ("", " = ", "", false, false),
522            BinaryOpType::NotEqual => ("", " != ", "", false, false),
523            BinaryOpType::Less => ("", " < ", "", false, false),
524            BinaryOpType::LessEqual => ("", " <= ", "", false, false),
525            BinaryOpType::Greater => ("", " > ", "", false, false),
526            BinaryOpType::GreaterEqual => ("", " >= ", "", false, false),
527            BinaryOpType::And => ("", " AND ", "", false, false),
528            BinaryOpType::Or => ("", " OR ", "", false, false),
529            BinaryOpType::Alias => ("", " AS ", "", false, false),
530        };
531        let precedence = self.expression_binary_op_precedence(&value.op);
532        buff.push_str(prefix);
533        possibly_parenthesized!(
534            buff,
535            !lhs_parenthesized && value.lhs.precedence(self.as_dyn()) < precedence,
536            value.lhs.write_query(self.as_dyn(), context, buff)
537        );
538        buff.push_str(infix);
539        possibly_parenthesized!(
540            buff,
541            !rhs_parenthesized && value.rhs.precedence(self.as_dyn()) <= precedence,
542            value.rhs.write_query(self.as_dyn(), context, buff)
543        );
544        buff.push_str(suffix);
545    }
546
547    fn write_expression_ordered(
548        &self,
549        context: &mut Context,
550        buff: &mut String,
551        value: &Ordered<&dyn Expression>,
552    ) {
553        value.expression.write_query(self.as_dyn(), context, buff);
554        if context.fragment == Fragment::SqlSelectOrderBy {
555            let _ = write!(
556                buff,
557                " {}",
558                match value.order {
559                    Order::ASC => "ASC",
560                    Order::DESC => "DESC",
561                }
562            );
563        }
564    }
565
566    fn write_join_type(&self, _context: &mut Context, buff: &mut String, join_type: &JoinType) {
567        buff.push_str(match &join_type {
568            JoinType::Default => "JOIN",
569            JoinType::Inner => "INNER JOIN",
570            JoinType::Outer => "OUTER JOIN",
571            JoinType::Left => "LEFT JOIN",
572            JoinType::Right => "RIGHT JOIN",
573            JoinType::Cross => "CROSS",
574            JoinType::Natural => "NATURAL JOIN",
575        });
576    }
577
578    fn write_join(
579        &self,
580        context: &mut Context,
581        buff: &mut String,
582        join: &Join<&dyn DataSet, &dyn DataSet, &dyn Expression>,
583    ) {
584        let mut context = context.switch_fragment(Fragment::SqlJoin);
585        context.current.qualify_columns = true;
586        join.lhs
587            .write_query(self.as_dyn(), &mut context.current, buff);
588        buff.push(' ');
589        self.write_join_type(&mut context.current, buff, &join.join);
590        buff.push(' ');
591        join.rhs
592            .write_query(self.as_dyn(), &mut context.current, buff);
593        if let Some(on) = &join.on {
594            buff.push_str(" ON ");
595            on.write_query(self.as_dyn(), &mut context.current, buff);
596        }
597    }
598
599    fn write_transaction_begin(&self, buff: &mut String) {
600        buff.push_str("BEGIN;");
601    }
602
603    fn write_transaction_commit(&self, buff: &mut String) {
604        buff.push_str("COMMIT;");
605    }
606
607    fn write_transaction_rollback(&self, buff: &mut String) {
608        buff.push_str("ROLLBACK;");
609    }
610
611    fn write_create_schema<E>(&self, buff: &mut String, if_not_exists: bool)
612    where
613        Self: Sized,
614        E: Entity,
615    {
616        buff.push_str("CREATE SCHEMA ");
617        let mut context = Context::new(Fragment::SqlCreateSchema, E::qualified_columns());
618        if if_not_exists {
619            buff.push_str("IF NOT EXISTS ");
620        }
621        self.write_identifier_quoted(&mut context, buff, E::table_ref().schema);
622        buff.push(';');
623    }
624
625    fn write_drop_schema<E>(&self, buff: &mut String, if_exists: bool)
626    where
627        Self: Sized,
628        E: Entity,
629    {
630        buff.push_str("DROP SCHEMA ");
631        let mut context = Context::new(Fragment::SqlDropSchema, E::qualified_columns());
632        if if_exists {
633            buff.push_str("IF EXISTS ");
634        }
635        self.write_identifier_quoted(&mut context, buff, E::table_ref().schema);
636        buff.push(';');
637    }
638
639    fn write_create_table<E>(&self, buff: &mut String, if_not_exists: bool)
640    where
641        Self: Sized,
642        E: Entity,
643    {
644        let mut context = Context::new(Fragment::SqlCreateTable, E::qualified_columns());
645        buff.push_str("CREATE TABLE ");
646        if if_not_exists {
647            buff.push_str("IF NOT EXISTS ");
648        }
649        self.write_table_ref(&mut context, buff, E::table_ref());
650        buff.push_str(" (\n");
651        separated_by(
652            buff,
653            E::columns(),
654            |buff, v| {
655                self.write_create_table_column_fragment(&mut context, buff, v);
656            },
657            ",\n",
658        );
659        let primary_key = E::primary_key_def();
660        if primary_key.len() > 1 {
661            buff.push_str(",\nPRIMARY KEY (");
662            separated_by(
663                buff,
664                primary_key,
665                |buff, v| {
666                    self.write_identifier_quoted(
667                        &mut context
668                            .switch_fragment(Fragment::SqlCreateTablePrimaryKey)
669                            .current,
670                        buff,
671                        v.name(),
672                    );
673                },
674                ", ",
675            );
676            buff.push(')');
677        }
678        for unique in E::unique_defs() {
679            if unique.len() > 1 {
680                buff.push_str(",\nUNIQUE (");
681                separated_by(
682                    buff,
683                    unique,
684                    |buff, v| {
685                        self.write_identifier_quoted(
686                            &mut context
687                                .switch_fragment(Fragment::SqlCreateTableUnique)
688                                .current,
689                            buff,
690                            v.name(),
691                        );
692                    },
693                    ", ",
694                );
695                buff.push(')');
696            }
697        }
698        buff.push_str(");");
699        self.write_column_comments::<E>(&mut context, buff);
700    }
701
702    fn write_column_comments<E>(&self, context: &mut Context, buff: &mut String)
703    where
704        Self: Sized,
705        E: Entity,
706    {
707        let mut context = context.switch_fragment(Fragment::SqlCommentOnColumn);
708        context.current.qualify_columns = true;
709        for c in E::columns().iter().filter(|c| !c.comment.is_empty()) {
710            buff.push_str("\nCOMMENT ON COLUMN ");
711            self.write_column_ref(&mut context.current, buff, c.into());
712            buff.push_str(" IS ");
713            self.write_value_string(&mut context.current, buff, c.comment);
714            buff.push(';');
715        }
716    }
717
718    fn write_create_table_column_fragment(
719        &self,
720        context: &mut Context,
721        buff: &mut String,
722        column: &ColumnDef,
723    ) where
724        Self: Sized,
725    {
726        self.write_identifier_quoted(context, buff, &column.name());
727        buff.push(' ');
728        if !column.column_type.is_empty() {
729            buff.push_str(&column.column_type);
730        } else {
731            SqlWriter::write_column_type(self, context, buff, &column.value);
732        }
733        if !column.nullable && column.primary_key == PrimaryKeyType::None {
734            buff.push_str(" NOT NULL");
735        }
736        if let Some(default) = &column.default {
737            buff.push_str(" DEFAULT ");
738            default.write_query(self.as_dyn(), context, buff);
739        }
740        if column.primary_key == PrimaryKeyType::PrimaryKey {
741            // Composite primary key will be printed elsewhere
742            buff.push_str(" PRIMARY KEY");
743        }
744        if column.unique && column.primary_key != PrimaryKeyType::PrimaryKey {
745            buff.push_str(" UNIQUE");
746        }
747        if let Some(references) = column.references {
748            buff.push_str(" REFERENCES ");
749            self.write_table_ref(context, buff, &references.table_ref());
750            buff.push('(');
751            self.write_column_ref(context, buff, &references);
752            buff.push(')');
753            if let Some(on_delete) = &column.on_delete {
754                buff.push_str(" ON DELETE ");
755                self.write_create_table_references_action(context, buff, on_delete);
756            }
757            if let Some(on_update) = &column.on_update {
758                buff.push_str(" ON UPDATE ");
759                self.write_create_table_references_action(context, buff, on_update);
760            }
761        }
762    }
763
764    fn write_create_table_references_action(
765        &self,
766        _context: &mut Context,
767        buff: &mut String,
768        action: &Action,
769    ) {
770        buff.push_str(match action {
771            Action::NoAction => "NO ACTION",
772            Action::Restrict => "RESTRICT",
773            Action::Cascade => "CASCADE",
774            Action::SetNull => "SET NULL",
775            Action::SetDefault => "SET DEFAULT",
776        });
777    }
778
779    fn write_drop_table<E>(&self, buff: &mut String, if_exists: bool)
780    where
781        Self: Sized,
782        E: Entity,
783    {
784        buff.push_str("DROP TABLE ");
785        let mut context = Context::new(Fragment::SqlDropTable, E::qualified_columns());
786        if if_exists {
787            buff.push_str("IF EXISTS ");
788        }
789        self.write_table_ref(&mut context, buff, E::table_ref());
790        buff.push(';');
791    }
792
793    fn write_select<Item, Cols, Data, Cond>(
794        &self,
795        buff: &mut String,
796        columns: Cols,
797        from: &Data,
798        condition: &Cond,
799        limit: Option<u32>,
800    ) where
801        Self: Sized,
802        Item: Expression,
803        Cols: IntoIterator<Item = Item> + Clone,
804        Data: DataSet,
805        Cond: Expression,
806    {
807        buff.push_str("SELECT ");
808        let mut has_order_by = false;
809        let mut context = Context::new(Fragment::SqlSelect, Data::qualified_columns());
810        separated_by(
811            buff,
812            columns.clone(),
813            |buff, col| {
814                col.write_query(self, &mut context, buff);
815                has_order_by = has_order_by || col.is_ordered();
816            },
817            ", ",
818        );
819        buff.push_str("\nFROM ");
820        from.write_query(
821            self,
822            &mut context.switch_fragment(Fragment::SqlSelectFrom).current,
823            buff,
824        );
825        buff.push_str("\nWHERE ");
826        condition.write_query(
827            self,
828            &mut context.switch_fragment(Fragment::SqlSelectWhere).current,
829            buff,
830        );
831        if has_order_by {
832            buff.push_str("\nORDER BY ");
833            for col in columns.into_iter().filter(Expression::is_ordered) {
834                col.write_query(
835                    self,
836                    &mut context.switch_fragment(Fragment::SqlSelectOrderBy).current,
837                    buff,
838                );
839            }
840        }
841        if let Some(limit) = limit {
842            let _ = write!(buff, "\nLIMIT {}", limit);
843        }
844        buff.push(';');
845    }
846
847    fn write_insert<'b, E, It>(&self, buff: &mut String, entities: It, update: bool)
848    where
849        Self: Sized,
850        E: Entity + 'b,
851        It: IntoIterator<Item = &'b E>,
852    {
853        let mut rows = entities.into_iter().map(Entity::row_filtered).peekable();
854        let Some(mut row) = rows.next() else {
855            return;
856        };
857        buff.push_str("INSERT INTO ");
858        let mut context = Context::new(Fragment::SqlInsertInto, E::qualified_columns());
859        self.write_table_ref(&mut context, buff, E::table_ref());
860        buff.push_str(" (");
861        let columns = E::columns().iter();
862        let single = rows.peek().is_none();
863        if single {
864            // Inserting a single row uses row_labeled to filter buff Passive::NotSet columns
865            separated_by(
866                buff,
867                row.iter(),
868                |buff, v| {
869                    self.write_identifier_quoted(&mut context, buff, v.0);
870                },
871                ", ",
872            );
873        } else {
874            // Inserting more rows will list all columns, Passive::NotSet columns will result in DEFAULT value
875            separated_by(
876                buff,
877                columns.clone(),
878                |buff, v| {
879                    self.write_identifier_quoted(&mut context, buff, v.name());
880                },
881                ", ",
882            );
883        };
884        buff.push_str(") VALUES\n");
885        let mut context = context.switch_fragment(Fragment::SqlInsertIntoValues);
886        let mut first_row = None;
887        let mut separate = false;
888        loop {
889            if separate {
890                buff.push_str(",\n");
891            }
892            buff.push('(');
893            let mut fields = row.iter();
894            let mut field = fields.next();
895            separated_by(
896                buff,
897                E::columns(),
898                |buff, col| {
899                    if Some(col.name()) == field.map(|v| v.0) {
900                        self.write_value(
901                            &mut context.current,
902                            buff,
903                            field
904                                .map(|v| &v.1)
905                                .expect(&format!("Column {} does not have a value", col.name())),
906                        );
907                        field = fields.next();
908                    } else if !single {
909                        buff.push_str("DEFAULT");
910                    }
911                },
912                ", ",
913            );
914            buff.push(')');
915            separate = true;
916            if first_row.is_none() {
917                first_row = row.into();
918            }
919            if let Some(next) = rows.next() {
920                row = next;
921            } else {
922                break;
923            };
924        }
925        let first_row = first_row
926            .expect("Should have at least one row")
927            .into_iter()
928            .map(|(v, _)| v);
929        if update {
930            self.write_insert_update_fragment::<E, _>(
931                &mut context.current,
932                buff,
933                if single {
934                    EitherIterator::Left(
935                        // If there is only one row to insert then list only the columns that appear
936                        columns.filter(|c| first_row.clone().find(|n| *n == c.name()).is_some()),
937                    )
938                } else {
939                    EitherIterator::Right(columns)
940                },
941            );
942        }
943        buff.push(';');
944    }
945
946    fn write_insert_update_fragment<'a, E, It>(
947        &self,
948        context: &mut Context,
949        buff: &mut String,
950        columns: It,
951    ) where
952        Self: Sized,
953        E: Entity,
954        It: Iterator<Item = &'a ColumnDef>,
955    {
956        let pk = E::primary_key_def();
957        if pk.len() == 0 {
958            return;
959        }
960        buff.push_str("\nON CONFLICT");
961        context.fragment = Fragment::SqlInsertIntoOnConflict;
962        if pk.len() > 0 {
963            buff.push_str(" (");
964            separated_by(
965                buff,
966                pk,
967                |buff, v| {
968                    self.write_identifier_quoted(context, buff, v.name());
969                },
970                ", ",
971            );
972            buff.push(')');
973        }
974        buff.push_str(" DO UPDATE SET\n");
975        separated_by(
976            buff,
977            columns.filter(|c| c.primary_key == PrimaryKeyType::None),
978            |buff, v| {
979                self.write_identifier_quoted(context, buff, v.name());
980                buff.push_str(" = EXCLUDED.");
981                self.write_identifier_quoted(context, buff, v.name());
982            },
983            ",\n",
984        );
985    }
986
987    fn write_delete<E, Expr>(&self, buff: &mut String, condition: &Expr)
988    where
989        Self: Sized,
990        E: Entity,
991        Expr: Expression,
992    {
993        buff.push_str("DELETE FROM ");
994        let mut context = Context::new(Fragment::SqlDeleteFrom, E::qualified_columns());
995        self.write_table_ref(&mut context, buff, E::table_ref());
996        buff.push_str("\nWHERE ");
997        condition.write_query(
998            self,
999            &mut context
1000                .switch_fragment(Fragment::SqlDeleteFromWhere)
1001                .current,
1002            buff,
1003        );
1004        buff.push(';');
1005    }
1006}
1007
1008pub struct GenericSqlWriter;
1009impl GenericSqlWriter {
1010    pub fn new() -> Self {
1011        Self {}
1012    }
1013}
1014impl SqlWriter for GenericSqlWriter {
1015    fn as_dyn(&self) -> &dyn SqlWriter {
1016        self
1017    }
1018}