1use crate::ast::*;
2use partiql_common::pretty::{
3 pretty_list, pretty_parenthesized_doc, pretty_prefixed_doc, pretty_seperated,
4 pretty_seperated_doc, pretty_seq, pretty_seq_doc, PrettyDoc, PRETTY_INDENT_MINOR_NEST,
5 PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST,
6};
7use pretty::{DocAllocator, DocBuilder};
8mod graph;
9
10impl<T> PrettyDoc for AstNode<T>
11where
12 T: PrettyDoc,
13{
14 #[inline]
15 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
16 where
17 D: DocAllocator<'b, A>,
18 D::Doc: Clone,
19 A: Clone,
20 {
21 self.node.pretty_doc(arena)
22 }
23}
24
25impl PrettyDoc for TopLevelQuery {
26 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
27 where
28 D: DocAllocator<'b, A>,
29 D::Doc: Clone,
30 A: Clone,
31 {
32 if self.with.is_some() {
33 todo!("WITH Clause")
34 }
35 self.query.pretty_doc(arena)
36 }
37}
38
39impl PrettyDoc for Query {
40 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
41 where
42 D: DocAllocator<'b, A>,
43 D::Doc: Clone,
44 A: Clone,
45 {
46 let Query {
47 set,
48 order_by,
49 limit_offset,
50 } = self;
51
52 let clauses = [
53 Some(set.pretty_doc(arena)),
54 order_by.as_ref().map(|inner| inner.pretty_doc(arena)),
55 limit_offset.as_ref().map(|inner| inner.pretty_doc(arena)),
56 ]
57 .into_iter()
58 .flatten();
59
60 arena.intersperse(clauses, arena.softline()).group()
61 }
62}
63
64impl PrettyDoc for QuerySet {
65 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
66 where
67 D: DocAllocator<'b, A>,
68 D::Doc: Clone,
69 A: Clone,
70 {
71 match self {
72 QuerySet::BagOp(op) => op.pretty_doc(arena),
73 QuerySet::Select(sel) => sel.pretty_doc(arena),
74 QuerySet::Expr(e) => e.pretty_doc(arena),
75 QuerySet::Values(v) => pretty_prefixed_doc("VALUES", pretty_list(v, 0, arena), arena),
76 QuerySet::Table(t) => pretty_prefixed_expr("TABLE", t, 0, arena),
77 }
78 }
79}
80
81impl PrettyDoc for BagOpExpr {
82 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
83 where
84 D: DocAllocator<'b, A>,
85 D::Doc: Clone,
86 A: Clone,
87 {
88 let op = match self.bag_op {
89 BagOperator::Union => "UNION",
90 BagOperator::Except => "EXCEPT",
91 BagOperator::Intersect => "INTERSECT",
92 BagOperator::OuterUnion => "OUTER UNION",
93 BagOperator::OuterExcept => "OUTER EXCEPT",
94 BagOperator::OuterIntersect => "OUTER INTERSECT",
95 };
96 let op = arena.text(op);
97 let op = match self.setq {
98 None => op,
99 Some(SetQuantifier::All) => op.append(" ALL"),
100 Some(SetQuantifier::Distinct) => op.append(" DISTINCT"),
101 };
102
103 let lhs = pretty_parenthesized_expr(&self.lhs, PRETTY_INDENT_MINOR_NEST, arena);
104 let rhs = pretty_parenthesized_expr(&self.rhs, PRETTY_INDENT_MINOR_NEST, arena);
105
106 arena.intersperse([lhs, op, rhs], arena.hardline()).group()
107 }
108}
109
110impl PrettyDoc for QueryTable {
111 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
112 where
113 D: DocAllocator<'b, A>,
114 D::Doc: Clone,
115 A: Clone,
116 {
117 self.table_name.pretty_doc(arena)
118 }
119}
120
121impl PrettyDoc for Select {
122 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
123 where
124 D: DocAllocator<'b, A>,
125 D::Doc: Clone,
126 A: Clone,
127 {
128 fn format<'b, C, D, A>(child: &'b C, arena: &'b D) -> DocBuilder<'b, D, A>
129 where
130 D: DocAllocator<'b, A>,
131 D::Doc: Clone,
132 A: Clone,
133 C: PrettyDoc,
134 {
135 child.pretty_doc(arena).group()
136 }
137
138 fn delegate<'b, C, D, A>(child: &'b Option<C>, arena: &'b D) -> Option<DocBuilder<'b, D, A>>
139 where
140 D: DocAllocator<'b, A>,
141 D::Doc: Clone,
142 A: Clone,
143 C: PrettyDoc,
144 {
145 child.as_ref().map(|inner| format(inner, arena))
146 }
147
148 let Select {
149 project,
150 exclude,
151 from,
152 from_let,
153 where_clause,
154 group_by,
155 having,
156 } = self;
157 let mut clauses = [
158 Some(format(project, arena)),
159 delegate(exclude, arena),
160 delegate(from, arena),
161 delegate(from_let, arena),
162 delegate(where_clause, arena),
163 delegate(group_by, arena),
164 delegate(having, arena),
165 ]
166 .into_iter()
167 .flatten();
168
169 let mut result = arena.nil();
170 let separator = arena.line();
171 if let Some(first) = clauses.next() {
172 let mut curr = first;
173
174 for clause in clauses {
175 result = result.append(curr.append(separator.clone()).group());
176 curr = clause;
177 }
178
179 result = result.append(curr);
180 }
181
182 result
183 }
184}
185
186impl PrettyDoc for Projection {
187 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
188 where
189 D: DocAllocator<'b, A>,
190 D::Doc: Clone,
191 A: Clone,
192 {
193 if self.setq.is_some() {
194 todo!("project SetQuantifier")
195 }
196 self.kind.pretty_doc(arena)
197 }
198}
199
200impl PrettyDoc for ProjectionKind {
201 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
202 where
203 D: DocAllocator<'b, A>,
204 D::Doc: Clone,
205 A: Clone,
206 {
207 match self {
208 ProjectionKind::ProjectStar => arena.text("SELECT *"),
209 ProjectionKind::ProjectList(l) => pretty_prefixed_doc(
210 "SELECT",
211 pretty_list(l, PRETTY_INDENT_MINOR_NEST, arena),
212 arena,
213 ),
214 ProjectionKind::ProjectPivot(ProjectPivot { key, value }) => {
215 let parts = [
216 value.pretty_doc(arena),
217 arena.text("AT"),
218 key.pretty_doc(arena),
219 ];
220 let decl = arena.intersperse(parts, arena.space()).group();
221 pretty_prefixed_doc("PIVOT", decl, arena)
222 }
223 ProjectionKind::ProjectValue(ctor) => {
224 pretty_prefixed_expr("SELECT VALUE", ctor, PRETTY_INDENT_MINOR_NEST, arena)
225 }
226 }
227 .group()
228 }
229}
230
231impl PrettyDoc for ProjectItem {
232 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
233 where
234 D: DocAllocator<'b, A>,
235 D::Doc: Clone,
236 A: Clone,
237 {
238 match self {
239 ProjectItem::ProjectAll(_) => {
240 todo!("ProjectItem::ProjectAll; remove this?")
241 }
242 ProjectItem::ProjectExpr(e) => e.pretty_doc(arena),
243 }
244 }
245}
246
247impl PrettyDoc for ProjectExpr {
248 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
249 where
250 D: DocAllocator<'b, A>,
251 D::Doc: Clone,
252 A: Clone,
253 {
254 pretty_source_as_alias(&self.expr, self.as_alias.as_ref(), arena)
255 .unwrap_or_else(|| self.expr.pretty_doc(arena))
256 }
257}
258
259impl PrettyDoc for Exclusion {
260 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
261 where
262 D: DocAllocator<'b, A>,
263 D::Doc: Clone,
264 A: Clone,
265 {
266 pretty_prefixed_doc(
267 "EXCLUDE",
268 pretty_list(&self.items, PRETTY_INDENT_MINOR_NEST, arena),
269 arena,
270 )
271 }
272}
273
274impl PrettyDoc for ExcludePath {
275 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
276 where
277 D: DocAllocator<'b, A>,
278 D::Doc: Clone,
279 A: Clone,
280 {
281 let ExcludePath { root, steps } = self;
282 let mut path = root.pretty_doc(arena);
283 for step in steps {
284 path = path.append(match step {
285 ExcludePathStep::PathProject(e) => arena.text(".").append(e.pretty_doc(arena)),
286 ExcludePathStep::PathIndex(e) => arena
287 .text("[")
288 .append(e.pretty_doc(arena))
289 .append(arena.text("]")),
290 ExcludePathStep::PathForEach => arena.text("[*]"),
291 ExcludePathStep::PathUnpivot => arena.text(".*"),
292 });
293 }
294
295 path
296 }
297}
298
299impl PrettyDoc for Expr {
300 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
301 where
302 D: DocAllocator<'b, A>,
303 D::Doc: Clone,
304 A: Clone,
305 {
306 match self {
307 Expr::Lit(inner) => inner.pretty_doc(arena),
308 Expr::VarRef(inner) => inner.pretty_doc(arena),
309 Expr::BinOp(inner) => inner.pretty_doc(arena),
310 Expr::UniOp(inner) => inner.pretty_doc(arena),
311 Expr::Like(inner) => inner.pretty_doc(arena),
312 Expr::Between(inner) => inner.pretty_doc(arena),
313 Expr::In(inner) => inner.pretty_doc(arena),
314 Expr::Case(inner) => inner.pretty_doc(arena),
315 Expr::Struct(inner) => inner.pretty_doc(arena),
316 Expr::Bag(inner) => inner.pretty_doc(arena),
317 Expr::List(inner) => inner.pretty_doc(arena),
318 Expr::Path(inner) => inner.pretty_doc(arena),
319 Expr::Call(inner) => inner.pretty_doc(arena),
320 Expr::CallAgg(inner) => inner.pretty_doc(arena),
321 Expr::GraphMatch(inner) => inner.pretty_doc(arena),
322 Expr::Query(inner) => {
323 let inner = inner.pretty_doc(arena).group();
324 arena
325 .text("(")
326 .append(inner.nest(PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST))
327 .append(arena.text(")"))
328 }
329 Expr::Error => {
330 unreachable!();
331 }
332 }
333 .group()
334 }
335}
336
337impl PrettyDoc for Path {
338 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
339 where
340 D: DocAllocator<'b, A>,
341 D::Doc: Clone,
342 A: Clone,
343 {
344 let Path { root, steps } = self;
345 let mut path = root.pretty_doc(arena);
346 for step in steps {
347 path = path.append(match step {
348 PathStep::PathProject(e) => arena.text(".").append(e.index.pretty_doc(arena)),
349 PathStep::PathIndex(e) => arena
350 .text("[")
351 .append(e.index.pretty_doc(arena))
352 .append(arena.text("]")),
353 PathStep::PathForEach => arena.text("[*]"),
354 PathStep::PathUnpivot => arena.text(".*"),
355 });
356 }
357
358 path
359 }
360}
361
362impl PrettyDoc for VarRef {
363 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
364 where
365 D: DocAllocator<'b, A>,
366 D::Doc: Clone,
367 A: Clone,
368 {
369 let name = self.name.pretty_doc(arena);
370 match self.qualifier {
371 ScopeQualifier::Unqualified => name,
372 ScopeQualifier::Qualified => arena.text("@").append(name).group(),
373 }
374 }
375}
376
377impl PrettyDoc for Lit {
378 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
379 where
380 D: DocAllocator<'b, A>,
381 D::Doc: Clone,
382 A: Clone,
383 {
384 match self {
385 Lit::Null => arena.text("NULL"),
386 Lit::Missing => arena.text("MISSING"),
387 Lit::Int8Lit(inner) => arena.text(inner.to_string()),
388 Lit::Int16Lit(inner) => arena.text(inner.to_string()),
389 Lit::Int32Lit(inner) => arena.text(inner.to_string()),
390 Lit::Int64Lit(inner) => arena.text(inner.to_string()),
391 Lit::DecimalLit(inner) => inner.pretty_doc(arena),
392 Lit::NumericLit(inner) => inner.pretty_doc(arena),
393 Lit::RealLit(inner) => arena.text(inner.to_string()),
394 Lit::FloatLit(inner) => arena.text(inner.to_string()),
395 Lit::DoubleLit(inner) => arena.text(inner.to_string()),
396 Lit::BoolLit(inner) => arena.text(inner.to_string()),
397 Lit::EmbeddedDocLit(inner, _typ) => inner.pretty_doc(arena), Lit::CharStringLit(inner) => inner.pretty_doc(arena),
399 Lit::NationalCharStringLit(inner) => inner.pretty_doc(arena),
400 Lit::BitStringLit(inner) => inner.pretty_doc(arena),
401 Lit::HexStringLit(inner) => inner.pretty_doc(arena),
402 Lit::StructLit(inner) => inner.pretty_doc(arena),
403 Lit::BagLit(inner) => inner.pretty_doc(arena),
404 Lit::ListLit(inner) => inner.pretty_doc(arena),
405 Lit::TypedLit(s, ty) => {
406 let ty = ty.pretty_doc(arena);
407 let s = s.pretty_doc(arena);
408 pretty_seperated_doc(arena.space(), [ty, s], 0, arena)
409 }
410 }
411 }
412}
413
414impl PrettyDoc for Type {
415 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
416 where
417 D: DocAllocator<'b, A>,
418 D::Doc: Clone,
419 A: Clone,
420 {
421 match self {
422 Type::CustomType(cty) => cty.pretty_doc(arena),
423 Type::NullType => arena.text("NULL"),
424 Type::BooleanType => arena.text("BOOL"),
425 Type::Integer2Type => arena.text("INT2"),
426 Type::Integer4Type => arena.text("INT4"),
427 Type::Integer8Type => arena.text("INT8"),
428 Type::DecimalType => arena.text("DECIMAL"),
429 Type::NumericType => arena.text("NUMERIC"),
430 Type::RealType => arena.text("REAL"),
431 Type::DoublePrecisionType => arena.text("DOUBLE PRECISION"),
432 Type::TimestampType => arena.text("TIMESTAMP"),
433 Type::CharacterType => arena.text("CHAR"),
434 Type::CharacterVaryingType => arena.text("VARCHAR"),
435 Type::MissingType => arena.text("MISSING"),
436 Type::StringType => arena.text("STRING"),
437 Type::SymbolType => arena.text("SYMBOL"),
438 Type::BlobType => arena.text("BLOB"),
439 Type::ClobType => arena.text("CLOB"),
440 Type::DateType => arena.text("DATE"),
441 Type::TimeType => arena.text("TIME"),
442 Type::ZonedTimestampType => arena.text("TIMESTAMPTZ"),
443 Type::StructType => arena.text("STRUCT"),
444 Type::TupleType => arena.text("TUPLE"),
445 Type::ListType => arena.text("LIST"),
446 Type::BagType => arena.text("BAG"),
447 Type::AnyType => arena.text("ANY"),
448 }
449 }
450}
451
452impl PrettyDoc for CustomType {
453 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
454 where
455 D: DocAllocator<'b, A>,
456 D::Doc: Clone,
457 A: Clone,
458 {
459 pretty_seperated(arena.space(), &self.parts, 0, arena)
460 }
461}
462
463impl PrettyDoc for CustomTypePart {
464 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
465 where
466 D: DocAllocator<'b, A>,
467 D::Doc: Clone,
468 A: Clone,
469 {
470 match self {
471 CustomTypePart::Name(sym) => sym.pretty_doc(arena),
472 CustomTypePart::Parameterized(sym, param) => {
473 let sym = sym.pretty_doc(arena);
474 let list = pretty_list(param, 0, arena);
475 let list = pretty_parenthesized_doc(list, arena);
476 sym.append(list)
477 }
478 }
479 }
480}
481
482impl PrettyDoc for CustomTypeParam {
483 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
484 where
485 D: DocAllocator<'b, A>,
486 D::Doc: Clone,
487 A: Clone,
488 {
489 match self {
490 CustomTypeParam::Lit(l) => l.pretty_doc(arena),
491 CustomTypeParam::Type(ty) => ty.pretty_doc(arena),
492 }
493 }
494}
495
496impl PrettyDoc for BinOp {
497 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
498 where
499 D: DocAllocator<'b, A>,
500 D::Doc: Clone,
501 A: Clone,
502 {
503 let BinOp { kind, lhs, rhs } = self;
504 let (nest, sym) = match kind {
505 BinOpKind::Add => (0, "+"),
506 BinOpKind::Div => (0, "/"),
507 BinOpKind::Exp => (0, "^"),
508 BinOpKind::Mod => (0, "%"),
509 BinOpKind::Mul => (0, "*"),
510 BinOpKind::Sub => (0, "-"),
511 BinOpKind::And => (PRETTY_INDENT_MINOR_NEST, "AND"),
512 BinOpKind::Or => (PRETTY_INDENT_MINOR_NEST, "OR"),
513 BinOpKind::Concat => (0, "||"),
514 BinOpKind::Eq => (0, "="),
515 BinOpKind::Gt => (0, ">"),
516 BinOpKind::Gte => (0, ">="),
517 BinOpKind::Lt => (0, "<"),
518 BinOpKind::Lte => (0, "<="),
519 BinOpKind::Ne => (0, "<>"),
520 BinOpKind::Is => (0, "IS"),
521 };
522 let op = arena.text(sym);
523 let lhs = lhs.pretty_doc(arena).nest(nest);
524 let rhs = rhs.pretty_doc(arena).nest(nest);
525 let sep = if nest == 0 {
526 arena.space()
527 } else {
528 arena.softline()
529 };
530 let expr = arena.intersperse([lhs, op, rhs], sep).group();
531 pretty_parenthesized_doc(expr, arena).group()
532 }
533}
534
535impl PrettyDoc for UniOp {
536 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
537 where
538 D: DocAllocator<'b, A>,
539 D::Doc: Clone,
540 A: Clone,
541 {
542 let UniOp { kind, expr } = self;
544 let (sym, paren) = match kind {
545 UniOpKind::Pos => ("+", false),
546 UniOpKind::Neg => ("-", false),
547 UniOpKind::Not => ("NOT ", true),
548 };
549 let op = arena.text(sym);
550 let expr = expr.pretty_doc(arena);
551 if paren {
552 let open = arena.text("(");
553 let close = arena.text(")");
554 arena.concat([op, open, expr, close]).group()
555 } else {
556 arena.concat([op, expr]).group()
557 }
558 }
559}
560
561impl PrettyDoc for Like {
562 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
563 where
564 D: DocAllocator<'b, A>,
565 D::Doc: Clone,
566 A: Clone,
567 {
568 let Like {
569 value,
570 pattern,
571 escape,
572 } = self;
573
574 let sep = arena.space();
575 let value = value.pretty_doc(arena);
576 let kw_like = arena.text("LIKE");
577 let pattern = pattern.pretty_doc(arena);
578 if let Some(escape) = escape {
579 let kw_esc = arena.text("ESCAPE");
580 let escape = escape.pretty_doc(arena);
581 arena.intersperse([value, kw_like, pattern, kw_esc, escape], sep)
582 } else {
583 arena.intersperse([value, kw_like, pattern], sep)
584 }
585 .group()
586 }
587}
588
589impl PrettyDoc for Between {
590 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
591 where
592 D: DocAllocator<'b, A>,
593 D::Doc: Clone,
594 A: Clone,
595 {
596 let Between { value, from, to } = self;
597
598 let value = value.pretty_doc(arena);
599 let kw_b = arena.text("BETWEEN");
600 let kw_a = arena.text("AND");
601 let from = from.pretty_doc(arena);
602 let to = to.pretty_doc(arena);
603 let sep = arena.space();
604 let expr = arena
605 .intersperse([value, kw_b, from, kw_a, to], sep)
606 .group();
607 expr.group()
608 }
609}
610
611impl PrettyDoc for In {
612 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
613 where
614 D: DocAllocator<'b, A>,
615 D::Doc: Clone,
616 A: Clone,
617 {
618 let In { lhs, rhs } = self;
619
620 let kw_in = arena.text("IN");
621 let lhs = lhs.pretty_doc(arena);
622 let rhs = rhs.pretty_doc(arena);
623 let sep = arena.space();
624 let expr = arena.intersperse([lhs, kw_in, rhs], sep).group();
625 expr.group()
626 }
627}
628
629impl PrettyDoc for Case {
630 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
631 where
632 D: DocAllocator<'b, A>,
633 D::Doc: Clone,
634 A: Clone,
635 {
636 match self {
637 Case::SimpleCase(inner) => inner.pretty_doc(arena),
638 Case::SearchedCase(inner) => inner.pretty_doc(arena),
639 }
640 }
641}
642
643impl PrettyDoc for SimpleCase {
644 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
645 where
646 D: DocAllocator<'b, A>,
647 D::Doc: Clone,
648 A: Clone,
649 {
650 let SimpleCase {
651 expr,
652 cases,
653 default,
654 } = self;
655
656 let search = expr.pretty_doc(arena);
657 let branches = case_branches(arena, cases, default);
658 pretty_seq_doc(
659 branches,
660 "CASE",
661 Some(search),
662 "END",
663 " ",
664 PRETTY_INDENT_MINOR_NEST,
665 arena,
666 )
667 }
668}
669
670impl PrettyDoc for SearchedCase {
671 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
672 where
673 D: DocAllocator<'b, A>,
674 D::Doc: Clone,
675 A: Clone,
676 {
677 let SearchedCase { cases, default } = self;
678
679 let branches = case_branches(arena, cases, default);
680 pretty_seq_doc(
681 branches,
682 "CASE",
683 None,
684 "END",
685 " ",
686 PRETTY_INDENT_MINOR_NEST,
687 arena,
688 )
689 }
690}
691
692impl PrettyDoc for Struct {
693 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
694 where
695 D: DocAllocator<'b, A>,
696 D::Doc: Clone,
697 A: Clone,
698 {
699 let fields = self.fields.iter().map(|expr_pair| {
700 let k = expr_pair.first.pretty_doc(arena);
701 let v = expr_pair.second.pretty_doc(arena);
702 let sep = arena.text(": ");
703
704 k.append(sep).group().append(v).group()
705 });
706 pretty_seq_doc(fields, "{", None, "}", ",", PRETTY_INDENT_MINOR_NEST, arena)
707 }
708}
709
710impl PrettyDoc for StructLit {
711 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
712 where
713 D: DocAllocator<'b, A>,
714 D::Doc: Clone,
715 A: Clone,
716 {
717 let fields = self.fields.iter().map(|expr_pair| {
718 let k = expr_pair.first.pretty_doc(arena);
719 let v = expr_pair.second.pretty_doc(arena);
720 let sep = arena.text(": ");
721
722 k.append(sep).group().append(v).group()
723 });
724 pretty_seq_doc(fields, "{", None, "}", ",", PRETTY_INDENT_MINOR_NEST, arena)
725 }
726}
727
728impl PrettyDoc for Bag {
729 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
730 where
731 D: DocAllocator<'b, A>,
732 D::Doc: Clone,
733 A: Clone,
734 {
735 pretty_seq(
736 &self.values,
737 "<<",
738 ">>",
739 ",",
740 PRETTY_INDENT_MINOR_NEST,
741 arena,
742 )
743 }
744}
745
746impl PrettyDoc for List {
747 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
748 where
749 D: DocAllocator<'b, A>,
750 D::Doc: Clone,
751 A: Clone,
752 {
753 pretty_seq(&self.values, "[", "]", ",", PRETTY_INDENT_MINOR_NEST, arena)
754 }
755}
756
757impl PrettyDoc for BagLit {
758 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
759 where
760 D: DocAllocator<'b, A>,
761 D::Doc: Clone,
762 A: Clone,
763 {
764 pretty_seq(
765 &self.values,
766 "<<",
767 ">>",
768 ",",
769 PRETTY_INDENT_MINOR_NEST,
770 arena,
771 )
772 }
773}
774
775impl PrettyDoc for ListLit {
776 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
777 where
778 D: DocAllocator<'b, A>,
779 D::Doc: Clone,
780 A: Clone,
781 {
782 pretty_seq(&self.values, "[", "]", ",", PRETTY_INDENT_MINOR_NEST, arena)
783 }
784}
785
786impl PrettyDoc for Call {
787 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
788 where
789 D: DocAllocator<'b, A>,
790 D::Doc: Clone,
791 A: Clone,
792 {
793 let name = self.func_name.pretty_doc(arena);
794 let list = pretty_list(&self.args, 0, arena);
795 name.append(arena.text("("))
796 .append(list.nest(PRETTY_INDENT_MINOR_NEST))
797 .append(arena.text(")"))
798 }
799}
800
801impl PrettyDoc for CallAgg {
802 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
803 where
804 D: DocAllocator<'b, A>,
805 D::Doc: Clone,
806 A: Clone,
807 {
808 let name = self.func_name.pretty_doc(arena);
809 let list = pretty_list(&self.args, 0, arena);
810 name.append(arena.text("("))
811 .append(list.nest(PRETTY_INDENT_MINOR_NEST))
812 .append(arena.text(")"))
813 }
814}
815
816impl PrettyDoc for CallArg {
817 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
818 where
819 D: DocAllocator<'b, A>,
820 D::Doc: Clone,
821 A: Clone,
822 {
823 match self {
824 CallArg::Star() => arena.text("*"),
825 CallArg::Positional(arg) => arg.pretty_doc(arena),
826 CallArg::PositionalType(_) => {
827 todo!("CallArg::PositionalType")
828 }
829 CallArg::Named(arg) => arg.pretty_doc(arena),
830 CallArg::NamedType(_) => {
831 todo!("CallArg::NamedType")
832 }
833 }
834 }
835}
836
837impl PrettyDoc for CallArgNamed {
838 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
839 where
840 D: DocAllocator<'b, A>,
841 D::Doc: Clone,
842 A: Clone,
843 {
844 let CallArgNamed { name, value } = self;
845 let name = name.pretty_doc(arena);
846 let value = value.pretty_doc(arena);
847 pretty_seperated_doc(":", [name, value], 0, arena)
848 }
849}
850
851impl PrettyDoc for SymbolPrimitive {
852 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
853 where
854 D: DocAllocator<'b, A>,
855 D::Doc: Clone,
856 A: Clone,
857 {
858 let sym = arena.text(self.value.as_str());
859 match self.case {
860 CaseSensitivity::CaseSensitive => arena.text("\"").append(sym).append(arena.text("\"")),
861 CaseSensitivity::CaseInsensitive => sym,
862 }
863 }
864}
865
866impl PrettyDoc for FromClause {
867 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
868 where
869 D: DocAllocator<'b, A>,
870 D::Doc: Clone,
871 A: Clone,
872 {
873 pretty_prefixed_expr("FROM", &self.source, PRETTY_INDENT_MINOR_NEST, arena)
874 }
875}
876
877impl PrettyDoc for FromSource {
878 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
879 where
880 D: DocAllocator<'b, A>,
881 D::Doc: Clone,
882 A: Clone,
883 {
884 match self {
885 FromSource::FromLet(fl) => fl.pretty_doc(arena),
886 FromSource::Join(join) => join.pretty_doc(arena),
887 }
888 }
889}
890
891impl PrettyDoc for FromLet {
892 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
893 where
894 D: DocAllocator<'b, A>,
895 D::Doc: Clone,
896 A: Clone,
897 {
898 let FromLet {
899 expr,
900 kind,
901 as_alias,
902 at_alias,
903 by_alias,
904 } = self;
905
906 let expr = expr.pretty_doc(arena);
907 let as_alias = pretty_as_alias(as_alias.as_ref(), arena);
908 let at_alias = pretty_at_alias(at_alias.as_ref(), arena);
909 let by_alias = pretty_by_alias(by_alias.as_ref(), arena);
910 let aliases: Vec<_> = [as_alias, at_alias, by_alias]
911 .into_iter()
912 .flatten()
913 .collect();
914
915 let clause = match kind {
916 FromLetKind::Scan => expr,
917 FromLetKind::Unpivot => pretty_prefixed_doc("UNPIVOT", expr, arena),
918 FromLetKind::GraphTable => pretty_prefixed_doc("GRAPH_TABLE", expr, arena),
919 };
920
921 if aliases.is_empty() {
922 clause
923 } else {
924 clause.append(arena.concat(aliases).group())
925 }
926 .group()
927 }
928}
929
930impl PrettyDoc for Join {
931 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
932 where
933 D: DocAllocator<'b, A>,
934 D::Doc: Clone,
935 A: Clone,
936 {
937 let Join {
938 kind,
939 left,
940 right,
941 predicate,
942 } = self;
943
944 let arms = [left.as_ref(), right.as_ref()];
945 let kw_join = match kind {
946 JoinKind::Cross => " CROSS JOIN ",
947 JoinKind::Inner => " INNER JOIN ",
948 JoinKind::Left => " LEFT JOIN ",
949 JoinKind::Right => " RIGHT JOIN ",
950 JoinKind::Full => " FULL JOIN ",
951 };
952
953 match (kind, predicate) {
954 (JoinKind::Cross, Some(_)) => {
955 todo!("CROSS JOIN with predicate")
956 }
957 (JoinKind::Cross, None) => pretty_list(arms, 0, arena),
958 (_, None) => pretty_seperated(kw_join, arms, 0, arena),
959 (_, Some(pred)) => match &pred.node {
960 JoinSpec::Natural => {
961 let kw = arena.text(" NATURAL").append(kw_join);
962 pretty_seperated(kw, arms, 0, arena)
963 }
964 JoinSpec::On(on) => {
965 let join = pretty_seperated(kw_join, arms, 0, arena);
966 let pred = arena
967 .softline()
968 .append(arena.text("ON"))
969 .append(arena.softline())
970 .append(on.pretty_doc(arena).nest(PRETTY_INDENT_MINOR_NEST));
971 join.append(pred)
972 }
973 JoinSpec::Using(using) => {
974 let join = pretty_seperated(kw_join, arms, 0, arena);
975 let using = pretty_list(using, PRETTY_INDENT_MINOR_NEST, arena);
976 let pred = arena
977 .softline()
978 .append(arena.text("USING"))
979 .append(arena.softline())
980 .append(using);
981 join.append(pred)
982 }
983 },
984 }
985 .group()
986 }
987}
988
989impl PrettyDoc for Let {
990 fn pretty_doc<'b, D, A>(&'b self, _arena: &'b D) -> DocBuilder<'b, D, A>
991 where
992 D: DocAllocator<'b, A>,
993 D::Doc: Clone,
994 A: Clone,
995 {
996 todo!("LET")
997 }
998}
999
1000impl PrettyDoc for WhereClause {
1001 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1002 where
1003 D: DocAllocator<'b, A>,
1004 D::Doc: Clone,
1005 A: Clone,
1006 {
1007 pretty_prefixed_expr("WHERE", &self.expr, PRETTY_INDENT_MINOR_NEST, arena)
1008 }
1009}
1010
1011impl PrettyDoc for GroupByExpr {
1012 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1013 where
1014 D: DocAllocator<'b, A>,
1015 D::Doc: Clone,
1016 A: Clone,
1017 {
1018 let GroupByExpr {
1019 strategy,
1020 keys,
1021 group_as_alias,
1022 } = self;
1023
1024 let mut doc = match strategy {
1025 None => arena.text("GROUP"),
1026 Some(GroupingStrategy::GroupFull) => arena.text("GROUP ALL"),
1027 Some(GroupingStrategy::GroupPartial) => arena.text("GROUP PARTIAL"),
1028 };
1029
1030 if !keys.is_empty() {
1031 doc = doc.append(arena.space()).append(arena.text("BY")).group();
1032 doc = doc.append(arena.softline()).append(pretty_list(
1033 keys,
1034 PRETTY_INDENT_MINOR_NEST,
1035 arena,
1036 ));
1037 }
1038
1039 match group_as_alias {
1040 None => doc,
1041 Some(gas) => {
1042 let gas = pretty_source_as_alias("GROUP", Some(gas), arena);
1043 doc.append(gas)
1044 }
1045 }
1046 .group()
1047 }
1048}
1049
1050impl PrettyDoc for GroupKey {
1051 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1052 where
1053 D: DocAllocator<'b, A>,
1054 D::Doc: Clone,
1055 A: Clone,
1056 {
1057 pretty_source_as_alias(&self.expr, self.as_alias.as_ref(), arena)
1058 .unwrap_or_else(|| self.expr.pretty_doc(arena))
1059 }
1060}
1061
1062impl PrettyDoc for HavingClause {
1063 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1064 where
1065 D: DocAllocator<'b, A>,
1066 D::Doc: Clone,
1067 A: Clone,
1068 {
1069 pretty_prefixed_expr("HAVING", &self.expr, PRETTY_INDENT_MINOR_NEST, arena)
1070 }
1071}
1072
1073impl PrettyDoc for OrderByExpr {
1074 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1075 where
1076 D: DocAllocator<'b, A>,
1077 D::Doc: Clone,
1078 A: Clone,
1079 {
1080 if self.sort_specs.is_empty() {
1081 arena.text("ORDER BY PRESERVE")
1082 } else {
1083 pretty_prefixed_doc(
1084 "ORDER BY",
1085 pretty_list(&self.sort_specs, PRETTY_INDENT_MINOR_NEST, arena),
1086 arena,
1087 )
1088 }
1089 .group()
1090 }
1091}
1092
1093impl PrettyDoc for SortSpec {
1094 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1095 where
1096 D: DocAllocator<'b, A>,
1097 D::Doc: Clone,
1098 A: Clone,
1099 {
1100 let SortSpec {
1101 expr,
1102 ordering_spec,
1103 null_ordering_spec,
1104 } = self;
1105 let mut doc = expr.pretty_doc(arena);
1106 if let Some(os) = ordering_spec {
1107 let os = arena.space().append(os.pretty_doc(arena)).group();
1108 doc = doc.append(os)
1109 };
1110 if let Some(nos) = null_ordering_spec {
1111 let nos = arena.space().append(nos.pretty_doc(arena)).group();
1112 doc = doc.append(nos)
1113 };
1114
1115 doc.group()
1116 }
1117}
1118
1119impl PrettyDoc for OrderingSpec {
1120 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1121 where
1122 D: DocAllocator<'b, A>,
1123 D::Doc: Clone,
1124 A: Clone,
1125 {
1126 arena.text(match self {
1127 OrderingSpec::Asc => "ASC",
1128 OrderingSpec::Desc => "DESC",
1129 })
1130 }
1131}
1132
1133impl PrettyDoc for NullOrderingSpec {
1134 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1135 where
1136 D: DocAllocator<'b, A>,
1137 D::Doc: Clone,
1138 A: Clone,
1139 {
1140 arena.text(match self {
1141 NullOrderingSpec::First => "NULLS FIRST",
1142 NullOrderingSpec::Last => "NULLS LAST",
1143 })
1144 }
1145}
1146
1147impl PrettyDoc for LimitOffsetClause {
1148 fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
1149 where
1150 D: DocAllocator<'b, A>,
1151 D::Doc: Clone,
1152 A: Clone,
1153 {
1154 let limit = self
1155 .limit
1156 .as_ref()
1157 .map(|l| pretty_prefixed_expr("LIMIT", l, PRETTY_INDENT_MINOR_NEST, arena));
1158
1159 let offset = self
1160 .offset
1161 .as_ref()
1162 .map(|o| pretty_prefixed_expr("OFFSET", o, PRETTY_INDENT_MINOR_NEST, arena));
1163
1164 match (limit, offset) {
1165 (None, None) => unreachable!(),
1166 (Some(limit), None) => limit,
1167 (None, Some(offset)) => offset,
1168 (Some(limit), Some(offset)) => limit.append(arena.softline()).append(offset),
1169 }
1170 }
1171}
1172
1173fn case_branches<'b, D, A>(
1174 arena: &'b D,
1175 cases: &'b [ExprPair],
1176 default: &'b Option<Box<Expr>>,
1177) -> impl Iterator<Item = DocBuilder<'b, D, A>>
1178where
1179 D: DocAllocator<'b, A>,
1180 D::Doc: Clone,
1181 A: Clone + 'b,
1182{
1183 cases
1184 .iter()
1185 .map(|ExprPair { first, second }| {
1186 let kw_when = arena.text("WHEN");
1187 let test = first.pretty_doc(arena);
1188 let kw_then = arena.text("THEN");
1189 let then = second.pretty_doc(arena);
1190 arena
1191 .intersperse([kw_when, test, kw_then, then], arena.space())
1192 .group()
1193 })
1194 .chain(
1195 default
1196 .iter()
1197 .map(|d| arena.text("ELSE ").append(d.pretty_doc(arena)).group()),
1198 )
1199}
1200
1201fn pretty_prefixed_expr<'b, P, D, A>(
1202 annot: &'static str,
1203 expr: &'b P,
1204 nest: isize,
1205 arena: &'b D,
1206) -> DocBuilder<'b, D, A>
1207where
1208 P: PrettyDoc,
1209 D: DocAllocator<'b, A>,
1210 D::Doc: Clone,
1211 A: Clone,
1212{
1213 pretty_prefixed_doc(annot, expr.pretty_doc(arena).nest(nest), arena)
1214}
1215
1216fn pretty_parenthesized_expr<'b, P, D, A>(
1217 expr: &'b P,
1218 nest: isize,
1219 arena: &'b D,
1220) -> DocBuilder<'b, D, A>
1221where
1222 P: PrettyDoc,
1223 D: DocAllocator<'b, A>,
1224 D::Doc: Clone,
1225 A: Clone,
1226{
1227 pretty_parenthesized_doc(expr.pretty_doc(arena).nest(nest), arena)
1228}
1229
1230fn pretty_alias_helper<'b, D, A>(
1231 kw: &'static str,
1232 sym: Option<&'b SymbolPrimitive>,
1233 arena: &'b D,
1234) -> Option<DocBuilder<'b, D, A>>
1235where
1236 D: DocAllocator<'b, A>,
1237 D::Doc: Clone,
1238 A: Clone,
1239{
1240 sym.map(|sym| {
1241 arena
1242 .space()
1243 .append(arena.text(kw))
1244 .append(arena.space())
1245 .append(sym.pretty_doc(arena))
1246 .group()
1247 })
1248}
1249
1250fn pretty_source_as_alias<'b, S, D, A>(
1251 source: &'b S,
1252 as_alias: Option<&'b SymbolPrimitive>,
1253 arena: &'b D,
1254) -> Option<DocBuilder<'b, D, A>>
1255where
1256 S: PrettyDoc + ?Sized,
1257 D: DocAllocator<'b, A>,
1258 D::Doc: Clone,
1259 A: Clone,
1260{
1261 pretty_as_alias(as_alias, arena).map(|alias| {
1262 let expr = source.pretty_doc(arena);
1263 arena.concat([expr, alias]).group()
1264 })
1265}
1266
1267fn pretty_as_alias<'b, D, A>(
1268 sym: Option<&'b SymbolPrimitive>,
1269 arena: &'b D,
1270) -> Option<DocBuilder<'b, D, A>>
1271where
1272 D: DocAllocator<'b, A>,
1273 D::Doc: Clone,
1274 A: Clone,
1275{
1276 pretty_alias_helper("AS", sym, arena)
1277}
1278
1279fn pretty_at_alias<'b, D, A>(
1280 sym: Option<&'b SymbolPrimitive>,
1281 arena: &'b D,
1282) -> Option<DocBuilder<'b, D, A>>
1283where
1284 D: DocAllocator<'b, A>,
1285 D::Doc: Clone,
1286 A: Clone,
1287{
1288 pretty_alias_helper("AT", sym, arena)
1289}
1290
1291fn pretty_by_alias<'b, D, A>(
1292 sym: Option<&'b SymbolPrimitive>,
1293 arena: &'b D,
1294) -> Option<DocBuilder<'b, D, A>>
1295where
1296 D: DocAllocator<'b, A>,
1297 D::Doc: Clone,
1298 A: Clone,
1299{
1300 pretty_alias_helper("BY", sym, arena)
1301}