use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use crate::err::TranslationErrors;
use crate::sql::expression::identifier::Identifier;
use crate::sql::expression::{Leaf, SQLExpression};
use crate::sql::query::PatternVariable;
use crate::write_utils::{maybe_newline, maybe_pad, newline_or_space, Indent};
use anyhow::{anyhow, Result};
use chrono::{DateTime, Utc};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BinaryLiteral {
hex_value: String,
}
impl BinaryLiteral {
pub fn new(hex_value: &str) -> Self {
Self {
hex_value: hex_value.to_string(),
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "x{}", self.hex_value)
}
}
impl Display for BinaryLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BooleanLiteral {
pub value: bool,
}
impl BooleanLiteral {
pub fn new(value: bool) -> Self {
Self { value }
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
if self.value {
write!(f, "true")
} else {
write!(f, "false")
}
}
}
impl Display for BooleanLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ColumnReference {
pub identifier: Identifier,
}
impl ColumnReference {
pub fn new(identifier: Identifier) -> Self {
Self { identifier }
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
indentation: Indent,
) -> std::fmt::Result {
self.identifier.fmt_indented(f, indentation)
}
pub fn prefixed_with(&self, prefix: &str) -> Self {
Self {
identifier: self.identifier.prefixed_with_str(prefix).into(),
}
}
}
impl Display for ColumnReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
impl FromStr for ColumnReference {
type Err = TranslationErrors;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse().map(|ident| Self::new(ident))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PatternVariableReference {
pub pattern_variable: PatternVariable,
}
impl PatternVariableReference {
pub fn new(pattern_variable: PatternVariable) -> Self {
Self { pattern_variable }
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
self.pattern_variable.fmt(f)
}
}
impl Display for PatternVariableReference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecimalLiteral {
pub number: String,
}
impl DecimalLiteral {
pub fn new(number: &str) -> Self {
Self {
number: number.to_string(),
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "{}", self.number.clone())
}
}
impl Display for DecimalLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntegerLiteral {
pub number: String,
}
impl IntegerLiteral {
pub fn from_int(number: i64) -> Self {
Self {
number: number.to_string(),
}
}
pub fn new(number: &str) -> Self {
Self {
number: number.to_string(),
}
}
pub fn to_sql_expression(self) -> SQLExpression {
SQLExpression::Leaf(Leaf::IntegerLiteral(self))
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "{}", self.number.clone())
}
}
impl Display for IntegerLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct NullLiteral {}
impl NullLiteral {
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "NULL")
}
}
impl Display for NullLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Unit {
Year,
Month,
Week,
Day,
Hour,
Minute,
Second,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IntervalLiteral {
value: String,
unit: Unit,
}
impl IntervalLiteral {
pub fn new<V: ToString>(value: V, unit: Unit) -> Self {
Self {
value: value.to_string(),
unit,
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(
f,
"INTERVAL '{}' {}",
self.value,
match self.unit {
Unit::Year => "YEAR",
Unit::Month => "MONTH",
Unit::Week => "WEEK",
Unit::Day => "DAY",
Unit::Hour => "HOUR",
Unit::Minute => "MINUTE",
Unit::Second => "SECOND",
}
)
}
}
impl Display for IntervalLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScientificLiteral {
number: String,
}
impl ScientificLiteral {
pub fn new(number: &str) -> Self {
Self {
number: number.to_string(),
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "{}", self.number)
}
}
impl Display for ScientificLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StringLiteral {
pub value: String,
}
impl StringLiteral {
pub fn new(value: &str) -> Self {
Self {
value: value.to_string(),
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "'{}'", self.value.replace("'", "''"))
}
}
impl Display for StringLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TimestampLiteral {
value: DateTime<Utc>,
}
impl TimestampLiteral {
pub fn new(value: DateTime<Utc>) -> Self {
Self { value }
}
pub fn from_string_literal(literal: &StringLiteral) -> anyhow::Result<Self> {
TimestampLiteral::parse(&literal.value).map(|value| Self { value })
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
write!(f, "TIMESTAMP '{}'", self.value)
}
fn parse(literal: &str) -> anyhow::Result<DateTime<Utc>> {
DateTime::parse_from_rfc3339(literal)
.or(DateTime::parse_from_rfc2822(literal))
.map(|dt| dt.with_timezone(&Utc))
.map_err(|e| anyhow!("Could not parse timestamp literal: {}", e))
}
}
impl Display for TimestampLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnicodeStringLiteral {
value: String,
uescape: Option<String>,
}
impl UnicodeStringLiteral {
pub fn new<T: AsRef<str>>(value: &str, uescape: Option<T>) -> Self {
Self {
value: value.to_string(),
uescape: uescape.map(|u| u.as_ref().to_string()),
}
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
_indentation: Indent,
) -> std::fmt::Result {
let qesc_value = self.value.replace("'", "''");
let qesc_uesc = self
.uescape
.as_ref()
.map(|u| u.replace("'", "''"))
.map(|u| format!(" UESCAPE '{}'", u));
write!(
f,
"U&'{}'{}",
qesc_value,
qesc_uesc.unwrap_or("".to_string())
)
}
}
impl Display for UnicodeStringLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArrayLiteral {
pub elements: Vec<SQLExpression>,
}
impl ArrayLiteral {
pub fn new(elements: Vec<SQLExpression>) -> Self {
Self { elements }
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
indentation: Indent,
) -> std::fmt::Result {
let indentation = match indentation {
Indent::Pretty { .. } if self.subelements() > 3 => indentation,
_ => Indent::Compact,
};
write!(f, "ARRAY[")?;
maybe_newline(f, indentation)?;
for (i, element) in self.elements.iter().enumerate() {
maybe_pad(f, indentation.nested())?;
element.fmt_indented(f, indentation.nested())?;
if i < self.elements.len() - 1 {
write!(f, ",")?;
newline_or_space(f, indentation)?;
}
}
maybe_newline(f, indentation)?;
maybe_pad(f, indentation)?;
write!(f, "]")
}
pub(crate) fn subelements(&self) -> usize {
self.elements
.iter()
.map(|element| element.subelements() + 1)
.sum()
}
}
impl Display for ArrayLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RowLiteral {
pub values: Vec<SQLExpression>,
}
impl RowLiteral {
pub fn new(values: Vec<SQLExpression>) -> Self {
Self { values }
}
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,
};
write!(f, "ROW(")?;
maybe_newline(f, indentation)?;
for (i, value) in self.values.iter().enumerate() {
maybe_pad(f, indentation.nested())?;
value.fmt_indented(f, indentation.nested())?;
if i < self.values.len() - 1 {
write!(f, ",")?;
newline_or_space(f, indentation)?;
}
}
maybe_newline(f, indentation)?;
maybe_pad(f, indentation)?;
write!(f, ")")
}
pub(crate) fn subelements(&self) -> usize {
self.values
.iter()
.map(|value| value.subelements() + 1)
.sum()
}
}
impl Display for RowLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TupleLiteral {
pub elements: Vec<SQLExpression>,
}
impl TupleLiteral {
pub fn new(elements: Vec<SQLExpression>) -> Self {
Self { elements }
}
pub fn fmt_indented(
&self,
f: &mut std::fmt::Formatter<'_>,
indentation: Indent,
) -> std::fmt::Result {
let indentation = match indentation {
Indent::Pretty { .. } if self.subelements() > 3 => indentation,
_ => Indent::Compact,
};
write!(f, "(")?;
maybe_newline(f, indentation)?;
for (i, element) in self.elements.iter().enumerate() {
maybe_pad(f, indentation.nested())?;
element.fmt_indented(f, indentation.nested())?;
if i < self.elements.len() - 1 {
write!(f, ",")?;
newline_or_space(f, indentation)?;
}
}
maybe_newline(f, indentation)?;
maybe_pad(f, indentation)?;
write!(f, ")")
}
pub(crate) fn subelements(&self) -> usize {
self.elements
.iter()
.map(|element| element.subelements() + 1)
.sum()
}
}
impl Display for TupleLiteral {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_indented(f, Indent::default())
}
}