#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
use core::fmt::{self, Display};
use crate::{RelNamed, SelectInto, TableAlias, Values};
use super::display_utils::{Indent, SpaceOrNewline, indented_list};
use super::{Expr, Ident, ObjectName, OrderByExpr, Query, SelectItem, display_comma_separated};
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Insert {
pub table: ObjectName,
pub columns: Vec<Ident>,
pub source: Box<Query>,
}
impl Display for Insert {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "INSERT INTO {} ", self.table)?;
if !self.columns.is_empty() {
write!(f, "({})", display_comma_separated(&self.columns))?;
SpaceOrNewline.fmt(f)?;
}
self.source.fmt(f)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Delete {
pub tables: Vec<ObjectName>,
pub from: FromTable,
pub using: Option<Vec<RelNamed>>,
pub selection: Option<Expr>,
pub returning: Option<Vec<SelectItem>>,
pub order_by: Vec<OrderByExpr>,
pub limit: Option<Expr>,
}
impl Display for Delete {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("DELETE")?;
if !self.tables.is_empty() {
indented_list(f, &self.tables)?;
}
match &self.from {
FromTable::WithFromKeyword(from) => {
f.write_str(" FROM")?;
indented_list(f, from)?;
}
FromTable::WithoutKeyword(from) => {
indented_list(f, from)?;
}
}
if let Some(using) = &self.using {
SpaceOrNewline.fmt(f)?;
f.write_str("USING")?;
indented_list(f, using)?;
}
if let Some(selection) = &self.selection {
SpaceOrNewline.fmt(f)?;
f.write_str("WHERE")?;
SpaceOrNewline.fmt(f)?;
Indent(selection).fmt(f)?;
}
if let Some(returning) = &self.returning {
SpaceOrNewline.fmt(f)?;
f.write_str("RETURNING")?;
indented_list(f, returning)?;
}
if !self.order_by.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("ORDER BY")?;
indented_list(f, &self.order_by)?;
}
if let Some(limit) = &self.limit {
SpaceOrNewline.fmt(f)?;
f.write_str("LIMIT")?;
SpaceOrNewline.fmt(f)?;
Indent(limit).fmt(f)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum FromTable {
WithFromKeyword(Vec<RelNamed>),
WithoutKeyword(Vec<RelNamed>),
}
impl Display for FromTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FromTable::WithFromKeyword(tables) => {
write!(f, "FROM {}", display_comma_separated(tables))
}
FromTable::WithoutKeyword(tables) => {
write!(f, "{}", display_comma_separated(tables))
}
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Update {
pub table: ObjectName,
pub alias: Option<TableAlias>,
pub assignments: Vec<Assignment>,
pub from: Vec<RelNamed>,
pub selection: Option<Expr>,
pub returning: Option<Vec<SelectItem>>,
pub limit: Option<Expr>,
}
impl fmt::Display for Update {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("UPDATE ")?;
self.table.fmt(f)?;
if let Some(alias) = &self.alias {
f.write_str(" AS ")?;
alias.fmt(f)?;
}
if !self.assignments.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("SET")?;
indented_list(f, &self.assignments)?;
}
if !self.from.is_empty() {
SpaceOrNewline.fmt(f)?;
f.write_str("FROM")?;
indented_list(f, &self.from)?;
}
if let Some(selection) = &self.selection {
SpaceOrNewline.fmt(f)?;
f.write_str("WHERE")?;
SpaceOrNewline.fmt(f)?;
Indent(selection).fmt(f)?;
}
if let Some(returning) = &self.returning {
SpaceOrNewline.fmt(f)?;
f.write_str("RETURNING")?;
indented_list(f, returning)?;
}
if let Some(limit) = &self.limit {
SpaceOrNewline.fmt(f)?;
write!(f, "LIMIT {limit}")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct Assignment {
pub target: AssignmentTarget,
pub value: Expr,
}
impl fmt::Display for Assignment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} = {}", self.target, self.value)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum AssignmentTarget {
ColumnName(ObjectName),
Tuple(Vec<ObjectName>),
}
impl fmt::Display for AssignmentTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AssignmentTarget::ColumnName(column) => write!(f, "{column}"),
AssignmentTarget::Tuple(columns) => write!(f, "({})", display_comma_separated(columns)),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MergeClauseKind {
Matched,
NotMatched,
NotMatchedByTarget,
NotMatchedBySource,
}
impl Display for MergeClauseKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MergeClauseKind::Matched => write!(f, "MATCHED"),
MergeClauseKind::NotMatched => write!(f, "NOT MATCHED"),
MergeClauseKind::NotMatchedByTarget => write!(f, "NOT MATCHED BY TARGET"),
MergeClauseKind::NotMatchedBySource => write!(f, "NOT MATCHED BY SOURCE"),
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MergeInsertKind {
Values(Values),
Row,
}
impl Display for MergeInsertKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MergeInsertKind::Values(values) => {
write!(f, "{values}")
}
MergeInsertKind::Row => {
write!(f, "ROW")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct MergeInsertExpr {
pub columns: Vec<Ident>,
pub kind: MergeInsertKind,
}
impl Display for MergeInsertExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.columns.is_empty() {
write!(f, "({}) ", display_comma_separated(self.columns.as_slice()))?;
}
write!(f, "{}", self.kind)
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MergeAction {
Insert(MergeInsertExpr),
Update { assignments: Vec<Assignment> },
Delete,
}
impl Display for MergeAction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MergeAction::Insert(insert) => {
write!(f, "INSERT {insert}")
}
MergeAction::Update { assignments } => {
write!(f, "UPDATE SET {}", display_comma_separated(assignments))
}
MergeAction::Delete => {
write!(f, "DELETE")
}
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct MergeClause {
pub clause_kind: MergeClauseKind,
pub predicate: Option<Expr>,
pub action: MergeAction,
}
impl Display for MergeClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let MergeClause {
clause_kind,
predicate,
action,
} = self;
write!(f, "WHEN {clause_kind}")?;
if let Some(pred) = predicate {
write!(f, " AND {pred}")?;
}
write!(f, " THEN {action}")
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum OutputClause {
Output {
select_items: Vec<SelectItem>,
into_table: Option<SelectInto>,
},
Returning {
select_items: Vec<SelectItem>,
},
}
impl fmt::Display for OutputClause {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OutputClause::Output {
select_items,
into_table,
} => {
f.write_str("OUTPUT ")?;
display_comma_separated(select_items).fmt(f)?;
if let Some(into_table) = into_table {
f.write_str(" ")?;
into_table.fmt(f)?;
}
Ok(())
}
OutputClause::Returning { select_items } => {
f.write_str("RETURNING ")?;
display_comma_separated(select_items).fmt(f)
}
}
}
}