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 !v.with_options.is_empty() {
381 docs.push(bracket(
382 "WITH (",
383 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
384 ")",
385 ));
386 }
387
388 RcDoc::intersperse(docs, Doc::line()).group()
389 }
390
391 pub(crate) fn doc_create_subsource<'a, T: AstInfo>(
392 &'a self,
393 v: &'a CreateSubsourceStatement<T>,
394 ) -> RcDoc<'a> {
395 let mut docs = Vec::new();
396
397 let mut title = "CREATE SUBSOURCE".to_string();
399 if v.if_not_exists {
400 title.push_str(" IF NOT EXISTS");
401 }
402
403 let mut col_items = Vec::new();
405 col_items.extend(v.columns.iter().map(|c| self.doc_display_pass(c)));
406 col_items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
407
408 let table_def = nest(
409 self.doc_display_pass(&v.name),
410 bracket("(", comma_separated(col_items), ")"),
411 );
412 docs.push(nest_title(title, table_def));
413
414 if let Some(of_source) = &v.of_source {
416 docs.push(nest_title("OF SOURCE", self.doc_display_pass(of_source)));
417 }
418
419 if !v.with_options.is_empty() {
421 docs.push(bracket(
422 "WITH (",
423 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
424 ")",
425 ));
426 }
427
428 RcDoc::intersperse(docs, Doc::line()).group()
429 }
430
431 pub(crate) fn doc_create_cluster<'a, T: AstInfo>(
432 &'a self,
433 v: &'a CreateClusterStatement<T>,
434 ) -> RcDoc<'a> {
435 let mut docs = Vec::new();
436
437 docs.push(nest_title("CREATE CLUSTER", self.doc_display_pass(&v.name)));
439
440 if !v.options.is_empty() {
442 docs.push(bracket(
443 "(",
444 comma_separate(|o| self.doc_display_pass(o), &v.options),
445 ")",
446 ));
447 }
448
449 if !v.features.is_empty() {
451 docs.push(bracket(
452 "FEATURES (",
453 comma_separate(|f| self.doc_display_pass(f), &v.features),
454 ")",
455 ));
456 }
457
458 RcDoc::intersperse(docs, Doc::line()).group()
459 }
460
461 pub(crate) fn doc_create_cluster_replica<'a, T: AstInfo>(
462 &'a self,
463 v: &'a CreateClusterReplicaStatement<T>,
464 ) -> RcDoc<'a> {
465 let mut docs = Vec::new();
466
467 let replica_name = RcDoc::concat([
469 self.doc_display_pass(&v.of_cluster),
470 RcDoc::text("."),
471 self.doc_display_pass(&v.definition.name),
472 ]);
473 docs.push(nest_title("CREATE CLUSTER REPLICA", replica_name));
474
475 docs.push(bracket(
477 "(",
478 comma_separate(|o| self.doc_display_pass(o), &v.definition.options),
479 ")",
480 ));
481
482 RcDoc::intersperse(docs, Doc::line()).group()
483 }
484
485 pub(crate) fn doc_create_network_policy<'a, T: AstInfo>(
486 &'a self,
487 v: &'a CreateNetworkPolicyStatement<T>,
488 ) -> RcDoc<'a> {
489 let docs = vec![
490 nest_title("CREATE NETWORK POLICY", self.doc_display_pass(&v.name)),
492 bracket(
494 "(",
495 comma_separate(|o| self.doc_display_pass(o), &v.options),
496 ")",
497 ),
498 ];
499
500 RcDoc::intersperse(docs, Doc::line()).group()
501 }
502
503 pub(crate) fn doc_create_index<'a, T: AstInfo>(
504 &'a self,
505 v: &'a CreateIndexStatement<T>,
506 ) -> RcDoc<'a> {
507 let mut docs = Vec::new();
508
509 let mut title = "CREATE".to_string();
511 if v.key_parts.is_none() {
512 title.push_str(" DEFAULT");
513 }
514 title.push_str(" INDEX");
515 if v.if_not_exists {
516 title.push_str(" IF NOT EXISTS");
517 }
518
519 if let Some(name) = &v.name {
520 docs.push(nest_title(title, self.doc_display_pass(name)));
521 } else {
522 docs.push(RcDoc::text(title));
523 }
524
525 if let Some(cluster) = &v.in_cluster {
527 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
528 }
529
530 let on_clause = if let Some(key_parts) = &v.key_parts {
532 nest(
533 self.doc_display_pass(&v.on_name),
534 bracket(
535 "(",
536 comma_separate(|k| self.doc_display_pass(k), key_parts),
537 ")",
538 ),
539 )
540 } else {
541 self.doc_display_pass(&v.on_name)
542 };
543 docs.push(nest_title("ON", on_clause));
544
545 if !v.with_options.is_empty() {
547 docs.push(bracket(
548 "WITH (",
549 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
550 ")",
551 ));
552 }
553
554 RcDoc::intersperse(docs, Doc::line()).group()
555 }
556
557 fn doc_format_specifier<T: AstInfo>(&self, v: &FormatSpecifier<T>) -> RcDoc<'_> {
558 match v {
559 FormatSpecifier::Bare(format) => nest_title("FORMAT", self.doc_display_pass(format)),
560 FormatSpecifier::KeyValue { key, value } => {
561 let docs = vec![
562 nest_title("KEY FORMAT", self.doc_display_pass(key)),
563 nest_title("VALUE FORMAT", self.doc_display_pass(value)),
564 ];
565 RcDoc::intersperse(docs, Doc::line()).group()
566 }
567 }
568 }
569
570 fn doc_external_references<'a>(&'a self, v: &'a ExternalReferences) -> RcDoc<'a> {
571 match v {
572 ExternalReferences::SubsetTables(subsources) => bracket(
573 "FOR TABLES (",
574 comma_separate(|s| self.doc_display_pass(s), subsources),
575 ")",
576 ),
577 ExternalReferences::SubsetSchemas(schemas) => bracket(
578 "FOR SCHEMAS (",
579 comma_separate(|s| self.doc_display_pass(s), schemas),
580 ")",
581 ),
582 ExternalReferences::All => RcDoc::text("FOR ALL TABLES"),
583 }
584 }
585
586 pub(crate) fn doc_copy<'a, T: AstInfo>(&'a self, v: &'a CopyStatement<T>) -> RcDoc<'a> {
587 let relation = match &v.relation {
588 CopyRelation::Named { name, columns } => {
589 let mut relation = self.doc_display_pass(name);
590 if !columns.is_empty() {
591 relation = bracket_doc(
592 nest(relation, RcDoc::text("(")),
593 comma_separate(|c| self.doc_display_pass(c), columns),
594 RcDoc::text(")"),
595 RcDoc::line_(),
596 );
597 }
598 RcDoc::concat([RcDoc::text("COPY "), relation])
599 }
600 CopyRelation::Select(query) => bracket("COPY (", self.doc_select_statement(query), ")"),
601 CopyRelation::Subscribe(query) => bracket("COPY (", self.doc_subscribe(query), ")"),
602 };
603 let mut docs = vec![
604 relation,
605 RcDoc::concat([
606 self.doc_display_pass(&v.direction),
607 RcDoc::text(" "),
608 self.doc_display_pass(&v.target),
609 ]),
610 ];
611 if !v.options.is_empty() {
612 docs.push(bracket(
613 "WITH (",
614 comma_separate(|o| self.doc_display_pass(o), &v.options),
615 ")",
616 ));
617 }
618 RcDoc::intersperse(docs, Doc::line()).group()
619 }
620
621 pub(crate) fn doc_subscribe<'a, T: AstInfo>(
622 &'a self,
623 v: &'a SubscribeStatement<T>,
624 ) -> RcDoc<'a> {
625 let doc = match &v.relation {
626 SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", self.doc_display_pass(name)),
627 SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", self.doc_query(query), ")"),
628 };
629 let mut docs = vec![doc];
630 if !v.options.is_empty() {
631 docs.push(bracket(
632 "WITH (",
633 comma_separate(|o| self.doc_display_pass(o), &v.options),
634 ")",
635 ));
636 }
637 if let Some(as_of) = &v.as_of {
638 docs.push(self.doc_as_of(as_of));
639 }
640 if let Some(up_to) = &v.up_to {
641 docs.push(nest_title("UP TO", self.doc_expr(up_to)));
642 }
643 match &v.output {
644 SubscribeOutput::Diffs => {}
645 SubscribeOutput::WithinTimestampOrderBy { order_by } => {
646 docs.push(nest_title(
647 "WITHIN TIMESTAMP ORDER BY ",
648 comma_separate(|o| self.doc_order_by_expr(o), order_by),
649 ));
650 }
651 SubscribeOutput::EnvelopeUpsert { key_columns } => {
652 docs.push(bracket(
653 "ENVELOPE UPSERT (KEY (",
654 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
655 "))",
656 ));
657 }
658 SubscribeOutput::EnvelopeDebezium { key_columns } => {
659 docs.push(bracket(
660 "ENVELOPE DEBEZIUM (KEY (",
661 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
662 "))",
663 ));
664 }
665 }
666 RcDoc::intersperse(docs, Doc::line()).group()
667 }
668
669 fn doc_as_of<'a, T: AstInfo>(&'a self, v: &'a AsOf<T>) -> RcDoc<'a> {
670 let (title, expr) = match v {
671 AsOf::At(expr) => ("AS OF", expr),
672 AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr),
673 };
674 nest_title(title, self.doc_expr(expr))
675 }
676
677 pub(crate) fn doc_create_view<'a, T: AstInfo>(
678 &'a self,
679 v: &'a CreateViewStatement<T>,
680 ) -> RcDoc<'a> {
681 let mut docs = vec![];
682 docs.push(RcDoc::text(format!(
683 "CREATE{}{} VIEW{}",
684 if v.if_exists == IfExistsBehavior::Replace {
685 " OR REPLACE"
686 } else {
687 ""
688 },
689 if v.temporary { " TEMPORARY" } else { "" },
690 if v.if_exists == IfExistsBehavior::Skip {
691 " IF NOT EXISTS"
692 } else {
693 ""
694 },
695 )));
696 docs.push(self.doc_view_definition(&v.definition));
697 intersperse_line_nest(docs)
698 }
699
700 pub(crate) fn doc_create_materialized_view<'a, T: AstInfo>(
701 &'a self,
702 v: &'a CreateMaterializedViewStatement<T>,
703 ) -> RcDoc<'a> {
704 let mut docs = vec![];
705 docs.push(RcDoc::text(format!(
706 "CREATE{}{} MATERIALIZED VIEW{} {}",
707 if v.if_exists == IfExistsBehavior::Replace {
708 " OR REPLACE"
709 } else {
710 ""
711 },
712 if v.replacement_for.is_some() {
713 " REPLACEMENT"
714 } else {
715 ""
716 },
717 if v.if_exists == IfExistsBehavior::Skip {
718 " IF NOT EXISTS"
719 } else {
720 ""
721 },
722 v.name,
723 )));
724 if !v.columns.is_empty() {
725 docs.push(bracket(
726 "(",
727 comma_separate(|c| self.doc_display_pass(c), &v.columns),
728 ")",
729 ));
730 }
731 if let Some(target) = &v.replacement_for {
732 docs.push(RcDoc::text(format!(
733 "FOR {}",
734 target.to_ast_string_simple()
735 )));
736 }
737 if let Some(cluster) = &v.in_cluster {
738 docs.push(RcDoc::text(format!(
739 "IN CLUSTER {}",
740 cluster.to_ast_string_simple()
741 )));
742 }
743 if !v.with_options.is_empty() {
744 docs.push(bracket(
745 "WITH (",
746 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
747 ")",
748 ));
749 }
750 docs.push(nest_title("AS", self.doc_query(&v.query)));
751 intersperse_line_nest(docs)
752 }
753
754 fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition<T>) -> RcDoc<'a> {
755 let mut docs = vec![RcDoc::text(v.name.to_string())];
756 if !v.columns.is_empty() {
757 docs.push(bracket(
758 "(",
759 comma_separate(|c| self.doc_display_pass(c), &v.columns),
760 ")",
761 ));
762 }
763 docs.push(nest_title("AS", self.doc_query(&v.query)));
764 RcDoc::intersperse(docs, Doc::line()).group()
765 }
766
767 pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement<T>) -> RcDoc<'a> {
768 let mut first = vec![RcDoc::text(format!(
769 "INSERT INTO {}",
770 v.table_name.to_ast_string_simple()
771 ))];
772 if !v.columns.is_empty() {
773 first.push(bracket(
774 "(",
775 comma_separate(|c| self.doc_display_pass(c), &v.columns),
776 ")",
777 ));
778 }
779 let sources = match &v.source {
780 InsertSource::Query(query) => self.doc_query(query),
781 _ => self.doc_display(&v.source, "insert source"),
782 };
783 let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]);
784 if !v.returning.is_empty() {
785 doc = nest(
786 doc,
787 nest_title(
788 "RETURNING",
789 comma_separate(|r| self.doc_display_pass(r), &v.returning),
790 ),
791 )
792 }
793 doc
794 }
795
796 pub(crate) fn doc_select_statement<'a, T: AstInfo>(
797 &'a self,
798 v: &'a SelectStatement<T>,
799 ) -> RcDoc<'a> {
800 let mut doc = self.doc_query(&v.query);
801 if let Some(as_of) = &v.as_of {
802 doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]);
803 }
804 doc.group()
805 }
806
807 fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr<T>]) -> RcDoc<'a> {
808 title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v)
809 }
810
811 fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr<T>) -> RcDoc<'a> {
812 let doc = self.doc_expr(&v.expr);
813 let doc = match v.asc {
814 Some(true) => nest(doc, RcDoc::text("ASC")),
815 Some(false) => nest(doc, RcDoc::text("DESC")),
816 None => doc,
817 };
818 match v.nulls_last {
819 Some(true) => nest(doc, RcDoc::text("NULLS LAST")),
820 Some(false) => nest(doc, RcDoc::text("NULLS FIRST")),
821 None => doc,
822 }
823 }
824
825 fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query<T>) -> RcDoc<'a> {
826 let mut docs = vec![];
827 if !v.ctes.is_empty() {
828 match &v.ctes {
829 CteBlock::Simple(ctes) => {
830 docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes))
831 }
832 CteBlock::MutuallyRecursive(mutrec) => {
833 let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE");
834 if !mutrec.options.is_empty() {
835 doc = nest(
836 doc,
837 bracket(
838 "(",
839 comma_separate(|o| self.doc_display_pass(o), &mutrec.options),
840 ")",
841 ),
842 );
843 }
844 docs.push(nest(
845 doc,
846 comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes),
847 ));
848 }
849 }
850 }
851 docs.push(self.doc_set_expr(&v.body));
852 if !v.order_by.is_empty() {
853 docs.push(self.doc_order_by(&v.order_by));
854 }
855
856 let offset = if let Some(offset) = &v.offset {
857 vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])]
858 } else {
859 vec![]
860 };
861
862 if let Some(limit) = &v.limit {
863 if limit.with_ties {
864 docs.extend(offset);
865 docs.push(RcDoc::concat([
866 RcDoc::text("FETCH FIRST "),
867 self.doc_expr(&limit.quantity),
868 RcDoc::text(" ROWS WITH TIES"),
869 ]));
870 } else {
871 docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity)));
872 docs.extend(offset);
873 }
874 } else {
875 docs.extend(offset);
876 }
877
878 RcDoc::intersperse(docs, Doc::line()).group()
879 }
880
881 fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte<T>) -> RcDoc<'a> {
882 RcDoc::concat([
883 RcDoc::text(format!("{} AS", v.alias)),
884 RcDoc::line(),
885 bracket("(", self.doc_query(&v.query), ")"),
886 ])
887 }
888
889 fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec<T>) -> RcDoc<'a> {
890 let mut docs = Vec::new();
891 if !v.columns.is_empty() {
892 docs.push(bracket(
893 "(",
894 comma_separate(|c| self.doc_display_pass(c), &v.columns),
895 ")",
896 ));
897 }
898 docs.push(bracket("AS (", self.doc_query(&v.query), ")"));
899 nest(
900 self.doc_display_pass(&v.name),
901 RcDoc::intersperse(docs, Doc::line()).group(),
902 )
903 }
904
905 fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr<T>) -> RcDoc<'a> {
906 match v {
907 SetExpr::Select(v) => self.doc_select(v),
908 SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"),
909 SetExpr::SetOperation {
910 op,
911 all,
912 left,
913 right,
914 } => {
915 let all_str = if *all { " ALL" } else { "" };
916 RcDoc::concat([
917 self.doc_set_expr(left),
918 RcDoc::line(),
919 RcDoc::concat([
920 RcDoc::text(format!("{}{}", op, all_str)),
921 RcDoc::line(),
922 self.doc_set_expr(right),
923 ])
924 .nest(TAB)
925 .group(),
926 ])
927 }
928 SetExpr::Values(v) => self.doc_values(v),
929 SetExpr::Show(v) => self.doc_display(v, "SHOW"),
930 SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)),
931 }
932 .group()
933 }
934
935 fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values<T>) -> RcDoc<'a> {
936 let rows =
937 v.0.iter()
938 .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")"));
939 RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)])
940 .nest(TAB)
941 .group()
942 }
943
944 fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins<T>) -> RcDoc<'a> {
945 let mut docs = vec![self.doc_table_factor(&v.relation)];
946 for j in &v.joins {
947 docs.push(self.doc_join(j));
948 }
949 intersperse_line_nest(docs)
950 }
951
952 fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join<T>) -> RcDoc<'a> {
953 let (constraint, name) = match &v.join_operator {
954 JoinOperator::Inner(constraint) => (constraint, "JOIN"),
955 JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"),
956 JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"),
957 JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"),
958 _ => return self.doc_display(v, "join operator"),
959 };
960 let constraint = match constraint {
961 JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)),
962 JoinConstraint::Using { columns, alias } => {
963 let mut doc = bracket(
964 "USING(",
965 comma_separate(|c| self.doc_display_pass(c), columns),
966 ")",
967 );
968 if let Some(alias) = alias {
969 doc = nest(doc, nest_title("AS", self.doc_display_pass(alias)));
970 }
971 doc
972 }
973 _ => return self.doc_display(v, "join constraint"),
974 };
975 intersperse_line_nest([
976 RcDoc::text(name),
977 self.doc_table_factor(&v.relation),
978 constraint,
979 ])
980 }
981
982 fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor<T>) -> RcDoc<'a> {
983 match v {
984 TableFactor::Derived {
985 lateral,
986 subquery,
987 alias,
988 } => {
989 let prefix = if *lateral { "LATERAL (" } else { "(" };
990 let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")];
991 if let Some(alias) = alias {
992 docs.push(RcDoc::text(format!("AS {}", alias)));
993 }
994 intersperse_line_nest(docs)
995 }
996 TableFactor::NestedJoin { join, alias } => {
997 let mut doc = bracket("(", self.doc_table_with_joins(join), ")");
998 if let Some(alias) = alias {
999 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1000 }
1001 doc
1002 }
1003 TableFactor::Table { name, alias } => {
1004 let mut doc = self.doc_display_pass(name);
1005 if let Some(alias) = alias {
1006 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1007 }
1008 doc
1009 }
1010 _ => self.doc_display(v, "table factor variant"),
1011 }
1012 }
1013
1014 fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct<T>) -> RcDoc<'a> {
1015 match v {
1016 Distinct::EntireRow => RcDoc::text("DISTINCT"),
1017 Distinct::On(cols) => bracket(
1018 "DISTINCT ON (",
1019 comma_separate(|c| self.doc_expr(c), cols),
1020 ")",
1021 ),
1022 }
1023 }
1024
1025 fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select<T>) -> RcDoc<'a> {
1026 let mut docs = vec![];
1027 let mut select = RcDoc::text("SELECT");
1028 if let Some(distinct) = &v.distinct {
1029 select = nest(select, self.doc_distinct(distinct));
1030 }
1031 docs.push(nest_comma_separate(
1032 select,
1033 |s| self.doc_select_item(s),
1034 &v.projection,
1035 ));
1036 if !v.from.is_empty() {
1037 docs.push(title_comma_separate(
1038 "FROM",
1039 |t| self.doc_table_with_joins(t),
1040 &v.from,
1041 ));
1042 }
1043 if let Some(selection) = &v.selection {
1044 docs.push(nest_title("WHERE", self.doc_expr(selection)));
1045 }
1046 if !v.group_by.is_empty() {
1047 docs.push(title_comma_separate(
1048 "GROUP BY",
1049 |e| self.doc_expr(e),
1050 &v.group_by,
1051 ));
1052 }
1053 if let Some(having) = &v.having {
1054 docs.push(nest_title("HAVING", self.doc_expr(having)));
1055 }
1056 if let Some(qualify) = &v.qualify {
1057 docs.push(nest_title("QUALIFY", self.doc_expr(qualify)));
1058 }
1059 if !v.options.is_empty() {
1060 docs.push(bracket(
1061 "OPTIONS (",
1062 comma_separate(|o| self.doc_display_pass(o), &v.options),
1063 ")",
1064 ));
1065 }
1066 RcDoc::intersperse(docs, Doc::line()).group()
1067 }
1068
1069 fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem<T>) -> RcDoc<'a> {
1070 match v {
1071 SelectItem::Expr { expr, alias } => {
1072 let mut doc = self.doc_expr(expr);
1073 if let Some(alias) = alias {
1074 doc = nest(
1075 doc,
1076 RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]),
1077 );
1078 }
1079 doc
1080 }
1081 SelectItem::Wildcard => self.doc_display_pass(v),
1082 }
1083 }
1084
1085 pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr<T>) -> RcDoc<'a> {
1086 match v {
1087 Expr::Op { op, expr1, expr2 } => {
1088 if let Some(expr2) = expr2 {
1089 RcDoc::concat([
1090 self.doc_expr(expr1),
1091 RcDoc::line(),
1092 RcDoc::text(format!("{} ", op)),
1093 self.doc_expr(expr2).nest(TAB),
1094 ])
1095 } else {
1096 RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)])
1097 }
1098 }
1099 Expr::Case {
1100 operand,
1101 conditions,
1102 results,
1103 else_result,
1104 } => {
1105 let mut docs = Vec::new();
1106 if let Some(operand) = operand {
1107 docs.push(self.doc_expr(operand));
1108 }
1109 for (c, r) in conditions.iter().zip_eq(results) {
1110 let when = nest_title("WHEN", self.doc_expr(c));
1111 let then = nest_title("THEN", self.doc_expr(r));
1112 docs.push(nest(when, then));
1113 }
1114 if let Some(else_result) = else_result {
1115 docs.push(nest_title("ELSE", self.doc_expr(else_result)));
1116 }
1117 let doc = intersperse_line_nest(docs);
1118 bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line())
1119 }
1120 Expr::Cast { expr, data_type } => {
1121 let doc = self.doc_expr(expr);
1122 RcDoc::concat([
1123 doc,
1124 RcDoc::text(format!("::{}", data_type.to_ast_string_simple())),
1125 ])
1126 }
1127 Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"),
1128 Expr::Function(fun) => self.doc_function(fun),
1129 Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"),
1130 Expr::Identifier(_)
1131 | Expr::Value(_)
1132 | Expr::QualifiedWildcard(_)
1133 | Expr::WildcardAccess(_)
1134 | Expr::FieldAccess { .. } => self.doc_display_pass(v),
1135 Expr::And { left, right } => bracket_doc(
1136 self.doc_expr(left),
1137 RcDoc::text("AND"),
1138 self.doc_expr(right),
1139 RcDoc::line(),
1140 ),
1141 Expr::Or { left, right } => bracket_doc(
1142 self.doc_expr(left),
1143 RcDoc::text("OR"),
1144 self.doc_expr(right),
1145 RcDoc::line(),
1146 ),
1147 Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"),
1148 Expr::IsExpr {
1149 expr,
1150 negated,
1151 construct,
1152 } => bracket_doc(
1153 self.doc_expr(expr),
1154 RcDoc::text(if *negated { "IS NOT" } else { "IS" }),
1155 self.doc_display_pass(construct),
1156 RcDoc::line(),
1157 ),
1158 Expr::Not { expr } => {
1159 RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)])
1160 }
1161 Expr::Between {
1162 expr,
1163 negated,
1164 low,
1165 high,
1166 } => RcDoc::intersperse(
1167 [
1168 self.doc_expr(expr),
1169 RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }),
1170 RcDoc::intersperse(
1171 [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)],
1172 RcDoc::line(),
1173 )
1174 .group(),
1175 ],
1176 RcDoc::line(),
1177 ),
1178 Expr::InSubquery {
1179 expr,
1180 subquery,
1181 negated,
1182 } => RcDoc::intersperse(
1183 [
1184 self.doc_expr(expr),
1185 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1186 self.doc_query(subquery),
1187 RcDoc::text(")"),
1188 ],
1189 RcDoc::line(),
1190 ),
1191 Expr::InList {
1192 expr,
1193 list,
1194 negated,
1195 } => RcDoc::intersperse(
1196 [
1197 self.doc_expr(expr),
1198 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1199 comma_separate(|e| self.doc_expr(e), list),
1200 RcDoc::text(")"),
1201 ],
1202 RcDoc::line(),
1203 ),
1204 Expr::Row { exprs } => {
1205 bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")")
1206 }
1207 Expr::NullIf { l_expr, r_expr } => bracket(
1208 "NULLIF (",
1209 comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]),
1210 ")",
1211 ),
1212 Expr::HomogenizingFunction { function, exprs } => bracket(
1213 format!("{function}("),
1214 comma_separate(|e| self.doc_expr(e), exprs),
1215 ")",
1216 ),
1217 Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"),
1218 Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"),
1219 Expr::Array(exprs) => {
1220 bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]")
1221 }
1222 Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"),
1223 _ => self.doc_display(v, "expr variant"),
1224 }
1225 .group()
1226 }
1227
1228 fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function<T>) -> RcDoc<'a> {
1229 match &v.args {
1230 FunctionArgs::Star => self.doc_display_pass(v),
1231 FunctionArgs::Args { args, order_by } => {
1232 if args.is_empty() {
1233 return self.doc_display_pass(v);
1235 }
1236 if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() {
1237 return self.doc_display(v, "function filter or over or order by");
1238 }
1239 let special = match v.name.to_ast_string_stable().as_str() {
1240 r#""extract""# if v.args.len() == Some(2) => true,
1241 r#""position""# if v.args.len() == Some(2) => true,
1242 _ => false,
1243 };
1244 if special {
1245 return self.doc_display(v, "special function");
1246 }
1247 let name = format!(
1248 "{}({}",
1249 v.name.to_ast_string_simple(),
1250 if v.distinct { "DISTINCT " } else { "" }
1251 );
1252 bracket(name, comma_separate(|e| self.doc_expr(e), args), ")")
1253 }
1254 }
1255 }
1256}