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