1use itertools::Itertools;
13use mz_sql_parser::ast::display::AstDisplay;
14use mz_sql_parser::ast::*;
15use pretty::{Doc, RcDoc};
16
17use crate::util::{
18 bracket, bracket_doc, comma_separate, comma_separated, intersperse_line_nest, nest,
19 nest_comma_separate, nest_title, title_comma_separate,
20};
21use crate::{Pretty, TAB};
22
23impl Pretty {
24 pub(crate) fn doc_display<'a, T: AstDisplay>(&self, v: &T, _debug: &str) -> RcDoc<'a, ()> {
26 #[cfg(test)]
27 eprintln!(
28 "UNKNOWN PRETTY TYPE in {}: {}, {}",
29 _debug,
30 std::any::type_name::<T>(),
31 v.to_ast_string_simple()
32 );
33 self.doc_display_pass(v)
34 }
35
36 fn doc_display_pass<'a, T: AstDisplay>(&self, v: &T) -> RcDoc<'a, ()> {
38 RcDoc::text(v.to_ast_string(self.config.format_mode))
39 }
40
41 pub(crate) fn doc_create_source<'a, T: AstInfo>(
42 &'a self,
43 v: &'a CreateSourceStatement<T>,
44 ) -> RcDoc<'a> {
45 let mut docs = Vec::new();
46 let title = format!(
47 "CREATE SOURCE{}",
48 if v.if_not_exists {
49 " IF NOT EXISTS"
50 } else {
51 ""
52 }
53 );
54 let mut doc = self.doc_display_pass(&v.name);
55 let mut names = Vec::new();
56 names.extend(v.col_names.iter().map(|name| self.doc_display_pass(name)));
57 names.extend(v.key_constraint.iter().map(|kc| self.doc_display_pass(kc)));
58 if !names.is_empty() {
59 doc = nest(doc, bracket("(", comma_separated(names), ")"));
60 }
61 docs.push(nest_title(title, doc));
62 if let Some(cluster) = &v.in_cluster {
63 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
64 }
65 docs.push(nest_title("FROM", self.doc_display_pass(&v.connection)));
66 if let Some(format) = &v.format {
67 docs.push(self.doc_format_specifier(format));
68 }
69 if !v.include_metadata.is_empty() {
70 docs.push(nest_title(
71 "INCLUDE",
72 comma_separate(|im| self.doc_display_pass(im), &v.include_metadata),
73 ));
74 }
75 if let Some(envelope) = &v.envelope {
76 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
77 }
78 if let Some(references) = &v.external_references {
79 docs.push(self.doc_external_references(references));
80 }
81 if let Some(progress) = &v.progress_subsource {
82 docs.push(nest_title(
83 "EXPOSE PROGRESS AS",
84 self.doc_display_pass(progress),
85 ));
86 }
87 if !v.with_options.is_empty() {
88 docs.push(bracket(
89 "WITH (",
90 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
91 ")",
92 ));
93 }
94 RcDoc::intersperse(docs, Doc::line()).group()
95 }
96
97 fn doc_format_specifier<T: AstInfo>(&self, v: &FormatSpecifier<T>) -> RcDoc<'_> {
98 match v {
99 FormatSpecifier::Bare(format) => nest_title("FORMAT", self.doc_display_pass(format)),
100 FormatSpecifier::KeyValue { key, value } => {
101 let docs = vec![
102 nest_title("KEY FORMAT", self.doc_display_pass(key)),
103 nest_title("VALUE FORMAT", self.doc_display_pass(value)),
104 ];
105 RcDoc::intersperse(docs, Doc::line()).group()
106 }
107 }
108 }
109
110 fn doc_external_references<'a>(&'a self, v: &'a ExternalReferences) -> RcDoc<'a> {
111 match v {
112 ExternalReferences::SubsetTables(subsources) => bracket(
113 "FOR TABLES (",
114 comma_separate(|s| self.doc_display_pass(s), subsources),
115 ")",
116 ),
117 ExternalReferences::SubsetSchemas(schemas) => bracket(
118 "FOR SCHEMAS (",
119 comma_separate(|s| self.doc_display_pass(s), schemas),
120 ")",
121 ),
122 ExternalReferences::All => RcDoc::text("FOR ALL TABLES"),
123 }
124 }
125
126 pub(crate) fn doc_copy<'a, T: AstInfo>(&'a self, v: &'a CopyStatement<T>) -> RcDoc<'a> {
127 let relation = match &v.relation {
128 CopyRelation::Named { name, columns } => {
129 let mut relation = self.doc_display_pass(name);
130 if !columns.is_empty() {
131 relation = bracket_doc(
132 nest(relation, RcDoc::text("(")),
133 comma_separate(|c| self.doc_display_pass(c), columns),
134 RcDoc::text(")"),
135 RcDoc::line_(),
136 );
137 }
138 RcDoc::concat([RcDoc::text("COPY "), relation])
139 }
140 CopyRelation::Select(query) => bracket("COPY (", self.doc_select_statement(query), ")"),
141 CopyRelation::Subscribe(query) => bracket("COPY (", self.doc_subscribe(query), ")"),
142 };
143 let mut docs = vec![
144 relation,
145 RcDoc::concat([
146 self.doc_display_pass(&v.direction),
147 RcDoc::text(" "),
148 self.doc_display_pass(&v.target),
149 ]),
150 ];
151 if !v.options.is_empty() {
152 docs.push(bracket(
153 "WITH (",
154 comma_separate(|o| self.doc_display_pass(o), &v.options),
155 ")",
156 ));
157 }
158 RcDoc::intersperse(docs, Doc::line()).group()
159 }
160
161 pub(crate) fn doc_subscribe<'a, T: AstInfo>(
162 &'a self,
163 v: &'a SubscribeStatement<T>,
164 ) -> RcDoc<'a> {
165 let doc = match &v.relation {
166 SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", self.doc_display_pass(name)),
167 SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", self.doc_query(query), ")"),
168 };
169 let mut docs = vec![doc];
170 if !v.options.is_empty() {
171 docs.push(bracket(
172 "WITH (",
173 comma_separate(|o| self.doc_display_pass(o), &v.options),
174 ")",
175 ));
176 }
177 if let Some(as_of) = &v.as_of {
178 docs.push(self.doc_as_of(as_of));
179 }
180 if let Some(up_to) = &v.up_to {
181 docs.push(nest_title("UP TO", self.doc_expr(up_to)));
182 }
183 match &v.output {
184 SubscribeOutput::Diffs => {}
185 SubscribeOutput::WithinTimestampOrderBy { order_by } => {
186 docs.push(nest_title(
187 "WITHIN TIMESTAMP ORDER BY ",
188 comma_separate(|o| self.doc_order_by_expr(o), order_by),
189 ));
190 }
191 SubscribeOutput::EnvelopeUpsert { key_columns } => {
192 docs.push(bracket(
193 "ENVELOPE UPSERT (KEY (",
194 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
195 "))",
196 ));
197 }
198 SubscribeOutput::EnvelopeDebezium { key_columns } => {
199 docs.push(bracket(
200 "ENVELOPE DEBEZIUM (KEY (",
201 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
202 "))",
203 ));
204 }
205 }
206 RcDoc::intersperse(docs, Doc::line()).group()
207 }
208
209 fn doc_as_of<'a, T: AstInfo>(&'a self, v: &'a AsOf<T>) -> RcDoc<'a> {
210 let (title, expr) = match v {
211 AsOf::At(expr) => ("AS OF", expr),
212 AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr),
213 };
214 nest_title(title, self.doc_expr(expr))
215 }
216
217 pub(crate) fn doc_create_view<'a, T: AstInfo>(
218 &'a self,
219 v: &'a CreateViewStatement<T>,
220 ) -> RcDoc<'a> {
221 let mut docs = vec![];
222 docs.push(RcDoc::text(format!(
223 "CREATE{}{} VIEW{}",
224 if v.if_exists == IfExistsBehavior::Replace {
225 " OR REPLACE"
226 } else {
227 ""
228 },
229 if v.temporary { " TEMPORARY" } else { "" },
230 if v.if_exists == IfExistsBehavior::Skip {
231 " IF NOT EXISTS"
232 } else {
233 ""
234 },
235 )));
236 docs.push(self.doc_view_definition(&v.definition));
237 intersperse_line_nest(docs)
238 }
239
240 pub(crate) fn doc_create_materialized_view<'a, T: AstInfo>(
241 &'a self,
242 v: &'a CreateMaterializedViewStatement<T>,
243 ) -> RcDoc<'a> {
244 let mut docs = vec![];
245 docs.push(RcDoc::text(format!(
246 "CREATE{} MATERIALIZED VIEW{} {}",
247 if v.if_exists == IfExistsBehavior::Replace {
248 " OR REPLACE"
249 } else {
250 ""
251 },
252 if v.if_exists == IfExistsBehavior::Skip {
253 " IF NOT EXISTS"
254 } else {
255 ""
256 },
257 v.name,
258 )));
259 if !v.columns.is_empty() {
260 docs.push(bracket(
261 "(",
262 comma_separate(|c| self.doc_display_pass(c), &v.columns),
263 ")",
264 ));
265 }
266 if let Some(target) = &v.replacing {
267 docs.push(RcDoc::text(format!(
268 "REPLACING {}",
269 target.to_ast_string_simple()
270 )));
271 }
272 if let Some(cluster) = &v.in_cluster {
273 docs.push(RcDoc::text(format!(
274 "IN CLUSTER {}",
275 cluster.to_ast_string_simple()
276 )));
277 }
278 if !v.with_options.is_empty() {
279 docs.push(bracket(
280 "WITH (",
281 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
282 ")",
283 ));
284 }
285 docs.push(nest_title("AS", self.doc_query(&v.query)));
286 intersperse_line_nest(docs)
287 }
288
289 fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition<T>) -> RcDoc<'a> {
290 let mut docs = vec![RcDoc::text(v.name.to_string())];
291 if !v.columns.is_empty() {
292 docs.push(bracket(
293 "(",
294 comma_separate(|c| self.doc_display_pass(c), &v.columns),
295 ")",
296 ));
297 }
298 docs.push(nest_title("AS", self.doc_query(&v.query)));
299 RcDoc::intersperse(docs, Doc::line()).group()
300 }
301
302 pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement<T>) -> RcDoc<'a> {
303 let mut first = vec![RcDoc::text(format!(
304 "INSERT INTO {}",
305 v.table_name.to_ast_string_simple()
306 ))];
307 if !v.columns.is_empty() {
308 first.push(bracket(
309 "(",
310 comma_separate(|c| self.doc_display_pass(c), &v.columns),
311 ")",
312 ));
313 }
314 let sources = match &v.source {
315 InsertSource::Query(query) => self.doc_query(query),
316 _ => self.doc_display(&v.source, "insert source"),
317 };
318 let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]);
319 if !v.returning.is_empty() {
320 doc = nest(
321 doc,
322 nest_title(
323 "RETURNING",
324 comma_separate(|r| self.doc_display_pass(r), &v.returning),
325 ),
326 )
327 }
328 doc
329 }
330
331 pub(crate) fn doc_select_statement<'a, T: AstInfo>(
332 &'a self,
333 v: &'a SelectStatement<T>,
334 ) -> RcDoc<'a> {
335 let mut doc = self.doc_query(&v.query);
336 if let Some(as_of) = &v.as_of {
337 doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]);
338 }
339 doc.group()
340 }
341
342 fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr<T>]) -> RcDoc<'a> {
343 title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v)
344 }
345
346 fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr<T>) -> RcDoc<'a> {
347 let doc = self.doc_expr(&v.expr);
348 let doc = match v.asc {
349 Some(true) => nest(doc, RcDoc::text("ASC")),
350 Some(false) => nest(doc, RcDoc::text("DESC")),
351 None => doc,
352 };
353 match v.nulls_last {
354 Some(true) => nest(doc, RcDoc::text("NULLS LAST")),
355 Some(false) => nest(doc, RcDoc::text("NULLS FIRST")),
356 None => doc,
357 }
358 }
359
360 fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query<T>) -> RcDoc<'a> {
361 let mut docs = vec![];
362 if !v.ctes.is_empty() {
363 match &v.ctes {
364 CteBlock::Simple(ctes) => {
365 docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes))
366 }
367 CteBlock::MutuallyRecursive(mutrec) => {
368 let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE");
369 if !mutrec.options.is_empty() {
370 doc = nest(
371 doc,
372 bracket(
373 "(",
374 comma_separate(|o| self.doc_display_pass(o), &mutrec.options),
375 ")",
376 ),
377 );
378 }
379 docs.push(nest(
380 doc,
381 comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes),
382 ));
383 }
384 }
385 }
386 docs.push(self.doc_set_expr(&v.body));
387 if !v.order_by.is_empty() {
388 docs.push(self.doc_order_by(&v.order_by));
389 }
390
391 let offset = if let Some(offset) = &v.offset {
392 vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])]
393 } else {
394 vec![]
395 };
396
397 if let Some(limit) = &v.limit {
398 if limit.with_ties {
399 docs.extend(offset);
400 docs.push(RcDoc::concat([
401 RcDoc::text("FETCH FIRST "),
402 self.doc_expr(&limit.quantity),
403 RcDoc::text(" ROWS WITH TIES"),
404 ]));
405 } else {
406 docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity)));
407 docs.extend(offset);
408 }
409 } else {
410 docs.extend(offset);
411 }
412
413 RcDoc::intersperse(docs, Doc::line()).group()
414 }
415
416 fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte<T>) -> RcDoc<'a> {
417 RcDoc::concat([
418 RcDoc::text(format!("{} AS", v.alias)),
419 RcDoc::line(),
420 bracket("(", self.doc_query(&v.query), ")"),
421 ])
422 }
423
424 fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec<T>) -> RcDoc<'a> {
425 let mut docs = Vec::new();
426 if !v.columns.is_empty() {
427 docs.push(bracket(
428 "(",
429 comma_separate(|c| self.doc_display_pass(c), &v.columns),
430 ")",
431 ));
432 }
433 docs.push(bracket("AS (", self.doc_query(&v.query), ")"));
434 nest(
435 self.doc_display_pass(&v.name),
436 RcDoc::intersperse(docs, Doc::line()).group(),
437 )
438 }
439
440 fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr<T>) -> RcDoc<'a> {
441 match v {
442 SetExpr::Select(v) => self.doc_select(v),
443 SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"),
444 SetExpr::SetOperation {
445 op,
446 all,
447 left,
448 right,
449 } => {
450 let all_str = if *all { " ALL" } else { "" };
451 RcDoc::concat([
452 self.doc_set_expr(left),
453 RcDoc::line(),
454 RcDoc::concat([
455 RcDoc::text(format!("{}{}", op, all_str)),
456 RcDoc::line(),
457 self.doc_set_expr(right),
458 ])
459 .nest(TAB)
460 .group(),
461 ])
462 }
463 SetExpr::Values(v) => self.doc_values(v),
464 SetExpr::Show(v) => self.doc_display(v, "SHOW"),
465 SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)),
466 }
467 .group()
468 }
469
470 fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values<T>) -> RcDoc<'a> {
471 let rows =
472 v.0.iter()
473 .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")"));
474 RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)])
475 .nest(TAB)
476 .group()
477 }
478
479 fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins<T>) -> RcDoc<'a> {
480 let mut docs = vec![self.doc_table_factor(&v.relation)];
481 for j in &v.joins {
482 docs.push(self.doc_join(j));
483 }
484 intersperse_line_nest(docs)
485 }
486
487 fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join<T>) -> RcDoc<'a> {
488 let (constraint, name) = match &v.join_operator {
489 JoinOperator::Inner(constraint) => (constraint, "JOIN"),
490 JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"),
491 JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"),
492 JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"),
493 _ => return self.doc_display(v, "join operator"),
494 };
495 let constraint = match constraint {
496 JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)),
497 JoinConstraint::Using { columns, alias } => {
498 let mut doc = bracket(
499 "USING(",
500 comma_separate(|c| self.doc_display_pass(c), columns),
501 ")",
502 );
503 if let Some(alias) = alias {
504 doc = nest(doc, nest_title("AS", self.doc_display_pass(alias)));
505 }
506 doc
507 }
508 _ => return self.doc_display(v, "join constraint"),
509 };
510 intersperse_line_nest([
511 RcDoc::text(name),
512 self.doc_table_factor(&v.relation),
513 constraint,
514 ])
515 }
516
517 fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor<T>) -> RcDoc<'a> {
518 match v {
519 TableFactor::Derived {
520 lateral,
521 subquery,
522 alias,
523 } => {
524 let prefix = if *lateral { "LATERAL (" } else { "(" };
525 let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")];
526 if let Some(alias) = alias {
527 docs.push(RcDoc::text(format!("AS {}", alias)));
528 }
529 intersperse_line_nest(docs)
530 }
531 TableFactor::NestedJoin { join, alias } => {
532 let mut doc = bracket("(", self.doc_table_with_joins(join), ")");
533 if let Some(alias) = alias {
534 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
535 }
536 doc
537 }
538 TableFactor::Table { name, alias } => {
539 let mut doc = self.doc_display_pass(name);
540 if let Some(alias) = alias {
541 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
542 }
543 doc
544 }
545 _ => self.doc_display(v, "table factor variant"),
546 }
547 }
548
549 fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct<T>) -> RcDoc<'a> {
550 match v {
551 Distinct::EntireRow => RcDoc::text("DISTINCT"),
552 Distinct::On(cols) => bracket(
553 "DISTINCT ON (",
554 comma_separate(|c| self.doc_expr(c), cols),
555 ")",
556 ),
557 }
558 }
559
560 fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select<T>) -> RcDoc<'a> {
561 let mut docs = vec![];
562 let mut select = RcDoc::text("SELECT");
563 if let Some(distinct) = &v.distinct {
564 select = nest(select, self.doc_distinct(distinct));
565 }
566 docs.push(nest_comma_separate(
567 select,
568 |s| self.doc_select_item(s),
569 &v.projection,
570 ));
571 if !v.from.is_empty() {
572 docs.push(title_comma_separate(
573 "FROM",
574 |t| self.doc_table_with_joins(t),
575 &v.from,
576 ));
577 }
578 if let Some(selection) = &v.selection {
579 docs.push(nest_title("WHERE", self.doc_expr(selection)));
580 }
581 if !v.group_by.is_empty() {
582 docs.push(title_comma_separate(
583 "GROUP BY",
584 |e| self.doc_expr(e),
585 &v.group_by,
586 ));
587 }
588 if let Some(having) = &v.having {
589 docs.push(nest_title("HAVING", self.doc_expr(having)));
590 }
591 if let Some(qualify) = &v.qualify {
592 docs.push(nest_title("QUALIFY", self.doc_expr(qualify)));
593 }
594 if !v.options.is_empty() {
595 docs.push(bracket(
596 "OPTIONS (",
597 comma_separate(|o| self.doc_display_pass(o), &v.options),
598 ")",
599 ));
600 }
601 RcDoc::intersperse(docs, Doc::line()).group()
602 }
603
604 fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem<T>) -> RcDoc<'a> {
605 match v {
606 SelectItem::Expr { expr, alias } => {
607 let mut doc = self.doc_expr(expr);
608 if let Some(alias) = alias {
609 doc = nest(
610 doc,
611 RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]),
612 );
613 }
614 doc
615 }
616 SelectItem::Wildcard => self.doc_display_pass(v),
617 }
618 }
619
620 pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr<T>) -> RcDoc<'a> {
621 match v {
622 Expr::Op { op, expr1, expr2 } => {
623 if let Some(expr2) = expr2 {
624 RcDoc::concat([
625 self.doc_expr(expr1),
626 RcDoc::line(),
627 RcDoc::text(format!("{} ", op)),
628 self.doc_expr(expr2).nest(TAB),
629 ])
630 } else {
631 RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)])
632 }
633 }
634 Expr::Case {
635 operand,
636 conditions,
637 results,
638 else_result,
639 } => {
640 let mut docs = Vec::new();
641 if let Some(operand) = operand {
642 docs.push(self.doc_expr(operand));
643 }
644 for (c, r) in conditions.iter().zip_eq(results) {
645 let when = nest_title("WHEN", self.doc_expr(c));
646 let then = nest_title("THEN", self.doc_expr(r));
647 docs.push(nest(when, then));
648 }
649 if let Some(else_result) = else_result {
650 docs.push(nest_title("ELSE", self.doc_expr(else_result)));
651 }
652 let doc = intersperse_line_nest(docs);
653 bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line())
654 }
655 Expr::Cast { expr, data_type } => {
656 let doc = self.doc_expr(expr);
657 RcDoc::concat([
658 doc,
659 RcDoc::text(format!("::{}", data_type.to_ast_string_simple())),
660 ])
661 }
662 Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"),
663 Expr::Function(fun) => self.doc_function(fun),
664 Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"),
665 Expr::Identifier(_)
666 | Expr::Value(_)
667 | Expr::QualifiedWildcard(_)
668 | Expr::WildcardAccess(_)
669 | Expr::FieldAccess { .. } => self.doc_display_pass(v),
670 Expr::And { left, right } => bracket_doc(
671 self.doc_expr(left),
672 RcDoc::text("AND"),
673 self.doc_expr(right),
674 RcDoc::line(),
675 ),
676 Expr::Or { left, right } => bracket_doc(
677 self.doc_expr(left),
678 RcDoc::text("OR"),
679 self.doc_expr(right),
680 RcDoc::line(),
681 ),
682 Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"),
683 Expr::IsExpr {
684 expr,
685 negated,
686 construct,
687 } => bracket_doc(
688 self.doc_expr(expr),
689 RcDoc::text(if *negated { "IS NOT" } else { "IS" }),
690 self.doc_display_pass(construct),
691 RcDoc::line(),
692 ),
693 Expr::Not { expr } => {
694 RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)])
695 }
696 Expr::Between {
697 expr,
698 negated,
699 low,
700 high,
701 } => RcDoc::intersperse(
702 [
703 self.doc_expr(expr),
704 RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }),
705 RcDoc::intersperse(
706 [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)],
707 RcDoc::line(),
708 )
709 .group(),
710 ],
711 RcDoc::line(),
712 ),
713 Expr::InSubquery {
714 expr,
715 subquery,
716 negated,
717 } => RcDoc::intersperse(
718 [
719 self.doc_expr(expr),
720 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
721 self.doc_query(subquery),
722 RcDoc::text(")"),
723 ],
724 RcDoc::line(),
725 ),
726 Expr::InList {
727 expr,
728 list,
729 negated,
730 } => RcDoc::intersperse(
731 [
732 self.doc_expr(expr),
733 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
734 comma_separate(|e| self.doc_expr(e), list),
735 RcDoc::text(")"),
736 ],
737 RcDoc::line(),
738 ),
739 Expr::Row { exprs } => {
740 bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")")
741 }
742 Expr::NullIf { l_expr, r_expr } => bracket(
743 "NULLIF (",
744 comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]),
745 ")",
746 ),
747 Expr::HomogenizingFunction { function, exprs } => bracket(
748 format!("{function}("),
749 comma_separate(|e| self.doc_expr(e), exprs),
750 ")",
751 ),
752 Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"),
753 Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"),
754 Expr::Array(exprs) => {
755 bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]")
756 }
757 Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"),
758 _ => self.doc_display(v, "expr variant"),
759 }
760 .group()
761 }
762
763 fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function<T>) -> RcDoc<'a> {
764 match &v.args {
765 FunctionArgs::Star => self.doc_display_pass(v),
766 FunctionArgs::Args { args, order_by } => {
767 if args.is_empty() {
768 return self.doc_display_pass(v);
770 }
771 if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() {
772 return self.doc_display(v, "function filter or over or order by");
773 }
774 let special = match v.name.to_ast_string_stable().as_str() {
775 r#""extract""# if v.args.len() == Some(2) => true,
776 r#""position""# if v.args.len() == Some(2) => true,
777 _ => false,
778 };
779 if special {
780 return self.doc_display(v, "special function");
781 }
782 let name = format!(
783 "{}({}",
784 v.name.to_ast_string_simple(),
785 if v.distinct { "DISTINCT " } else { "" }
786 );
787 bracket(name, comma_separate(|e| self.doc_expr(e), args), ")")
788 }
789 }
790 }
791}