1#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, vec::Vec};
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19use crate::ast::*;
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Query {
26 pub with: Option<With>,
28 pub body: SetExpr,
30 pub order_by: Vec<OrderByExpr>,
32 pub limit: Option<Expr>,
34 pub offset: Option<String>,
39 pub fetch: Option<Fetch>,
44}
45
46impl Query {
47 pub fn as_simple_values(&self) -> Option<&Values> {
49 match &self {
50 Query {
51 with: None,
52 body: SetExpr::Values(values),
53 order_by,
54 limit: None,
55 offset: None,
56 fetch: None,
57 } if order_by.is_empty() => Some(values),
58 _ => None,
59 }
60 }
61
62 pub fn as_single_select_item(&self) -> Option<&Expr> {
64 match &self {
65 Query {
66 with: None,
67 body: SetExpr::Select(select),
68 order_by,
69 limit: None,
70 offset: None,
71 fetch: None,
72 } if order_by.is_empty() => match select.as_ref() {
73 Select {
74 distinct: Distinct::All,
75 projection,
76 from,
77 lateral_views,
78 selection: None,
79 group_by,
80 having: None,
81 window,
82 } if projection.len() == 1
83 && from.is_empty()
84 && lateral_views.is_empty()
85 && group_by.is_empty()
86 && window.is_empty() =>
87 {
88 match &projection[0] {
89 SelectItem::UnnamedExpr(expr) => Some(expr),
90 SelectItem::ExprWithAlias { expr, .. } => Some(expr),
91 _ => None,
92 }
93 }
94 _ => None,
95 },
96 _ => None,
97 }
98 }
99}
100
101impl fmt::Display for Query {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 if let Some(ref with) = self.with {
104 write!(f, "{} ", with)?;
105 }
106 write!(f, "{}", self.body)?;
107 if !self.order_by.is_empty() {
108 write!(f, " ORDER BY {}", display_comma_separated(&self.order_by))?;
109 }
110 if let Some(ref limit) = self.limit {
111 write!(f, " LIMIT {}", limit)?;
112 }
113 if let Some(ref offset) = self.offset {
114 write!(f, " OFFSET {}", offset)?;
115 }
116 if let Some(ref fetch) = self.fetch {
117 write!(f, " {}", fetch)?;
118 }
119 Ok(())
120 }
121}
122
123#[allow(clippy::large_enum_variant)]
126#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub enum SetExpr {
129 Select(Box<Select>),
131 Query(Box<Query>),
134 SetOperation {
136 op: SetOperator,
137 all: bool,
138 corresponding: Corresponding,
139 left: Box<SetExpr>,
140 right: Box<SetExpr>,
141 },
142 Values(Values),
143}
144
145impl fmt::Display for SetExpr {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match self {
148 SetExpr::Select(s) => write!(f, "{}", s),
149 SetExpr::Query(q) => write!(f, "({})", q),
150 SetExpr::Values(v) => write!(f, "{}", v),
151 SetExpr::SetOperation {
152 left,
153 right,
154 op,
155 all,
156 corresponding,
157 } => {
158 let all_str = if *all { " ALL" } else { "" };
159 write!(f, "{} {}{}{} {}", left, op, all_str, corresponding, right)
160 }
161 }
162 }
163}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
167pub enum SetOperator {
168 Union,
169 Except,
170 Intersect,
171}
172
173impl fmt::Display for SetOperator {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.write_str(match self {
176 SetOperator::Union => "UNION",
177 SetOperator::Except => "EXCEPT",
178 SetOperator::Intersect => "INTERSECT",
179 })
180 }
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
185pub struct Corresponding {
187 pub corresponding: bool,
188 pub column_list: Option<Vec<Ident>>,
189}
190
191impl Corresponding {
192 pub fn with_column_list(column_list: Option<Vec<Ident>>) -> Self {
193 Self {
194 corresponding: true,
195 column_list,
196 }
197 }
198
199 pub fn none() -> Self {
200 Self {
201 corresponding: false,
202 column_list: None,
203 }
204 }
205
206 pub fn is_corresponding(&self) -> bool {
207 self.corresponding
208 }
209
210 pub fn column_list(&self) -> Option<&[Ident]> {
211 self.column_list.as_deref()
212 }
213}
214
215impl fmt::Display for Corresponding {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 if self.corresponding {
218 write!(f, " CORRESPONDING")?;
219 if let Some(column_list) = &self.column_list {
220 write!(f, " BY ({})", display_comma_separated(column_list))?;
221 }
222 }
223 Ok(())
224 }
225}
226
227#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
231#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
232pub struct Select {
233 pub distinct: Distinct,
234 pub projection: Vec<SelectItem>,
236 pub from: Vec<TableWithJoins>,
238 pub lateral_views: Vec<LateralView>,
240 pub selection: Option<Expr>,
242 pub group_by: Vec<Expr>,
244 pub having: Option<Expr>,
246 pub window: Vec<NamedWindow>,
248}
249
250impl fmt::Display for Select {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 write!(f, "SELECT{}", &self.distinct)?;
253 write!(f, " {}", display_comma_separated(&self.projection))?;
254 if !self.from.is_empty() {
255 write!(f, " FROM {}", display_comma_separated(&self.from))?;
256 }
257 if !self.lateral_views.is_empty() {
258 for lv in &self.lateral_views {
259 write!(f, "{}", lv)?;
260 }
261 }
262 if let Some(ref selection) = self.selection {
263 write!(f, " WHERE {}", selection)?;
264 }
265 if !self.group_by.is_empty() {
266 write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
267 }
268 if let Some(ref having) = self.having {
269 write!(f, " HAVING {}", having)?;
270 }
271 if !self.window.is_empty() {
272 write!(f, " WINDOW {}", display_comma_separated(&self.window))?;
273 }
274 Ok(())
275 }
276}
277
278#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281#[expect(clippy::enum_variant_names)]
282pub enum Distinct {
283 #[default]
285 All,
286 Distinct,
288 DistinctOn(Vec<Expr>),
290}
291
292impl Distinct {
293 pub const fn is_all(&self) -> bool {
294 matches!(self, Distinct::All)
295 }
296
297 pub const fn is_distinct(&self) -> bool {
298 matches!(self, Distinct::Distinct)
299 }
300}
301
302impl fmt::Display for Distinct {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 match self {
305 Distinct::All => write!(f, ""),
306 Distinct::Distinct => write!(f, " DISTINCT"),
307 Distinct::DistinctOn(exprs) => {
308 write!(f, " DISTINCT ON ({})", display_comma_separated(exprs))
309 }
310 }
311 }
312}
313
314#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317pub struct LateralView {
318 pub lateral_view: Expr,
320 pub lateral_view_name: ObjectName,
322 pub lateral_col_alias: Vec<Ident>,
324 pub outer: bool,
326}
327
328impl fmt::Display for LateralView {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 write!(
331 f,
332 " LATERAL VIEW{outer} {} {}",
333 self.lateral_view,
334 self.lateral_view_name,
335 outer = if self.outer { " OUTER" } else { "" }
336 )?;
337 if !self.lateral_col_alias.is_empty() {
338 write!(
339 f,
340 " AS {}",
341 display_comma_separated(&self.lateral_col_alias)
342 )?;
343 }
344 Ok(())
345 }
346}
347
348#[derive(Debug, Clone, PartialEq, Eq, Hash)]
349#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
350pub struct With {
351 pub recursive: bool,
352 pub cte_tables: Vec<Cte>,
353}
354
355impl fmt::Display for With {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 write!(
358 f,
359 "WITH {}{}",
360 if self.recursive { "RECURSIVE " } else { "" },
361 display_comma_separated(&self.cte_tables)
362 )
363 }
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Hash)]
372#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
373pub struct Cte {
374 pub alias: TableAlias,
375 pub cte_inner: CteInner,
376}
377
378impl fmt::Display for Cte {
379 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380 match &self.cte_inner {
381 CteInner::Query(query) => write!(f, "{} AS ({})", self.alias, query)?,
382 CteInner::ChangeLog(obj_name) => {
383 write!(f, "{} AS changelog from {}", self.alias, obj_name)?
384 }
385 }
386 Ok(())
387 }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq, Hash)]
391#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
392pub enum CteInner {
393 Query(Box<Query>),
394 ChangeLog(ObjectName),
395}
396
397#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
400pub enum SelectItem {
401 UnnamedExpr(Expr),
403 ExprQualifiedWildcard(Expr, Vec<Ident>),
407 ExprWithAlias { expr: Expr, alias: Ident },
409 QualifiedWildcard(ObjectName, Option<Vec<Expr>>),
411 Wildcard(Option<Vec<Expr>>),
413}
414
415impl fmt::Display for SelectItem {
416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417 match &self {
418 SelectItem::UnnamedExpr(expr) => write!(f, "{}", expr),
419 SelectItem::ExprWithAlias { expr, alias } => write!(f, "{} AS {}", expr, alias),
420 SelectItem::ExprQualifiedWildcard(expr, prefix) => write!(
421 f,
422 "({}){}.*",
423 expr,
424 prefix
425 .iter()
426 .format_with("", |i, f| f(&format_args!(".{i}")))
427 ),
428 SelectItem::QualifiedWildcard(prefix, except) => match except {
429 Some(cols) => write!(
430 f,
431 "{}.* EXCEPT ({})",
432 prefix,
433 cols.iter()
434 .map(|v| v.to_string())
435 .collect::<Vec<String>>()
436 .as_slice()
437 .join(", ")
438 ),
439 None => write!(f, "{}.*", prefix),
440 },
441 SelectItem::Wildcard(except) => match except {
442 Some(cols) => write!(
443 f,
444 "* EXCEPT ({})",
445 cols.iter()
446 .map(|v| v.to_string())
447 .collect::<Vec<String>>()
448 .as_slice()
449 .join(", ")
450 ),
451 None => write!(f, "*"),
452 },
453 }
454 }
455}
456
457#[derive(Debug, Clone, PartialEq, Eq, Hash)]
458#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
459pub struct TableWithJoins {
460 pub relation: TableFactor,
461 pub joins: Vec<Join>,
462}
463
464impl fmt::Display for TableWithJoins {
465 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 write!(f, "{}", self.relation)?;
467 for join in &self.joins {
468 write!(f, "{}", join)?;
469 }
470 Ok(())
471 }
472}
473
474#[derive(Debug, Clone, PartialEq, Eq, Hash)]
476#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
477pub enum TableFactor {
478 Table {
479 name: ObjectName,
480 alias: Option<TableAlias>,
481 as_of: Option<AsOf>,
482 },
483 Derived {
484 lateral: bool,
485 subquery: Box<Query>,
486 alias: Option<TableAlias>,
487 },
488 TableFunction {
492 name: ObjectName,
493 alias: Option<TableAlias>,
494 args: Vec<FunctionArg>,
495 with_ordinality: bool,
496 },
497 NestedJoin(Box<TableWithJoins>),
504}
505
506impl fmt::Display for TableFactor {
507 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
508 match self {
509 TableFactor::Table { name, alias, as_of } => {
510 write!(f, "{}", name)?;
511 if let Some(as_of) = as_of {
512 write!(f, "{}", as_of)?
513 }
514 if let Some(alias) = alias {
515 write!(f, " AS {}", alias)?;
516 }
517 Ok(())
518 }
519 TableFactor::Derived {
520 lateral,
521 subquery,
522 alias,
523 } => {
524 if *lateral {
525 write!(f, "LATERAL ")?;
526 }
527 write!(f, "({})", subquery)?;
528 if let Some(alias) = alias {
529 write!(f, " AS {}", alias)?;
530 }
531 Ok(())
532 }
533 TableFactor::TableFunction {
534 name,
535 alias,
536 args,
537 with_ordinality,
538 } => {
539 write!(f, "{}({})", name, display_comma_separated(args))?;
540 if *with_ordinality {
541 write!(f, " WITH ORDINALITY")?;
542 }
543 if let Some(alias) = alias {
544 write!(f, " AS {}", alias)?;
545 }
546 Ok(())
547 }
548 TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference),
549 }
550 }
551}
552
553#[derive(Debug, Clone, PartialEq, Eq, Hash)]
554#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
555pub struct TableAlias {
556 pub name: Ident,
557 pub columns: Vec<Ident>,
558}
559
560impl fmt::Display for TableAlias {
561 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
562 write!(f, "{}", self.name)?;
563 if !self.columns.is_empty() {
564 write!(f, " ({})", display_comma_separated(&self.columns))?;
565 }
566 Ok(())
567 }
568}
569
570#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
572pub struct Join {
573 pub relation: TableFactor,
574 pub join_operator: JoinOperator,
575}
576
577impl fmt::Display for Join {
578 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579 fn prefix(constraint: &JoinConstraint) -> &'static str {
580 match constraint {
581 JoinConstraint::Natural => "NATURAL ",
582 _ => "",
583 }
584 }
585 fn suffix(constraint: &'_ JoinConstraint) -> impl fmt::Display + '_ {
586 struct Suffix<'a>(&'a JoinConstraint);
587 impl fmt::Display for Suffix<'_> {
588 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
589 match self.0 {
590 JoinConstraint::On(expr) => write!(f, " ON {}", expr),
591 JoinConstraint::Using(attrs) => {
592 write!(f, " USING({})", display_comma_separated(attrs))
593 }
594 _ => Ok(()),
595 }
596 }
597 }
598 Suffix(constraint)
599 }
600 match &self.join_operator {
601 JoinOperator::Inner(constraint) => write!(
602 f,
603 " {}JOIN {}{}",
604 prefix(constraint),
605 self.relation,
606 suffix(constraint)
607 ),
608 JoinOperator::LeftOuter(constraint) => write!(
609 f,
610 " {}LEFT JOIN {}{}",
611 prefix(constraint),
612 self.relation,
613 suffix(constraint)
614 ),
615 JoinOperator::RightOuter(constraint) => write!(
616 f,
617 " {}RIGHT JOIN {}{}",
618 prefix(constraint),
619 self.relation,
620 suffix(constraint)
621 ),
622 JoinOperator::FullOuter(constraint) => write!(
623 f,
624 " {}FULL JOIN {}{}",
625 prefix(constraint),
626 self.relation,
627 suffix(constraint)
628 ),
629 JoinOperator::CrossJoin => write!(f, " CROSS JOIN {}", self.relation),
630 JoinOperator::AsOfInner(constraint) => write!(
631 f,
632 " {}ASOF JOIN {}{}",
633 prefix(constraint),
634 self.relation,
635 suffix(constraint)
636 ),
637 JoinOperator::AsOfLeft(constraint) => write!(
638 f,
639 " {}ASOF LEFT JOIN {}{}",
640 prefix(constraint),
641 self.relation,
642 suffix(constraint)
643 ),
644 }
645 }
646}
647
648#[derive(Debug, Clone, PartialEq, Eq, Hash)]
649#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
650pub enum JoinOperator {
651 Inner(JoinConstraint),
652 LeftOuter(JoinConstraint),
653 RightOuter(JoinConstraint),
654 FullOuter(JoinConstraint),
655 CrossJoin,
656 AsOfInner(JoinConstraint),
657 AsOfLeft(JoinConstraint),
658}
659
660#[derive(Debug, Clone, PartialEq, Eq, Hash)]
661#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
662pub enum JoinConstraint {
663 On(Expr),
664 Using(Vec<Ident>),
665 Natural,
666 None,
667}
668
669#[derive(Debug, Clone, PartialEq, Eq, Hash)]
671#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
672pub struct OrderByExpr {
673 pub expr: Expr,
674 pub asc: Option<bool>,
676 pub nulls_first: Option<bool>,
678}
679
680impl fmt::Display for OrderByExpr {
681 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
682 write!(f, "{}", self.expr)?;
683 match self.asc {
684 Some(true) => write!(f, " ASC")?,
685 Some(false) => write!(f, " DESC")?,
686 None => (),
687 }
688 match self.nulls_first {
689 Some(true) => write!(f, " NULLS FIRST")?,
690 Some(false) => write!(f, " NULLS LAST")?,
691 None => (),
692 }
693 Ok(())
694 }
695}
696
697#[derive(Debug, Clone, PartialEq, Eq, Hash)]
698#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
699pub struct Fetch {
700 pub with_ties: bool,
701 pub quantity: Option<String>,
702}
703
704impl fmt::Display for Fetch {
705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706 let extension = if self.with_ties { "WITH TIES" } else { "ONLY" };
707 if let Some(ref quantity) = self.quantity {
708 write!(f, "FETCH FIRST {} ROWS {}", quantity, extension)
709 } else {
710 write!(f, "FETCH FIRST ROWS {}", extension)
711 }
712 }
713}
714
715#[derive(Debug, Clone, PartialEq, Eq, Hash)]
716#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
717pub struct Top {
718 pub with_ties: bool,
720 pub percent: bool,
721 pub quantity: Option<Expr>,
722}
723
724impl fmt::Display for Top {
725 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
726 let extension = if self.with_ties { " WITH TIES" } else { "" };
727 if let Some(ref quantity) = self.quantity {
728 let percent = if self.percent { " PERCENT" } else { "" };
729 write!(f, "TOP ({}){}{}", quantity, percent, extension)
730 } else {
731 write!(f, "TOP{}", extension)
732 }
733 }
734}
735
736#[derive(Debug, Clone, PartialEq, Eq, Hash)]
737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
738pub struct Values(pub Vec<Vec<Expr>>);
739
740impl fmt::Display for Values {
741 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
742 write!(f, "VALUES ")?;
743 let mut delim = "";
744 for row in &self.0 {
745 write!(f, "{}", delim)?;
746 delim = ", ";
747 write!(f, "({})", display_comma_separated(row))?;
748 }
749 Ok(())
750 }
751}
752
753#[derive(Debug, Clone, PartialEq, Eq, Hash)]
755#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
756pub struct NamedWindow {
757 pub name: Ident,
758 pub window_spec: WindowSpec,
759}
760
761impl fmt::Display for NamedWindow {
762 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763 write!(f, "{} AS ({})", self.name, self.window_spec)
764 }
765}