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 pub(crate) fn doc_create_webhook_source<'a, T: AstInfo>(
98 &'a self,
99 v: &'a CreateWebhookSourceStatement<T>,
100 ) -> RcDoc<'a> {
101 let mut docs = Vec::new();
102
103 let mut title = "CREATE ".to_string();
104 if v.is_table {
105 title.push_str("TABLE");
106 } else {
107 title.push_str("SOURCE");
108 }
109 if v.if_not_exists {
110 title.push_str(" IF NOT EXISTS");
111 }
112 docs.push(nest_title(title, self.doc_display_pass(&v.name)));
113
114 if !v.is_table {
116 if let Some(cluster) = &v.in_cluster {
117 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
118 }
119 }
120
121 docs.push(RcDoc::text("FROM WEBHOOK"));
122 docs.push(nest_title(
123 "BODY FORMAT",
124 self.doc_display_pass(&v.body_format),
125 ));
126
127 if !v.include_headers.mappings.is_empty() || v.include_headers.column.is_some() {
128 let mut header_docs = Vec::new();
129
130 for mapping in &v.include_headers.mappings {
132 header_docs.push(self.doc_display_pass(mapping));
133 }
134
135 if let Some(filters) = &v.include_headers.column {
137 if filters.is_empty() {
138 header_docs.push(RcDoc::text("INCLUDE HEADERS"));
139 } else {
140 header_docs.push(bracket(
141 "INCLUDE HEADERS (",
142 comma_separate(|f| self.doc_display_pass(f), filters),
143 ")",
144 ));
145 }
146 }
147
148 if !header_docs.is_empty() {
149 docs.extend(header_docs);
150 }
151 }
152
153 if let Some(check) = &v.validate_using {
154 docs.push(self.doc_webhook_check(check));
155 }
156
157 RcDoc::intersperse(docs, Doc::line()).group()
158 }
159
160 fn doc_webhook_check<'a, T: AstInfo>(
161 &'a self,
162 v: &'a CreateWebhookSourceCheck<T>,
163 ) -> RcDoc<'a> {
164 let mut inner = Vec::new();
165
166 if let Some(options) = &v.options {
167 let mut with_items = Vec::new();
168
169 for header in &options.headers {
170 with_items.push(self.doc_display_pass(header));
171 }
172 for body in &options.bodies {
173 with_items.push(self.doc_display_pass(body));
174 }
175 for secret in &options.secrets {
176 with_items.push(self.doc_display_pass(secret));
177 }
178
179 if !with_items.is_empty() {
180 inner.push(bracket("WITH (", comma_separated(with_items), ")"));
181 inner.push(RcDoc::line());
182 }
183 }
184
185 inner.push(self.doc_display_pass(&v.using));
186
187 bracket_doc(
188 RcDoc::text("CHECK ("),
189 RcDoc::concat(inner),
190 RcDoc::text(")"),
191 RcDoc::line(),
192 )
193 }
194
195 pub(crate) fn doc_create_table<'a, T: AstInfo>(
196 &'a self,
197 v: &'a CreateTableStatement<T>,
198 ) -> RcDoc<'a> {
199 let mut docs = Vec::new();
200
201 let mut title = "CREATE ".to_string();
203 if v.temporary {
204 title.push_str("TEMPORARY ");
205 }
206 title.push_str("TABLE");
207 if v.if_not_exists {
208 title.push_str(" IF NOT EXISTS");
209 }
210
211 let mut col_items = Vec::new();
213 col_items.extend(v.columns.iter().map(|c| self.doc_display_pass(c)));
214 col_items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
215
216 let table_def = nest(
217 self.doc_display_pass(&v.name),
218 bracket("(", comma_separated(col_items), ")"),
219 );
220 docs.push(nest_title(title, table_def));
221
222 if !v.with_options.is_empty() {
224 docs.push(bracket(
225 "WITH (",
226 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
227 ")",
228 ));
229 }
230
231 RcDoc::intersperse(docs, Doc::line()).group()
232 }
233
234 pub(crate) fn doc_create_table_from_source<'a, T: AstInfo>(
235 &'a self,
236 v: &'a CreateTableFromSourceStatement<T>,
237 ) -> RcDoc<'a> {
238 let mut docs = Vec::new();
239
240 let mut title = "CREATE TABLE".to_string();
242 if v.if_not_exists {
243 title.push_str(" IF NOT EXISTS");
244 }
245
246 let mut table_def = self.doc_display_pass(&v.name);
247
248 let has_columns_or_constraints = match &v.columns {
249 TableFromSourceColumns::NotSpecified => false,
250 _ => true,
251 } || !v.constraints.is_empty();
252
253 if has_columns_or_constraints {
254 let mut items = Vec::new();
255
256 match &v.columns {
257 TableFromSourceColumns::NotSpecified => {}
258 TableFromSourceColumns::Named(cols) => {
259 items.extend(cols.iter().map(|c| self.doc_display_pass(c)));
260 }
261 TableFromSourceColumns::Defined(cols) => {
262 items.extend(cols.iter().map(|c| self.doc_display_pass(c)));
263 }
264 }
265
266 items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
267
268 if !items.is_empty() {
269 table_def = nest(table_def, bracket("(", comma_separated(items), ")"));
270 }
271 }
272
273 docs.push(nest_title(title, table_def));
274
275 let mut from_source = nest_title("FROM SOURCE", self.doc_display_pass(&v.source));
277 if let Some(reference) = &v.external_reference {
278 from_source = nest(
279 from_source,
280 bracket("(REFERENCE = ", self.doc_display_pass(reference), ")"),
281 );
282 }
283 docs.push(from_source);
284
285 if let Some(format) = &v.format {
286 docs.push(self.doc_format_specifier(format));
287 }
288
289 if !v.include_metadata.is_empty() {
290 docs.push(nest_title(
291 "INCLUDE",
292 comma_separate(|im| self.doc_display_pass(im), &v.include_metadata),
293 ));
294 }
295
296 if let Some(envelope) = &v.envelope {
297 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
298 }
299
300 if !v.with_options.is_empty() {
301 docs.push(bracket(
302 "WITH (",
303 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
304 ")",
305 ));
306 }
307
308 RcDoc::intersperse(docs, Doc::line()).group()
309 }
310
311 pub(crate) fn doc_create_connection<'a, T: AstInfo>(
312 &'a self,
313 v: &'a CreateConnectionStatement<T>,
314 ) -> RcDoc<'a> {
315 let mut docs = Vec::new();
316
317 let mut title = "CREATE CONNECTION".to_string();
318 if v.if_not_exists {
319 title.push_str(" IF NOT EXISTS");
320 }
321 docs.push(nest_title(title, self.doc_display_pass(&v.name)));
322
323 let connection_with_values = nest(
324 RcDoc::concat([
325 RcDoc::text("TO "),
326 self.doc_display_pass(&v.connection_type),
327 ]),
328 bracket(
329 "(",
330 comma_separate(|val| self.doc_display_pass(val), &v.values),
331 ")",
332 ),
333 );
334 docs.push(connection_with_values);
335
336 if !v.with_options.is_empty() {
337 docs.push(bracket(
338 "WITH (",
339 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
340 ")",
341 ));
342 }
343
344 RcDoc::intersperse(docs, Doc::line()).group()
345 }
346
347 pub(crate) fn doc_create_sink<'a, T: AstInfo>(
348 &'a self,
349 v: &'a CreateSinkStatement<T>,
350 ) -> RcDoc<'a> {
351 let mut docs = Vec::new();
352
353 let mut title = "CREATE SINK".to_string();
355 if v.if_not_exists {
356 title.push_str(" IF NOT EXISTS");
357 }
358
359 if let Some(name) = &v.name {
360 docs.push(nest_title(title, self.doc_display_pass(name)));
361 } else {
362 docs.push(RcDoc::text(title));
363 }
364
365 if let Some(cluster) = &v.in_cluster {
366 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
367 }
368
369 docs.push(nest_title("FROM", self.doc_display_pass(&v.from)));
370 docs.push(nest_title("INTO", self.doc_display_pass(&v.connection)));
371
372 if let Some(format) = &v.format {
373 docs.push(self.doc_format_specifier(format));
374 }
375
376 if let Some(envelope) = &v.envelope {
377 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
378 }
379
380 if let Some(mode) = &v.mode {
381 docs.push(nest_title("MODE", self.doc_display_pass(mode)));
382 }
383
384 if !v.with_options.is_empty() {
385 docs.push(bracket(
386 "WITH (",
387 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
388 ")",
389 ));
390 }
391
392 RcDoc::intersperse(docs, Doc::line()).group()
393 }
394
395 pub(crate) fn doc_create_subsource<'a, T: AstInfo>(
396 &'a self,
397 v: &'a CreateSubsourceStatement<T>,
398 ) -> RcDoc<'a> {
399 let mut docs = Vec::new();
400
401 let mut title = "CREATE SUBSOURCE".to_string();
403 if v.if_not_exists {
404 title.push_str(" IF NOT EXISTS");
405 }
406
407 let mut col_items = Vec::new();
409 col_items.extend(v.columns.iter().map(|c| self.doc_display_pass(c)));
410 col_items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
411
412 let table_def = nest(
413 self.doc_display_pass(&v.name),
414 bracket("(", comma_separated(col_items), ")"),
415 );
416 docs.push(nest_title(title, table_def));
417
418 if let Some(of_source) = &v.of_source {
420 docs.push(nest_title("OF SOURCE", self.doc_display_pass(of_source)));
421 }
422
423 if !v.with_options.is_empty() {
425 docs.push(bracket(
426 "WITH (",
427 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
428 ")",
429 ));
430 }
431
432 RcDoc::intersperse(docs, Doc::line()).group()
433 }
434
435 pub(crate) fn doc_create_cluster<'a, T: AstInfo>(
436 &'a self,
437 v: &'a CreateClusterStatement<T>,
438 ) -> RcDoc<'a> {
439 let mut docs = Vec::new();
440
441 docs.push(nest_title("CREATE CLUSTER", self.doc_display_pass(&v.name)));
443
444 if !v.options.is_empty() {
446 docs.push(bracket(
447 "(",
448 comma_separate(|o| self.doc_display_pass(o), &v.options),
449 ")",
450 ));
451 }
452
453 if !v.features.is_empty() {
455 docs.push(bracket(
456 "FEATURES (",
457 comma_separate(|f| self.doc_display_pass(f), &v.features),
458 ")",
459 ));
460 }
461
462 RcDoc::intersperse(docs, Doc::line()).group()
463 }
464
465 pub(crate) fn doc_create_cluster_replica<'a, T: AstInfo>(
466 &'a self,
467 v: &'a CreateClusterReplicaStatement<T>,
468 ) -> RcDoc<'a> {
469 let mut docs = Vec::new();
470
471 let replica_name = RcDoc::concat([
473 self.doc_display_pass(&v.of_cluster),
474 RcDoc::text("."),
475 self.doc_display_pass(&v.definition.name),
476 ]);
477 docs.push(nest_title("CREATE CLUSTER REPLICA", replica_name));
478
479 docs.push(bracket(
481 "(",
482 comma_separate(|o| self.doc_display_pass(o), &v.definition.options),
483 ")",
484 ));
485
486 RcDoc::intersperse(docs, Doc::line()).group()
487 }
488
489 pub(crate) fn doc_create_network_policy<'a, T: AstInfo>(
490 &'a self,
491 v: &'a CreateNetworkPolicyStatement<T>,
492 ) -> RcDoc<'a> {
493 let docs = vec![
494 nest_title("CREATE NETWORK POLICY", self.doc_display_pass(&v.name)),
496 bracket(
498 "(",
499 comma_separate(|o| self.doc_display_pass(o), &v.options),
500 ")",
501 ),
502 ];
503
504 RcDoc::intersperse(docs, Doc::line()).group()
505 }
506
507 pub(crate) fn doc_create_index<'a, T: AstInfo>(
508 &'a self,
509 v: &'a CreateIndexStatement<T>,
510 ) -> RcDoc<'a> {
511 let mut docs = Vec::new();
512
513 let mut title = "CREATE".to_string();
515 if v.key_parts.is_none() {
516 title.push_str(" DEFAULT");
517 }
518 title.push_str(" INDEX");
519 if v.if_not_exists {
520 title.push_str(" IF NOT EXISTS");
521 }
522
523 if let Some(name) = &v.name {
524 docs.push(nest_title(title, self.doc_display_pass(name)));
525 } else {
526 docs.push(RcDoc::text(title));
527 }
528
529 if let Some(cluster) = &v.in_cluster {
531 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
532 }
533
534 let on_clause = if let Some(key_parts) = &v.key_parts {
536 nest(
537 self.doc_display_pass(&v.on_name),
538 bracket(
539 "(",
540 comma_separate(|k| self.doc_display_pass(k), key_parts),
541 ")",
542 ),
543 )
544 } else {
545 self.doc_display_pass(&v.on_name)
546 };
547 docs.push(nest_title("ON", on_clause));
548
549 if !v.with_options.is_empty() {
551 docs.push(bracket(
552 "WITH (",
553 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
554 ")",
555 ));
556 }
557
558 RcDoc::intersperse(docs, Doc::line()).group()
559 }
560
561 fn doc_format_specifier<T: AstInfo>(&self, v: &FormatSpecifier<T>) -> RcDoc<'_> {
562 match v {
563 FormatSpecifier::Bare(format) => nest_title("FORMAT", self.doc_display_pass(format)),
564 FormatSpecifier::KeyValue { key, value } => {
565 let docs = vec![
566 nest_title("KEY FORMAT", self.doc_display_pass(key)),
567 nest_title("VALUE FORMAT", self.doc_display_pass(value)),
568 ];
569 RcDoc::intersperse(docs, Doc::line()).group()
570 }
571 }
572 }
573
574 fn doc_external_references<'a>(&'a self, v: &'a ExternalReferences) -> RcDoc<'a> {
575 match v {
576 ExternalReferences::SubsetTables(subsources) => bracket(
577 "FOR TABLES (",
578 comma_separate(|s| self.doc_display_pass(s), subsources),
579 ")",
580 ),
581 ExternalReferences::SubsetSchemas(schemas) => bracket(
582 "FOR SCHEMAS (",
583 comma_separate(|s| self.doc_display_pass(s), schemas),
584 ")",
585 ),
586 ExternalReferences::All => RcDoc::text("FOR ALL TABLES"),
587 }
588 }
589
590 pub(crate) fn doc_copy<'a, T: AstInfo>(&'a self, v: &'a CopyStatement<T>) -> RcDoc<'a> {
591 let relation = match &v.relation {
592 CopyRelation::Named { name, columns } => {
593 let mut relation = self.doc_display_pass(name);
594 if !columns.is_empty() {
595 relation = bracket_doc(
596 nest(relation, RcDoc::text("(")),
597 comma_separate(|c| self.doc_display_pass(c), columns),
598 RcDoc::text(")"),
599 RcDoc::line_(),
600 );
601 }
602 RcDoc::concat([RcDoc::text("COPY "), relation])
603 }
604 CopyRelation::Select(query) => bracket("COPY (", self.doc_select_statement(query), ")"),
605 CopyRelation::Subscribe(query) => bracket("COPY (", self.doc_subscribe(query), ")"),
606 };
607 let mut docs = vec![
608 relation,
609 RcDoc::concat([
610 self.doc_display_pass(&v.direction),
611 RcDoc::text(" "),
612 self.doc_display_pass(&v.target),
613 ]),
614 ];
615 if !v.options.is_empty() {
616 docs.push(bracket(
617 "WITH (",
618 comma_separate(|o| self.doc_display_pass(o), &v.options),
619 ")",
620 ));
621 }
622 RcDoc::intersperse(docs, Doc::line()).group()
623 }
624
625 pub(crate) fn doc_subscribe<'a, T: AstInfo>(
626 &'a self,
627 v: &'a SubscribeStatement<T>,
628 ) -> RcDoc<'a> {
629 let doc = match &v.relation {
630 SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", self.doc_display_pass(name)),
631 SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", self.doc_query(query), ")"),
632 };
633 let mut docs = vec![doc];
634 if !v.options.is_empty() {
635 docs.push(bracket(
636 "WITH (",
637 comma_separate(|o| self.doc_display_pass(o), &v.options),
638 ")",
639 ));
640 }
641 if let Some(as_of) = &v.as_of {
642 docs.push(self.doc_as_of(as_of));
643 }
644 if let Some(up_to) = &v.up_to {
645 docs.push(nest_title("UP TO", self.doc_expr(up_to)));
646 }
647 match &v.output {
648 SubscribeOutput::Diffs => {}
649 SubscribeOutput::WithinTimestampOrderBy { order_by } => {
650 docs.push(nest_title(
651 "WITHIN TIMESTAMP ORDER BY ",
652 comma_separate(|o| self.doc_order_by_expr(o), order_by),
653 ));
654 }
655 SubscribeOutput::EnvelopeUpsert { key_columns } => {
656 docs.push(bracket(
657 "ENVELOPE UPSERT (KEY (",
658 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
659 "))",
660 ));
661 }
662 SubscribeOutput::EnvelopeDebezium { key_columns } => {
663 docs.push(bracket(
664 "ENVELOPE DEBEZIUM (KEY (",
665 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
666 "))",
667 ));
668 }
669 }
670 RcDoc::intersperse(docs, Doc::line()).group()
671 }
672
673 fn doc_as_of<'a, T: AstInfo>(&'a self, v: &'a AsOf<T>) -> RcDoc<'a> {
674 let (title, expr) = match v {
675 AsOf::At(expr) => ("AS OF", expr),
676 AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr),
677 };
678 nest_title(title, self.doc_expr(expr))
679 }
680
681 pub(crate) fn doc_create_view<'a, T: AstInfo>(
682 &'a self,
683 v: &'a CreateViewStatement<T>,
684 ) -> RcDoc<'a> {
685 let mut docs = vec![];
686 docs.push(RcDoc::text(format!(
687 "CREATE{}{} VIEW{}",
688 if v.if_exists == IfExistsBehavior::Replace {
689 " OR REPLACE"
690 } else {
691 ""
692 },
693 if v.temporary { " TEMPORARY" } else { "" },
694 if v.if_exists == IfExistsBehavior::Skip {
695 " IF NOT EXISTS"
696 } else {
697 ""
698 },
699 )));
700 docs.push(self.doc_view_definition(&v.definition));
701 intersperse_line_nest(docs)
702 }
703
704 pub(crate) fn doc_create_materialized_view<'a, T: AstInfo>(
705 &'a self,
706 v: &'a CreateMaterializedViewStatement<T>,
707 ) -> RcDoc<'a> {
708 let mut docs = vec![];
709 docs.push(RcDoc::text(format!(
710 "CREATE{}{} MATERIALIZED VIEW{} {}",
711 if v.if_exists == IfExistsBehavior::Replace {
712 " OR REPLACE"
713 } else {
714 ""
715 },
716 if v.replacement_for.is_some() {
717 " REPLACEMENT"
718 } else {
719 ""
720 },
721 if v.if_exists == IfExistsBehavior::Skip {
722 " IF NOT EXISTS"
723 } else {
724 ""
725 },
726 v.name,
727 )));
728 if !v.columns.is_empty() {
729 docs.push(bracket(
730 "(",
731 comma_separate(|c| self.doc_display_pass(c), &v.columns),
732 ")",
733 ));
734 }
735 if let Some(target) = &v.replacement_for {
736 docs.push(RcDoc::text(format!(
737 "FOR {}",
738 target.to_ast_string_simple()
739 )));
740 }
741 if let Some(cluster) = &v.in_cluster {
742 docs.push(RcDoc::text(format!(
743 "IN CLUSTER {}",
744 cluster.to_ast_string_simple()
745 )));
746 }
747 if !v.with_options.is_empty() {
748 docs.push(bracket(
749 "WITH (",
750 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
751 ")",
752 ));
753 }
754 docs.push(nest_title("AS", self.doc_query(&v.query)));
755 intersperse_line_nest(docs)
756 }
757
758 fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition<T>) -> RcDoc<'a> {
759 let mut docs = vec![RcDoc::text(v.name.to_string())];
760 if !v.columns.is_empty() {
761 docs.push(bracket(
762 "(",
763 comma_separate(|c| self.doc_display_pass(c), &v.columns),
764 ")",
765 ));
766 }
767 docs.push(nest_title("AS", self.doc_query(&v.query)));
768 RcDoc::intersperse(docs, Doc::line()).group()
769 }
770
771 pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement<T>) -> RcDoc<'a> {
772 let mut first = vec![RcDoc::text(format!(
773 "INSERT INTO {}",
774 v.table_name.to_ast_string_simple()
775 ))];
776 if !v.columns.is_empty() {
777 first.push(bracket(
778 "(",
779 comma_separate(|c| self.doc_display_pass(c), &v.columns),
780 ")",
781 ));
782 }
783 let sources = match &v.source {
784 InsertSource::Query(query) => self.doc_query(query),
785 _ => self.doc_display(&v.source, "insert source"),
786 };
787 let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]);
788 if !v.returning.is_empty() {
789 doc = nest(
790 doc,
791 nest_title(
792 "RETURNING",
793 comma_separate(|r| self.doc_display_pass(r), &v.returning),
794 ),
795 )
796 }
797 doc
798 }
799
800 pub(crate) fn doc_select_statement<'a, T: AstInfo>(
801 &'a self,
802 v: &'a SelectStatement<T>,
803 ) -> RcDoc<'a> {
804 let mut doc = self.doc_query(&v.query);
805 if let Some(as_of) = &v.as_of {
806 doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]);
807 }
808 doc.group()
809 }
810
811 fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr<T>]) -> RcDoc<'a> {
812 title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v)
813 }
814
815 fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr<T>) -> RcDoc<'a> {
816 let doc = self.doc_expr(&v.expr);
817 let doc = match v.asc {
818 Some(true) => nest(doc, RcDoc::text("ASC")),
819 Some(false) => nest(doc, RcDoc::text("DESC")),
820 None => doc,
821 };
822 match v.nulls_last {
823 Some(true) => nest(doc, RcDoc::text("NULLS LAST")),
824 Some(false) => nest(doc, RcDoc::text("NULLS FIRST")),
825 None => doc,
826 }
827 }
828
829 fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query<T>) -> RcDoc<'a> {
830 let mut docs = vec![];
831 if !v.ctes.is_empty() {
832 match &v.ctes {
833 CteBlock::Simple(ctes) => {
834 docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes))
835 }
836 CteBlock::MutuallyRecursive(mutrec) => {
837 let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE");
838 if !mutrec.options.is_empty() {
839 doc = nest(
840 doc,
841 bracket(
842 "(",
843 comma_separate(|o| self.doc_display_pass(o), &mutrec.options),
844 ")",
845 ),
846 );
847 }
848 docs.push(nest(
849 doc,
850 comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes),
851 ));
852 }
853 }
854 }
855 docs.push(self.doc_set_expr(&v.body));
856 if !v.order_by.is_empty() {
857 docs.push(self.doc_order_by(&v.order_by));
858 }
859
860 let offset = if let Some(offset) = &v.offset {
861 vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])]
862 } else {
863 vec![]
864 };
865
866 if let Some(limit) = &v.limit {
867 if limit.with_ties {
868 docs.extend(offset);
869 docs.push(RcDoc::concat([
870 RcDoc::text("FETCH FIRST "),
871 self.doc_expr(&limit.quantity),
872 RcDoc::text(" ROWS WITH TIES"),
873 ]));
874 } else {
875 docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity)));
876 docs.extend(offset);
877 }
878 } else {
879 docs.extend(offset);
880 }
881
882 RcDoc::intersperse(docs, Doc::line()).group()
883 }
884
885 fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte<T>) -> RcDoc<'a> {
886 RcDoc::concat([
887 RcDoc::text(format!("{} AS", v.alias)),
888 RcDoc::line(),
889 bracket("(", self.doc_query(&v.query), ")"),
890 ])
891 }
892
893 fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec<T>) -> RcDoc<'a> {
894 let mut docs = Vec::new();
895 if !v.columns.is_empty() {
896 docs.push(bracket(
897 "(",
898 comma_separate(|c| self.doc_display_pass(c), &v.columns),
899 ")",
900 ));
901 }
902 docs.push(bracket("AS (", self.doc_query(&v.query), ")"));
903 nest(
904 self.doc_display_pass(&v.name),
905 RcDoc::intersperse(docs, Doc::line()).group(),
906 )
907 }
908
909 fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr<T>) -> RcDoc<'a> {
910 match v {
911 SetExpr::Select(v) => self.doc_select(v),
912 SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"),
913 SetExpr::SetOperation {
914 op,
915 all,
916 left,
917 right,
918 } => {
919 let all_str = if *all { " ALL" } else { "" };
920 RcDoc::concat([
921 self.doc_set_expr(left),
922 RcDoc::line(),
923 RcDoc::concat([
924 RcDoc::text(format!("{}{}", op, all_str)),
925 RcDoc::line(),
926 self.doc_set_expr(right),
927 ])
928 .nest(TAB)
929 .group(),
930 ])
931 }
932 SetExpr::Values(v) => self.doc_values(v),
933 SetExpr::Show(v) => self.doc_display(v, "SHOW"),
934 SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)),
935 }
936 .group()
937 }
938
939 fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values<T>) -> RcDoc<'a> {
940 let rows =
941 v.0.iter()
942 .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")"));
943 RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)])
944 .nest(TAB)
945 .group()
946 }
947
948 fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins<T>) -> RcDoc<'a> {
949 let mut docs = vec![self.doc_table_factor(&v.relation)];
950 for j in &v.joins {
951 docs.push(self.doc_join(j));
952 }
953 intersperse_line_nest(docs)
954 }
955
956 fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join<T>) -> RcDoc<'a> {
957 let (constraint, name) = match &v.join_operator {
958 JoinOperator::Inner(constraint) => (constraint, "JOIN"),
959 JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"),
960 JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"),
961 JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"),
962 _ => return self.doc_display(v, "join operator"),
963 };
964 let constraint = match constraint {
965 JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)),
966 JoinConstraint::Using { columns, alias } => {
967 let mut doc = bracket(
968 "USING(",
969 comma_separate(|c| self.doc_display_pass(c), columns),
970 ")",
971 );
972 if let Some(alias) = alias {
973 doc = nest(doc, nest_title("AS", self.doc_display_pass(alias)));
974 }
975 doc
976 }
977 _ => return self.doc_display(v, "join constraint"),
978 };
979 intersperse_line_nest([
980 RcDoc::text(name),
981 self.doc_table_factor(&v.relation),
982 constraint,
983 ])
984 }
985
986 fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor<T>) -> RcDoc<'a> {
987 match v {
988 TableFactor::Derived {
989 lateral,
990 subquery,
991 alias,
992 } => {
993 let prefix = if *lateral { "LATERAL (" } else { "(" };
994 let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")];
995 if let Some(alias) = alias {
996 docs.push(RcDoc::text(format!("AS {}", alias)));
997 }
998 intersperse_line_nest(docs)
999 }
1000 TableFactor::NestedJoin { join, alias } => {
1001 let mut doc = bracket("(", self.doc_table_with_joins(join), ")");
1002 if let Some(alias) = alias {
1003 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1004 }
1005 doc
1006 }
1007 TableFactor::Table { name, alias } => {
1008 let mut doc = self.doc_display_pass(name);
1009 if let Some(alias) = alias {
1010 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1011 }
1012 doc
1013 }
1014 _ => self.doc_display(v, "table factor variant"),
1015 }
1016 }
1017
1018 fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct<T>) -> RcDoc<'a> {
1019 match v {
1020 Distinct::EntireRow => RcDoc::text("DISTINCT"),
1021 Distinct::On(cols) => bracket(
1022 "DISTINCT ON (",
1023 comma_separate(|c| self.doc_expr(c), cols),
1024 ")",
1025 ),
1026 }
1027 }
1028
1029 fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select<T>) -> RcDoc<'a> {
1030 let mut docs = vec![];
1031 let mut select = RcDoc::text("SELECT");
1032 if let Some(distinct) = &v.distinct {
1033 select = nest(select, self.doc_distinct(distinct));
1034 }
1035 docs.push(nest_comma_separate(
1036 select,
1037 |s| self.doc_select_item(s),
1038 &v.projection,
1039 ));
1040 if !v.from.is_empty() {
1041 docs.push(title_comma_separate(
1042 "FROM",
1043 |t| self.doc_table_with_joins(t),
1044 &v.from,
1045 ));
1046 }
1047 if let Some(selection) = &v.selection {
1048 docs.push(nest_title("WHERE", self.doc_expr(selection)));
1049 }
1050 if !v.group_by.is_empty() {
1051 docs.push(title_comma_separate(
1052 "GROUP BY",
1053 |e| self.doc_expr(e),
1054 &v.group_by,
1055 ));
1056 }
1057 if let Some(having) = &v.having {
1058 docs.push(nest_title("HAVING", self.doc_expr(having)));
1059 }
1060 if let Some(qualify) = &v.qualify {
1061 docs.push(nest_title("QUALIFY", self.doc_expr(qualify)));
1062 }
1063 if !v.options.is_empty() {
1064 docs.push(bracket(
1065 "OPTIONS (",
1066 comma_separate(|o| self.doc_display_pass(o), &v.options),
1067 ")",
1068 ));
1069 }
1070 RcDoc::intersperse(docs, Doc::line()).group()
1071 }
1072
1073 fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem<T>) -> RcDoc<'a> {
1074 match v {
1075 SelectItem::Expr { expr, alias } => {
1076 let mut doc = self.doc_expr(expr);
1077 if let Some(alias) = alias {
1078 doc = nest(
1079 doc,
1080 RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]),
1081 );
1082 }
1083 doc
1084 }
1085 SelectItem::Wildcard => self.doc_display_pass(v),
1086 }
1087 }
1088
1089 pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr<T>) -> RcDoc<'a> {
1090 match v {
1091 Expr::Op { op, expr1, expr2 } => {
1092 if let Some(expr2) = expr2 {
1093 RcDoc::concat([
1094 self.doc_expr(expr1),
1095 RcDoc::line(),
1096 RcDoc::text(format!("{} ", op)),
1097 self.doc_expr(expr2).nest(TAB),
1098 ])
1099 } else {
1100 RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)])
1101 }
1102 }
1103 Expr::Case {
1104 operand,
1105 conditions,
1106 results,
1107 else_result,
1108 } => {
1109 let mut docs = Vec::new();
1110 if let Some(operand) = operand {
1111 docs.push(self.doc_expr(operand));
1112 }
1113 for (c, r) in conditions.iter().zip_eq(results) {
1114 let when = nest_title("WHEN", self.doc_expr(c));
1115 let then = nest_title("THEN", self.doc_expr(r));
1116 docs.push(nest(when, then));
1117 }
1118 if let Some(else_result) = else_result {
1119 docs.push(nest_title("ELSE", self.doc_expr(else_result)));
1120 }
1121 let doc = intersperse_line_nest(docs);
1122 bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line())
1123 }
1124 Expr::Cast { expr, data_type } => {
1125 let doc = self.doc_expr(expr);
1126 RcDoc::concat([
1127 doc,
1128 RcDoc::text(format!("::{}", data_type.to_ast_string_simple())),
1129 ])
1130 }
1131 Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"),
1132 Expr::Function(fun) => self.doc_function(fun),
1133 Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"),
1134 Expr::Identifier(_)
1135 | Expr::Value(_)
1136 | Expr::QualifiedWildcard(_)
1137 | Expr::WildcardAccess(_)
1138 | Expr::FieldAccess { .. } => self.doc_display_pass(v),
1139 Expr::And { left, right } => bracket_doc(
1140 self.doc_expr(left),
1141 RcDoc::text("AND"),
1142 self.doc_expr(right),
1143 RcDoc::line(),
1144 ),
1145 Expr::Or { left, right } => bracket_doc(
1146 self.doc_expr(left),
1147 RcDoc::text("OR"),
1148 self.doc_expr(right),
1149 RcDoc::line(),
1150 ),
1151 Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"),
1152 Expr::IsExpr {
1153 expr,
1154 negated,
1155 construct,
1156 } => bracket_doc(
1157 self.doc_expr(expr),
1158 RcDoc::text(if *negated { "IS NOT" } else { "IS" }),
1159 self.doc_display_pass(construct),
1160 RcDoc::line(),
1161 ),
1162 Expr::Not { expr } => {
1163 RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)])
1164 }
1165 Expr::Between {
1166 expr,
1167 negated,
1168 low,
1169 high,
1170 } => RcDoc::intersperse(
1171 [
1172 self.doc_expr(expr),
1173 RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }),
1174 RcDoc::intersperse(
1175 [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)],
1176 RcDoc::line(),
1177 )
1178 .group(),
1179 ],
1180 RcDoc::line(),
1181 ),
1182 Expr::InSubquery {
1183 expr,
1184 subquery,
1185 negated,
1186 } => RcDoc::intersperse(
1187 [
1188 self.doc_expr(expr),
1189 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1190 self.doc_query(subquery),
1191 RcDoc::text(")"),
1192 ],
1193 RcDoc::line(),
1194 ),
1195 Expr::InList {
1196 expr,
1197 list,
1198 negated,
1199 } => RcDoc::intersperse(
1200 [
1201 self.doc_expr(expr),
1202 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1203 comma_separate(|e| self.doc_expr(e), list),
1204 RcDoc::text(")"),
1205 ],
1206 RcDoc::line(),
1207 ),
1208 Expr::Row { exprs } => {
1209 bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")")
1210 }
1211 Expr::NullIf { l_expr, r_expr } => bracket(
1212 "NULLIF (",
1213 comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]),
1214 ")",
1215 ),
1216 Expr::HomogenizingFunction { function, exprs } => bracket(
1217 format!("{function}("),
1218 comma_separate(|e| self.doc_expr(e), exprs),
1219 ")",
1220 ),
1221 Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"),
1222 Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"),
1223 Expr::Array(exprs) => {
1224 bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]")
1225 }
1226 Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"),
1227 _ => self.doc_display(v, "expr variant"),
1228 }
1229 .group()
1230 }
1231
1232 fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function<T>) -> RcDoc<'a> {
1233 match &v.args {
1234 FunctionArgs::Star => self.doc_display_pass(v),
1235 FunctionArgs::Args { args, order_by } => {
1236 if args.is_empty() {
1237 return self.doc_display_pass(v);
1239 }
1240 if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() {
1241 return self.doc_display(v, "function filter or over or order by");
1242 }
1243 let special = match v.name.to_ast_string_stable().as_str() {
1244 r#""extract""# if v.args.len() == Some(2) => true,
1245 r#""position""# if v.args.len() == Some(2) => true,
1246 _ => false,
1247 };
1248 if special {
1249 return self.doc_display(v, "special function");
1250 }
1251 let name = format!(
1252 "{}({}",
1253 v.name.to_ast_string_simple(),
1254 if v.distinct { "DISTINCT " } else { "" }
1255 );
1256 bracket(name, comma_separate(|e| self.doc_expr(e), args), ")")
1257 }
1258 }
1259 }
1260}