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 match (&v.in_cluster, &v.in_cluster_replica) {
742 (Some(cluster), Some(replica)) => {
743 docs.push(RcDoc::text(format!(
744 "IN CLUSTER {} REPLICA {}",
745 cluster.to_ast_string_simple(),
746 replica.to_ast_string_simple(),
747 )));
748 }
749 (Some(cluster), None) => {
750 docs.push(RcDoc::text(format!(
751 "IN CLUSTER {}",
752 cluster.to_ast_string_simple(),
753 )));
754 }
755 (None, Some(replica)) => {
756 docs.push(RcDoc::text(format!(
757 "IN REPLICA {}",
758 replica.to_ast_string_simple(),
759 )));
760 }
761 (None, None) => {}
762 }
763 if !v.with_options.is_empty() {
764 docs.push(bracket(
765 "WITH (",
766 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
767 ")",
768 ));
769 }
770 docs.push(nest_title("AS", self.doc_query(&v.query)));
771 intersperse_line_nest(docs)
772 }
773
774 fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition<T>) -> RcDoc<'a> {
775 let mut docs = vec![RcDoc::text(v.name.to_string())];
776 if !v.columns.is_empty() {
777 docs.push(bracket(
778 "(",
779 comma_separate(|c| self.doc_display_pass(c), &v.columns),
780 ")",
781 ));
782 }
783 docs.push(nest_title("AS", self.doc_query(&v.query)));
784 RcDoc::intersperse(docs, Doc::line()).group()
785 }
786
787 pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement<T>) -> RcDoc<'a> {
788 let mut first = vec![RcDoc::text(format!(
789 "INSERT INTO {}",
790 v.table_name.to_ast_string_simple()
791 ))];
792 if !v.columns.is_empty() {
793 first.push(bracket(
794 "(",
795 comma_separate(|c| self.doc_display_pass(c), &v.columns),
796 ")",
797 ));
798 }
799 let sources = match &v.source {
800 InsertSource::Query(query) => self.doc_query(query),
801 _ => self.doc_display(&v.source, "insert source"),
802 };
803 let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]);
804 if !v.returning.is_empty() {
805 doc = nest(
806 doc,
807 nest_title(
808 "RETURNING",
809 comma_separate(|r| self.doc_display_pass(r), &v.returning),
810 ),
811 )
812 }
813 doc
814 }
815
816 pub(crate) fn doc_select_statement<'a, T: AstInfo>(
817 &'a self,
818 v: &'a SelectStatement<T>,
819 ) -> RcDoc<'a> {
820 let mut doc = self.doc_query(&v.query);
821 if let Some(as_of) = &v.as_of {
822 doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]);
823 }
824 doc.group()
825 }
826
827 fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr<T>]) -> RcDoc<'a> {
828 title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v)
829 }
830
831 fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr<T>) -> RcDoc<'a> {
832 let doc = self.doc_expr(&v.expr);
833 let doc = match v.asc {
834 Some(true) => nest(doc, RcDoc::text("ASC")),
835 Some(false) => nest(doc, RcDoc::text("DESC")),
836 None => doc,
837 };
838 match v.nulls_last {
839 Some(true) => nest(doc, RcDoc::text("NULLS LAST")),
840 Some(false) => nest(doc, RcDoc::text("NULLS FIRST")),
841 None => doc,
842 }
843 }
844
845 fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query<T>) -> RcDoc<'a> {
846 let mut docs = vec![];
847 if !v.ctes.is_empty() {
848 match &v.ctes {
849 CteBlock::Simple(ctes) => {
850 docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes))
851 }
852 CteBlock::MutuallyRecursive(mutrec) => {
853 let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE");
854 if !mutrec.options.is_empty() {
855 doc = nest(
856 doc,
857 bracket(
858 "(",
859 comma_separate(|o| self.doc_display_pass(o), &mutrec.options),
860 ")",
861 ),
862 );
863 }
864 docs.push(nest(
865 doc,
866 comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes),
867 ));
868 }
869 }
870 }
871 docs.push(self.doc_set_expr(&v.body));
872 if !v.order_by.is_empty() {
873 docs.push(self.doc_order_by(&v.order_by));
874 }
875
876 let offset = if let Some(offset) = &v.offset {
877 vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])]
878 } else {
879 vec![]
880 };
881
882 if let Some(limit) = &v.limit {
883 if limit.with_ties {
884 docs.extend(offset);
885 docs.push(RcDoc::concat([
886 RcDoc::text("FETCH FIRST "),
887 self.doc_expr(&limit.quantity),
888 RcDoc::text(" ROWS WITH TIES"),
889 ]));
890 } else {
891 docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity)));
892 docs.extend(offset);
893 }
894 } else {
895 docs.extend(offset);
896 }
897
898 RcDoc::intersperse(docs, Doc::line()).group()
899 }
900
901 fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte<T>) -> RcDoc<'a> {
902 RcDoc::concat([
903 RcDoc::text(format!("{} AS", v.alias)),
904 RcDoc::line(),
905 bracket("(", self.doc_query(&v.query), ")"),
906 ])
907 }
908
909 fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec<T>) -> RcDoc<'a> {
910 let mut docs = Vec::new();
911 if !v.columns.is_empty() {
912 docs.push(bracket(
913 "(",
914 comma_separate(|c| self.doc_display_pass(c), &v.columns),
915 ")",
916 ));
917 }
918 docs.push(bracket("AS (", self.doc_query(&v.query), ")"));
919 nest(
920 self.doc_display_pass(&v.name),
921 RcDoc::intersperse(docs, Doc::line()).group(),
922 )
923 }
924
925 fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr<T>) -> RcDoc<'a> {
926 match v {
927 SetExpr::Select(v) => self.doc_select(v),
928 SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"),
929 SetExpr::SetOperation {
930 op,
931 all,
932 left,
933 right,
934 } => {
935 let all_str = if *all { " ALL" } else { "" };
936 RcDoc::concat([
937 self.doc_set_expr(left),
938 RcDoc::line(),
939 RcDoc::concat([
940 RcDoc::text(format!("{}{}", op, all_str)),
941 RcDoc::line(),
942 self.doc_set_expr(right),
943 ])
944 .nest(TAB)
945 .group(),
946 ])
947 }
948 SetExpr::Values(v) => self.doc_values(v),
949 SetExpr::Show(v) => self.doc_display(v, "SHOW"),
950 SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)),
951 }
952 .group()
953 }
954
955 fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values<T>) -> RcDoc<'a> {
956 let rows =
957 v.0.iter()
958 .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")"));
959 RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)])
960 .nest(TAB)
961 .group()
962 }
963
964 fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins<T>) -> RcDoc<'a> {
965 let mut docs = vec![self.doc_table_factor(&v.relation)];
966 for j in &v.joins {
967 docs.push(self.doc_join(j));
968 }
969 intersperse_line_nest(docs)
970 }
971
972 fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join<T>) -> RcDoc<'a> {
973 let (constraint, name) = match &v.join_operator {
974 JoinOperator::Inner(constraint) => (constraint, "JOIN"),
975 JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"),
976 JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"),
977 JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"),
978 _ => return self.doc_display(v, "join operator"),
979 };
980 let constraint = match constraint {
981 JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)),
982 JoinConstraint::Using { columns, alias } => {
983 let mut doc = bracket(
984 "USING(",
985 comma_separate(|c| self.doc_display_pass(c), columns),
986 ")",
987 );
988 if let Some(alias) = alias {
989 doc = nest(doc, nest_title("AS", self.doc_display_pass(alias)));
990 }
991 doc
992 }
993 _ => return self.doc_display(v, "join constraint"),
994 };
995 intersperse_line_nest([
996 RcDoc::text(name),
997 self.doc_table_factor(&v.relation),
998 constraint,
999 ])
1000 }
1001
1002 fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor<T>) -> RcDoc<'a> {
1003 match v {
1004 TableFactor::Derived {
1005 lateral,
1006 subquery,
1007 alias,
1008 } => {
1009 let prefix = if *lateral { "LATERAL (" } else { "(" };
1010 let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")];
1011 if let Some(alias) = alias {
1012 docs.push(RcDoc::text(format!("AS {}", alias)));
1013 }
1014 intersperse_line_nest(docs)
1015 }
1016 TableFactor::NestedJoin { join, alias } => {
1017 let mut doc = bracket("(", self.doc_table_with_joins(join), ")");
1018 if let Some(alias) = alias {
1019 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1020 }
1021 doc
1022 }
1023 TableFactor::Table { name, alias } => {
1024 let mut doc = self.doc_display_pass(name);
1025 if let Some(alias) = alias {
1026 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1027 }
1028 doc
1029 }
1030 _ => self.doc_display(v, "table factor variant"),
1031 }
1032 }
1033
1034 fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct<T>) -> RcDoc<'a> {
1035 match v {
1036 Distinct::EntireRow => RcDoc::text("DISTINCT"),
1037 Distinct::On(cols) => bracket(
1038 "DISTINCT ON (",
1039 comma_separate(|c| self.doc_expr(c), cols),
1040 ")",
1041 ),
1042 }
1043 }
1044
1045 fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select<T>) -> RcDoc<'a> {
1046 let mut docs = vec![];
1047 let mut select = RcDoc::text("SELECT");
1048 if let Some(distinct) = &v.distinct {
1049 select = nest(select, self.doc_distinct(distinct));
1050 }
1051 docs.push(nest_comma_separate(
1052 select,
1053 |s| self.doc_select_item(s),
1054 &v.projection,
1055 ));
1056 if !v.from.is_empty() {
1057 docs.push(title_comma_separate(
1058 "FROM",
1059 |t| self.doc_table_with_joins(t),
1060 &v.from,
1061 ));
1062 }
1063 if let Some(selection) = &v.selection {
1064 docs.push(nest_title("WHERE", self.doc_expr(selection)));
1065 }
1066 if !v.group_by.is_empty() {
1067 docs.push(title_comma_separate(
1068 "GROUP BY",
1069 |e| self.doc_expr(e),
1070 &v.group_by,
1071 ));
1072 }
1073 if let Some(having) = &v.having {
1074 docs.push(nest_title("HAVING", self.doc_expr(having)));
1075 }
1076 if let Some(qualify) = &v.qualify {
1077 docs.push(nest_title("QUALIFY", self.doc_expr(qualify)));
1078 }
1079 if !v.options.is_empty() {
1080 docs.push(bracket(
1081 "OPTIONS (",
1082 comma_separate(|o| self.doc_display_pass(o), &v.options),
1083 ")",
1084 ));
1085 }
1086 RcDoc::intersperse(docs, Doc::line()).group()
1087 }
1088
1089 fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem<T>) -> RcDoc<'a> {
1090 match v {
1091 SelectItem::Expr { expr, alias } => {
1092 let mut doc = self.doc_expr(expr);
1093 if let Some(alias) = alias {
1094 doc = nest(
1095 doc,
1096 RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]),
1097 );
1098 }
1099 doc
1100 }
1101 SelectItem::Wildcard => self.doc_display_pass(v),
1102 }
1103 }
1104
1105 pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr<T>) -> RcDoc<'a> {
1106 match v {
1107 Expr::Op { op, expr1, expr2 } => {
1108 if let Some(expr2) = expr2 {
1109 RcDoc::concat([
1110 self.doc_expr(expr1),
1111 RcDoc::line(),
1112 RcDoc::text(format!("{} ", op)),
1113 self.doc_expr(expr2).nest(TAB),
1114 ])
1115 } else {
1116 RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)])
1117 }
1118 }
1119 Expr::Case {
1120 operand,
1121 conditions,
1122 results,
1123 else_result,
1124 } => {
1125 let mut docs = Vec::new();
1126 if let Some(operand) = operand {
1127 docs.push(self.doc_expr(operand));
1128 }
1129 for (c, r) in conditions.iter().zip_eq(results) {
1130 let when = nest_title("WHEN", self.doc_expr(c));
1131 let then = nest_title("THEN", self.doc_expr(r));
1132 docs.push(nest(when, then));
1133 }
1134 if let Some(else_result) = else_result {
1135 docs.push(nest_title("ELSE", self.doc_expr(else_result)));
1136 }
1137 let doc = intersperse_line_nest(docs);
1138 bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line())
1139 }
1140 Expr::Cast { expr, data_type } => {
1141 let doc = self.doc_expr(expr);
1142 RcDoc::concat([
1143 doc,
1144 RcDoc::text(format!("::{}", data_type.to_ast_string_simple())),
1145 ])
1146 }
1147 Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"),
1148 Expr::Function(fun) => self.doc_function(fun),
1149 Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"),
1150 Expr::Identifier(_)
1151 | Expr::Value(_)
1152 | Expr::QualifiedWildcard(_)
1153 | Expr::WildcardAccess(_)
1154 | Expr::FieldAccess { .. } => self.doc_display_pass(v),
1155 Expr::And { left, right } => bracket_doc(
1156 self.doc_expr(left),
1157 RcDoc::text("AND"),
1158 self.doc_expr(right),
1159 RcDoc::line(),
1160 ),
1161 Expr::Or { left, right } => bracket_doc(
1162 self.doc_expr(left),
1163 RcDoc::text("OR"),
1164 self.doc_expr(right),
1165 RcDoc::line(),
1166 ),
1167 Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"),
1168 Expr::IsExpr {
1169 expr,
1170 negated,
1171 construct,
1172 } => bracket_doc(
1173 self.doc_expr(expr),
1174 RcDoc::text(if *negated { "IS NOT" } else { "IS" }),
1175 self.doc_display_pass(construct),
1176 RcDoc::line(),
1177 ),
1178 Expr::Not { expr } => {
1179 RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)])
1180 }
1181 Expr::Between {
1182 expr,
1183 negated,
1184 low,
1185 high,
1186 } => RcDoc::intersperse(
1187 [
1188 self.doc_expr(expr),
1189 RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }),
1190 RcDoc::intersperse(
1191 [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)],
1192 RcDoc::line(),
1193 )
1194 .group(),
1195 ],
1196 RcDoc::line(),
1197 ),
1198 Expr::InSubquery {
1199 expr,
1200 subquery,
1201 negated,
1202 } => RcDoc::intersperse(
1203 [
1204 self.doc_expr(expr),
1205 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1206 self.doc_query(subquery),
1207 RcDoc::text(")"),
1208 ],
1209 RcDoc::line(),
1210 ),
1211 Expr::InList {
1212 expr,
1213 list,
1214 negated,
1215 } => RcDoc::intersperse(
1216 [
1217 self.doc_expr(expr),
1218 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1219 comma_separate(|e| self.doc_expr(e), list),
1220 RcDoc::text(")"),
1221 ],
1222 RcDoc::line(),
1223 ),
1224 Expr::Row { exprs } => {
1225 bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")")
1226 }
1227 Expr::NullIf { l_expr, r_expr } => bracket(
1228 "NULLIF (",
1229 comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]),
1230 ")",
1231 ),
1232 Expr::HomogenizingFunction { function, exprs } => bracket(
1233 format!("{function}("),
1234 comma_separate(|e| self.doc_expr(e), exprs),
1235 ")",
1236 ),
1237 Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"),
1238 Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"),
1239 Expr::Array(exprs) => {
1240 bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]")
1241 }
1242 Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"),
1243 _ => self.doc_display(v, "expr variant"),
1244 }
1245 .group()
1246 }
1247
1248 fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function<T>) -> RcDoc<'a> {
1249 match &v.args {
1250 FunctionArgs::Star => self.doc_display_pass(v),
1251 FunctionArgs::Args { args, order_by } => {
1252 if args.is_empty() {
1253 return self.doc_display_pass(v);
1255 }
1256 if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() {
1257 return self.doc_display(v, "function filter or over or order by");
1258 }
1259 let special = match v.name.to_ast_string_stable().as_str() {
1260 r#""extract""# if v.args.len() == Some(2) => true,
1261 r#""position""# if v.args.len() == Some(2) => true,
1262 _ => false,
1263 };
1264 if special {
1265 return self.doc_display(v, "special function");
1266 }
1267 let name = format!(
1268 "{}({}",
1269 v.name.to_ast_string_simple(),
1270 if v.distinct { "DISTINCT " } else { "" }
1271 );
1272 bracket(name, comma_separate(|e| self.doc_expr(e), args), ")")
1273 }
1274 }
1275 }
1276}