use crate::sql::expression::identifier::SimpleIdentifier;
use crate::sql::expression::operator::Operator;
use crate::sql::expression::precedence::precedence;
use crate::sql::expression::SQLExpression;
use crate::write_utils::{maybe_newline, maybe_pad, newline_or_space, Indent};
use ordermap::OrderMap;
use std::fmt;
use std::fmt::{Display, Formatter};
use super::OrderByExpression;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct FunctionCallApply {
pub function_name: String,
pub arguments: Vec<SQLExpression>,
pub named_arguments: OrderMap<String, SQLExpression>,
pub order_by: Vec<OrderByExpression>,
pub ignore_nulls: bool,
pub distinct: bool,
}
impl FunctionCallApply {
pub fn with_positional(function_name: &str, arguments: Vec<SQLExpression>) -> Self {
Self {
function_name: function_name.to_string(),
arguments: arguments.to_vec(),
..FunctionCallApply::default()
}
}
pub fn with_no_arguments(function_name: &str) -> Self {
Self {
function_name: function_name.to_string(),
..FunctionCallApply::default()
}
}
pub fn with_one(function_name: &str, argument: SQLExpression) -> Self {
Self {
function_name: function_name.to_string(),
arguments: vec![argument],
..FunctionCallApply::default()
}
}
pub fn with_two(
function_name: &str,
argument1: SQLExpression,
argument2: SQLExpression,
) -> Self {
Self {
function_name: function_name.to_string(),
arguments: vec![argument1, argument2],
..FunctionCallApply::default()
}
}
pub fn with_three(
function_name: &str,
argument1: SQLExpression,
argument2: SQLExpression,
argument3: SQLExpression,
) -> Self {
Self {
function_name: function_name.to_string(),
arguments: vec![argument1, argument2, argument3],
..FunctionCallApply::default()
}
}
pub fn with_four(
function_name: &str,
argument1: SQLExpression,
argument2: SQLExpression,
argument3: SQLExpression,
argument4: SQLExpression,
) -> Self {
Self {
function_name: function_name.to_string(),
arguments: vec![argument1, argument2, argument3, argument4],
..FunctionCallApply::default()
}
}
pub fn with_order_by(mut self, mut order_by: Vec<OrderByExpression>) -> Self {
self.order_by.append(&mut order_by);
self
}
pub fn with_ignore_nulls(mut self) -> Self {
self.ignore_nulls = true;
self
}
pub fn with_distinct(mut self) -> Self {
self.distinct = true;
self
}
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: Indent) -> fmt::Result {
let indentation = match indentation {
Indent::Pretty { .. } if self.subelements() > 3 => indentation,
_ => Indent::Compact,
};
let has_args = !self.arguments.is_empty();
let has_named = !self.named_arguments.is_empty();
let has_order_by = !self.order_by.is_empty();
let has_content = has_args || has_named || has_order_by || self.distinct;
write!(f, "{}(", self.function_name)?;
if has_content {
maybe_newline(f, indentation)?;
}
if self.distinct {
maybe_pad(f, indentation.nested())?;
write!(f, "DISTINCT")?;
newline_or_space(f, indentation)?;
}
for (i, arg) in self.arguments.iter().enumerate() {
maybe_pad(f, indentation.nested())?;
arg.fmt_indented(f, indentation.nested())?;
if i < self.arguments.len() - 1 {
write!(f, ",")?;
newline_or_space(f, indentation)?;
}
}
if has_args && has_named {
newline_or_space(f, indentation)?;
}
for (i, (key, value)) in self.named_arguments.iter().enumerate() {
maybe_pad(f, indentation.nested())?;
write!(f, "{} ", key)?;
value.fmt_indented(f, indentation.nested())?;
if i < self.named_arguments.len() - 1 {
newline_or_space(f, indentation)?;
}
}
if has_order_by {
newline_or_space(f, indentation)?;
maybe_pad(f, indentation.nested())?;
write!(f, "ORDER BY")?;
newline_or_space(f, indentation)?;
for (i, order) in self.order_by.iter().enumerate() {
maybe_pad(f, indentation.nested().nested())?;
order.fmt_indented(f, indentation.nested().nested())?;
if i < self.order_by.len() - 1 {
write!(f, ",")?;
newline_or_space(f, indentation)?;
}
}
}
if has_content {
maybe_newline(f, indentation)?;
maybe_pad(f, indentation)?;
}
write!(f, ")")?;
if self.ignore_nulls {
write!(f, " IGNORE NULLS")?;
}
Ok(())
}
pub(crate) fn subelements(&self) -> usize {
self.arguments
.iter()
.map(|a| a.subelements() + 1)
.sum::<usize>()
+ self
.named_arguments
.iter()
.map(|(_, v)| v.subelements() + 1)
.sum::<usize>()
+ self
.order_by
.iter()
.map(|obe| obe.expression.subelements() + 1)
.sum::<usize>()
}
}
impl Display for FunctionCallApply {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Lambda {
pub arguments: Vec<SimpleIdentifier>,
pub body: Box<SQLExpression>,
}
impl Lambda {
pub fn new(arguments: Vec<SimpleIdentifier>, body: SQLExpression) -> Self {
Self {
arguments,
body: Box::new(body),
}
}
pub fn from_single_argument(argument: SimpleIdentifier, body: SQLExpression) -> Self {
Self {
arguments: vec![argument],
body: Box::new(body),
}
}
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: Indent) -> fmt::Result {
write!(
f,
"({}) -> ",
self.arguments
.iter()
.map(|a| a.to_string())
.collect::<Vec<String>>()
.join(", "),
)?;
self.body.fmt_indented(f, indentation)
}
}
impl Display for Lambda {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinaryOperatorApply {
pub operator: Operator,
pub left: Box<SQLExpression>,
pub right: Box<SQLExpression>,
}
impl BinaryOperatorApply {
pub fn new(operator: Operator, left: SQLExpression, right: SQLExpression) -> Self {
Self {
operator,
left: Box::new(left),
right: Box::new(right),
}
}
pub fn fmt_indented(&self, f: &mut Formatter<'_>, indentation: Indent) -> fmt::Result {
let self_expression: SQLExpression = self.clone().into();
let parens_left = precedence(self.left.as_ref())
.and_then(|l| precedence(&self_expression).map(|t| t < l))
.unwrap_or(false);
let parens_right = precedence(self.right.as_ref())
.and_then(|r| precedence(&self_expression).map(|t| t < r))
.unwrap_or(false);
if parens_left {
write!(f, "(")?;
}
self.left.fmt_indented(f, indentation)?;
if parens_left {
write!(f, ")")?;
}
write!(f, " {} ", self.operator)?;
if parens_right {
write!(f, "(")?;
}
self.right.fmt_indented(f, indentation)?;
if parens_right {
write!(f, ")")?;
}
Ok(())
}
}
impl Display for BinaryOperatorApply {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnaryOperatorApply {
pub operator: Operator,
pub operand: Box<SQLExpression>,
}
impl UnaryOperatorApply {
pub fn new(operator: Operator, operand: SQLExpression) -> Self {
Self {
operator,
operand: Box::new(operand),
}
}
pub fn fmt_indented(&self, f: &mut Formatter<'_>, _indentation: Indent) -> fmt::Result {
let this: SQLExpression = self.clone().into();
let expression_render = self.operand.to_string();
let parens_expr = precedence(self.operand.as_ref())
.and_then(|e| precedence(&this).map(|t| t <= e))
.map(|b| {
if b {
format!("({})", expression_render)
} else {
expression_render.clone()
}
})
.unwrap_or(expression_render);
write!(f, "{} {}", self.operator.to_string(), parens_expr)
}
}
impl Display for UnaryOperatorApply {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}