when no context is needed use Display Impl

This commit is contained in:
pedrocarlo
2025-06-03 12:46:56 -03:00
parent bfc8cb6d4c
commit 5f379fe2d6
10 changed files with 284 additions and 263 deletions

View File

@@ -1,4 +1,6 @@
use crate::ast::{self, Expr};
use std::fmt::Display;
use crate::ast::{self, fmt::ToTokens, Expr};
use super::ToSqlString;
@@ -30,7 +32,7 @@ impl ToSqlString for Expr {
Expr::Binary(lhs, op, rhs) => {
ret.push_str(&lhs.to_sql_string(context));
ret.push(' ');
ret.push_str(&op.to_sql_string(context));
ret.push_str(&op.to_string());
ret.push(' ');
ret.push_str(&rhs.to_sql_string(context));
}
@@ -212,7 +214,7 @@ impl ToSqlString for Expr {
if *not {
ret.push_str("NOT ");
}
ret.push_str(&op.to_sql_string(context));
ret.push_str(&op.to_string());
ret.push(' ');
ret.push_str(&rhs.to_sql_string(context));
if let Some(escape) = escape {
@@ -221,7 +223,7 @@ impl ToSqlString for Expr {
}
}
Expr::Literal(literal) => {
ret.push_str(&literal.to_sql_string(context));
ret.push_str(&literal.to_string());
}
Expr::Name(name) => {
ret.push_str(&name.0);
@@ -247,7 +249,7 @@ impl ToSqlString for Expr {
}
Expr::Raise(resolve_type, expr) => {
ret.push_str("RAISE(");
ret.push_str(&resolve_type.to_sql_string(context));
ret.push_str(&resolve_type.to_string());
if let Some(expr) = expr {
ret.push_str(", ");
ret.push_str(&expr.to_sql_string(context));
@@ -260,7 +262,7 @@ impl ToSqlString for Expr {
ret.push(')');
}
Expr::Unary(unary_operator, expr) => {
ret.push_str(&unary_operator.to_sql_string(context));
ret.push_str(&unary_operator.to_string());
ret.push(' ');
ret.push_str(&expr.to_sql_string(context));
}
@@ -272,9 +274,9 @@ impl ToSqlString for Expr {
}
}
impl ToSqlString for ast::Operator {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
impl Display for ast::Operator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Add => "+",
Self::And => "AND",
Self::ArrowRight => "->",
@@ -298,8 +300,8 @@ impl ToSqlString for ast::Operator {
Self::Or => "OR",
Self::RightShift => ">>",
Self::Subtract => "-",
}
.to_string()
};
write!(f, "{}", value)
}
}
@@ -333,16 +335,20 @@ impl ToSqlString for ast::TypeSize {
}
}
impl ToSqlString for ast::Distinctness {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::All => "ALL",
Self::Distinct => "DISTINCT",
}
.to_string()
impl Display for ast::Distinctness {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::All => "ALL",
Self::Distinct => "DISTINCT",
}
)
}
}
// Can't impl Display here as it is already implemented for it
impl ToSqlString for ast::QualifiedName {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
let mut ret = String::new();
@@ -359,55 +365,49 @@ impl ToSqlString for ast::QualifiedName {
}
}
impl ToSqlString for ast::LikeOperator {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Glob => "GLOB",
Self::Like => "LIKE",
Self::Match => "MATCH",
Self::Regexp => "REGEXP",
}
.to_string()
impl Display for ast::LikeOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
impl ToSqlString for ast::Literal {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Blob(b) => format!("Ox{b}"),
Self::CurrentDate => "CURRENT_DATE".to_string(),
Self::CurrentTime => "CURRENT_TIME".to_string(),
Self::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
Self::Keyword(keyword) => keyword.clone(),
Self::Null => "NULL".to_string(),
Self::Numeric(num) => num.clone(),
Self::String(s) => s.clone(),
}
impl Display for ast::Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Blob(b) => format!("Ox{b}"),
Self::CurrentDate => "CURRENT_DATE".to_string(),
Self::CurrentTime => "CURRENT_TIME".to_string(),
Self::CurrentTimestamp => "CURRENT_TIMESTAMP".to_string(),
Self::Keyword(keyword) => keyword.clone(),
Self::Null => "NULL".to_string(),
Self::Numeric(num) => num.clone(),
Self::String(s) => s.clone(),
}
)
}
}
impl ToSqlString for ast::ResolveType {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Abort => "ABORT",
Self::Fail => "FAIL",
Self::Ignore => "IGNORE",
Self::Replace => "REPLACE",
Self::Rollback => "ROLLBACK",
}
.to_string()
impl Display for ast::ResolveType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
impl ToSqlString for ast::UnaryOperator {
fn to_sql_string<C: super::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::BitwiseNot => "~",
Self::Negative => "-",
Self::Not => "NOT",
Self::Positive => "+",
}
.to_string()
impl Display for ast::UnaryOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::BitwiseNot => "~",
Self::Negative => "-",
Self::Not => "NOT",
Self::Positive => "+",
}
)
}
}

View File

@@ -1,3 +1,5 @@
use std::fmt::Display;
use crate::{ast, to_sql_string::ToSqlString};
impl ToSqlString for ast::AlterTableBody {
@@ -60,15 +62,15 @@ impl ToSqlString for ast::ColumnConstraint {
format!("DEFAULT ({})", expr.to_sql_string(context))
}
}
Self::Defer(expr) => expr.to_sql_string(context),
Self::Defer(expr) => expr.to_string(),
Self::ForeignKey {
clause,
deref_clause,
} => format!(
"{}{}",
clause.to_sql_string(context),
clause.to_string(),
if let Some(deref) = deref_clause {
deref.to_sql_string(context)
deref.to_string()
} else {
"".to_string()
}
@@ -94,7 +96,7 @@ impl ToSqlString for ast::ColumnConstraint {
"NOT NULL{}",
conflict_clause.map_or("".to_string(), |conflict| format!(
" {}",
conflict.to_sql_string(context)
conflict.to_string()
))
)
}
@@ -105,13 +107,10 @@ impl ToSqlString for ast::ColumnConstraint {
} => {
format!(
"PRIMARY KEY{}{}{}",
order.map_or("".to_string(), |order| format!(
" {}",
order.to_sql_string(context)
)),
order.map_or("".to_string(), |order| format!(" {}", order.to_string())),
conflict_clause.map_or("".to_string(), |conflict| format!(
" {}",
conflict.to_sql_string(context)
conflict.to_string()
)),
auto_increment.then_some(" AUTOINCREMENT").unwrap_or("")
)
@@ -121,7 +120,7 @@ impl ToSqlString for ast::ColumnConstraint {
"UNIQUE{}",
conflict_clause.map_or("".to_string(), |conflict| format!(
" {}",
conflict.to_sql_string(context)
conflict.to_string()
))
)
}
@@ -129,9 +128,9 @@ impl ToSqlString for ast::ColumnConstraint {
}
}
impl ToSqlString for ast::ForeignKeyClause {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
format!(
impl Display for ast::ForeignKeyClause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = format!(
"REFERENCES {}{}{}",
self.tbl_name.0,
if let Some(columns) = &self.columns {
@@ -139,7 +138,7 @@ impl ToSqlString for ast::ForeignKeyClause {
"({})",
columns
.iter()
.map(|cols| cols.to_sql_string(context))
.map(|cols| cols.to_string())
.collect::<Vec<_>>()
.join(", ")
)
@@ -151,46 +150,48 @@ impl ToSqlString for ast::ForeignKeyClause {
" {}",
self.args
.iter()
.map(|arg| arg.to_sql_string(context))
.map(|arg| arg.to_string())
.collect::<Vec<_>>()
.join(" ")
)
} else {
"".to_string()
}
)
);
write!(f, "{}", value)
}
}
impl ToSqlString for ast::RefArg {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
match self {
impl Display for ast::RefArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Match(name) => format!("MATCH {}", name.0),
Self::OnDelete(act) => format!("ON DELETE {}", act.to_sql_string(context)),
Self::OnUpdate(act) => format!("ON UPDATE {}", act.to_sql_string(context)),
Self::OnDelete(act) => format!("ON DELETE {}", act.to_string()),
Self::OnUpdate(act) => format!("ON UPDATE {}", act.to_string()),
Self::OnInsert(..) => unimplemented!(
"On Insert does not exist in SQLite: https://www.sqlite.org/lang_altertable.html"
),
}
};
write!(f, "{}", value)
}
}
impl ToSqlString for ast::RefAct {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, _context: &C) -> String {
match self {
impl Display for ast::RefAct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Cascade => "CASCADE",
Self::NoAction => "NO ACTION",
Self::Restrict => "RESTRICT",
Self::SetDefault => "SET DEFAULT",
Self::SetNull => "SET NULL",
}
.to_string()
};
write!(f, "{}", value)
}
}
impl ToSqlString for ast::DeferSubclause {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, _context: &C) -> String {
format!(
impl Display for ast::DeferSubclause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = format!(
"{}{}",
if self.deferrable {
"NOT DEFERRABLE"
@@ -205,7 +206,8 @@ impl ToSqlString for ast::DeferSubclause {
} else {
""
}
)
);
write!(f, "{}", value)
}
}
#[cfg(test)]

View File

@@ -1,3 +1,5 @@
use std::fmt::Display;
use crate::{ast, to_sql_string::ToSqlString};
impl ToSqlString for ast::CreateTableBody {
@@ -26,7 +28,7 @@ impl ToSqlString for ast::CreateTableBody {
.collect::<Vec<_>>()
.join(", ")
)),
options.to_sql_string(context)
options.to_string()
)
}
}
@@ -59,12 +61,12 @@ impl ToSqlString for ast::TableConstraint {
"FOREIGN KEY ({}) {}{}",
columns
.iter()
.map(|col| col.to_sql_string(context))
.map(|col| col.to_string())
.collect::<Vec<_>>()
.join(", "),
clause.to_sql_string(context),
clause.to_string(),
if let Some(deref) = deref_clause {
deref.to_sql_string(context)
deref.to_string()
} else {
"".to_string()
}
@@ -82,7 +84,7 @@ impl ToSqlString for ast::TableConstraint {
.join(", "),
conflict_clause.map_or("".to_string(), |conflict| format!(
" {}",
conflict.to_sql_string(context)
conflict.to_string()
)),
auto_increment.then_some(" AUTOINCREMENT").unwrap_or("")
),
@@ -98,23 +100,26 @@ impl ToSqlString for ast::TableConstraint {
.join(", "),
conflict_clause.map_or("".to_string(), |conflict| format!(
" {}",
conflict.to_sql_string(context)
conflict.to_string()
))
),
}
}
}
impl ToSqlString for ast::TableOptions {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, _context: &C) -> String {
if *self == Self::NONE {
""
} else if *self == Self::STRICT {
" STRICT"
} else {
" WITHOUT ROWID"
}
.to_string()
impl Display for ast::TableOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
if *self == Self::NONE {
""
} else if *self == Self::STRICT {
" STRICT"
} else {
" WITHOUT ROWID"
}
)
}
}

View File

@@ -1,4 +1,9 @@
use crate::{ast, to_sql_string::ToSqlString};
use std::fmt::Display;
use crate::{
ast::{self, fmt::ToTokens},
to_sql_string::ToSqlString,
};
impl ToSqlString for ast::CreateTrigger {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
@@ -7,11 +12,9 @@ impl ToSqlString for ast::CreateTrigger {
self.temporary.then_some(" TEMP").unwrap_or(""),
self.if_not_exists.then_some("IF NOT EXISTS ").unwrap_or(""),
self.trigger_name.to_sql_string(context),
self.time.map_or("".to_string(), |time| format!(
" {}",
time.to_sql_string(context)
)),
self.event.to_sql_string(context),
self.time
.map_or("".to_string(), |time| format!(" {}", time.to_string())),
self.event.to_string(),
self.tbl_name.to_sql_string(context),
self.for_each_row.then_some(" FOR EACH ROW").unwrap_or(""),
self.when_clause
@@ -29,32 +32,31 @@ impl ToSqlString for ast::CreateTrigger {
}
}
impl ToSqlString for ast::TriggerTime {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::After => "AFTER",
Self::Before => "BEFORE",
Self::InsteadOf => "INSTEAD OF",
}
.to_string()
impl Display for ast::TriggerTime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
impl ToSqlString for ast::TriggerEvent {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Delete => "DELETE".to_string(),
Self::Insert => "INSERT".to_string(),
Self::Update => "UPDATE".to_string(),
Self::UpdateOf(col_names) => format!(
"UPDATE OF {}",
col_names
.iter()
.map(|name| name.0.clone())
.collect::<Vec<_>>()
.join(", ")
),
}
impl Display for ast::TriggerEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Delete => "DELETE".to_string(),
Self::Insert => "INSERT".to_string(),
Self::Update => "UPDATE".to_string(),
Self::UpdateOf(col_names) => format!(
"UPDATE OF {}",
col_names
.iter()
.map(|name| name.0.clone())
.collect::<Vec<_>>()
.join(", ")
),
}
)
}
}
@@ -97,7 +99,7 @@ impl ToSqlString for ast::TriggerCmdInsert {
"INSERT {}INTO {} {}{}{}{}",
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {} ",
conflict.to_sql_string(context)
conflict.to_string()
)),
self.tbl_name.0,
self.col_names
@@ -216,7 +218,7 @@ impl ToSqlString for ast::TriggerCmdUpdate {
"UPDATE {}{} SET {}{}{}",
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {}",
conflict.to_sql_string(context)
conflict.to_string()
)),
self.tbl_name.0, // TODO: should be a qualified table name,
self.sets

View File

@@ -13,7 +13,7 @@ impl ToSqlString for ast::Delete {
.as_ref()
.map_or("".to_string(), |indexed| format!(
" {}",
indexed.to_sql_string(context)
indexed.to_string()
)),
self.where_clause
.as_ref()

View File

@@ -10,7 +10,7 @@ impl ToSqlString for ast::Insert {
)),
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {} ",
conflict.to_sql_string(context)
conflict.to_string()
)),
self.tbl_name.to_sql_string(context),
self.columns

View File

@@ -108,7 +108,7 @@ impl ToSqlString for ast::Stmt {
" ({})",
columns
.iter()
.map(|col| col.to_sql_string(context))
.map(|col| col.to_string())
.collect::<Vec<_>>()
.join(", ")
)),

View File

@@ -1,5 +1,7 @@
use std::fmt::Display;
use crate::{
ast::{self},
ast::{self, fmt::ToTokens},
to_sql_string::{ToSqlContext, ToSqlString},
};
@@ -37,7 +39,7 @@ impl ToSqlString for ast::SelectBody {
let compound_selects = compounds
.iter()
.map(|compound_select| {
let mut curr = compound_select.operator.to_sql_string(context);
let mut curr = compound_select.operator.to_string();
curr.push(' ');
curr.push_str(&compound_select.select.to_sql_string(context));
curr
@@ -78,7 +80,7 @@ impl ToSqlString for ast::SelectInner {
let mut ret = Vec::with_capacity(2 + self.columns.len());
ret.push("SELECT".to_string());
if let Some(distinct) = self.distinctness {
ret.push(distinct.to_sql_string(context));
ret.push(distinct.to_string());
}
let joined_cols = self
.columns
@@ -124,7 +126,7 @@ impl ToSqlString for ast::FromClause {
let joined_joins = joins
.iter()
.map(|join| {
let mut curr = join.operator.to_sql_string(context);
let mut curr = join.operator.to_string();
curr.push(' ');
curr.push_str(&join.table.to_sql_string(context));
if let Some(join_constraint) = &join.constraint {
@@ -149,11 +151,11 @@ impl ToSqlString for ast::SelectTable {
ret.push_str(&name.to_sql_string(context));
if let Some(alias) = alias {
ret.push(' ');
ret.push_str(&alias.to_sql_string(context));
ret.push_str(&alias.to_string());
}
if let Some(indexed) = indexed {
ret.push(' ');
ret.push_str(&indexed.to_sql_string(context));
ret.push_str(&indexed.to_string());
}
}
Self::TableCall(table_func, args, alias) => {
@@ -169,7 +171,7 @@ impl ToSqlString for ast::SelectTable {
}
if let Some(alias) = alias {
ret.push(' ');
ret.push_str(&alias.to_sql_string(context));
ret.push_str(&alias.to_string());
}
}
Self::Select(select, alias) => {
@@ -178,7 +180,7 @@ impl ToSqlString for ast::SelectTable {
ret.push(')');
if let Some(alias) = alias {
ret.push(' ');
ret.push_str(&alias.to_sql_string(context));
ret.push_str(&alias.to_string());
}
}
Self::Sub(from_clause, alias) => {
@@ -187,7 +189,7 @@ impl ToSqlString for ast::SelectTable {
ret.push(')');
if let Some(alias) = alias {
ret.push(' ');
ret.push_str(&alias.to_sql_string(context));
ret.push_str(&alias.to_string());
}
}
}
@@ -232,7 +234,7 @@ impl ToSqlString for ast::CommonTableExpr {
if let Some(cols) = &self.columns {
let joined_cols = cols
.iter()
.map(|col| col.to_sql_string(context))
.map(|col| col.to_string())
.collect::<Vec<_>>()
.join(", ");
@@ -241,7 +243,7 @@ impl ToSqlString for ast::CommonTableExpr {
ret.push(format!(
"AS {}({})",
{
let mut materialized = self.materialized.to_sql_string(context);
let mut materialized = self.materialized.to_string();
if !materialized.is_empty() {
materialized.push(' ');
}
@@ -253,9 +255,9 @@ impl ToSqlString for ast::CommonTableExpr {
}
}
impl ToSqlString for ast::IndexedColumn {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
self.col_name.0.to_string()
impl Display for ast::IndexedColumn {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.col_name.0)
}
}
@@ -264,56 +266,36 @@ impl ToSqlString for ast::SortedColumn {
let mut curr = self.expr.to_sql_string(context);
if let Some(sort_order) = self.order {
curr.push(' ');
curr.push_str(&sort_order.to_sql_string(context));
curr.push_str(&sort_order.to_string());
}
if let Some(nulls_order) = self.nulls {
curr.push(' ');
curr.push_str(&nulls_order.to_sql_string(context));
curr.push_str(&nulls_order.to_string());
}
curr
}
}
impl ToSqlString for ast::SortOrder {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Asc => "ASC",
Self::Desc => "DESC",
}
.to_string()
impl Display for ast::SortOrder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
impl ToSqlString for ast::NullsOrder {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::First => "NULLS FIRST",
Self::Last => "NULLS LAST",
}
.to_string()
impl Display for ast::NullsOrder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
impl ToSqlString for ast::Materialized {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
impl Display for ast::Materialized {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = match self {
Self::Any => "",
Self::No => "NOT MATERIALIZED",
Self::Yes => "MATERIALIZED",
}
.to_string()
}
}
impl ToSqlString for ast::CompoundOperator {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Except => "EXCEPT",
Self::Intersect => "INTERSECT",
Self::Union => "UNION",
Self::UnionAll => "UNION ALL",
}
.to_string()
};
write!(f, "{}", value)
}
}
@@ -325,7 +307,7 @@ impl ToSqlString for ast::ResultColumn {
ret.push_str(&expr.to_sql_string(context));
if let Some(alias) = alias {
ret.push(' ');
ret.push_str(&alias.to_sql_string(context));
ret.push_str(&alias.to_string());
}
}
Self::Star => {
@@ -339,70 +321,85 @@ impl ToSqlString for ast::ResultColumn {
}
}
impl ToSqlString for ast::As {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::As(alias) => {
format!("AS {}", alias.0)
impl Display for ast::As {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::As(alias) => {
format!("AS {}", alias.0)
}
Self::Elided(alias) => alias.0.clone(),
}
Self::Elided(alias) => alias.0.clone(),
}
)
}
}
impl ToSqlString for ast::Indexed {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::NotIndexed => "NOT INDEXED".to_string(),
Self::IndexedBy(name) => format!("INDEXED BY {}", name.0),
}
impl Display for ast::Indexed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::NotIndexed => "NOT INDEXED".to_string(),
Self::IndexedBy(name) => format!("INDEXED BY {}", name.0),
}
)
}
}
impl ToSqlString for ast::JoinOperator {
fn to_sql_string<C: ToSqlContext>(&self, context: &C) -> String {
match self {
Self::Comma => ",".to_string(),
Self::TypedJoin(join) => {
let join_keyword = "JOIN";
if let Some(join) = join {
format!("{} {}", join.to_sql_string(context), join_keyword)
} else {
join_keyword.to_string()
impl Display for ast::JoinOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Comma => ",".to_string(),
Self::TypedJoin(join) => {
let join_keyword = "JOIN";
if let Some(join) = join {
format!("{} {}", join.to_string(), join_keyword)
} else {
join_keyword.to_string()
}
}
}
}
)
}
}
impl ToSqlString for ast::JoinType {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
let mut modifiers = Vec::new();
if self.contains(Self::NATURAL) {
modifiers.push("NATURAL");
}
if self.contains(Self::LEFT) || self.contains(Self::RIGHT) {
// TODO: I think the parser incorrectly asigns outer to every LEFT and RIGHT query
if self.contains(Self::LEFT | Self::RIGHT) {
modifiers.push("FULL");
} else if self.contains(Self::LEFT) {
modifiers.push("LEFT");
} else if self.contains(Self::RIGHT) {
modifiers.push("RIGHT");
impl Display for ast::JoinType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let value = {
let mut modifiers = Vec::new();
if self.contains(Self::NATURAL) {
modifiers.push("NATURAL");
}
if self.contains(Self::LEFT) || self.contains(Self::RIGHT) {
// TODO: I think the parser incorrectly asigns outer to every LEFT and RIGHT query
if self.contains(Self::LEFT | Self::RIGHT) {
modifiers.push("FULL");
} else if self.contains(Self::LEFT) {
modifiers.push("LEFT");
} else if self.contains(Self::RIGHT) {
modifiers.push("RIGHT");
}
// FIXME: ignore outer joins as I think they are parsed incorrectly in the bitflags
// if self.contains(Self::OUTER) {
// modifiers.push("OUTER");
// }
}
// FIXME: ignore outer joins as I think they are parsed incorrectly in the bitflags
// if self.contains(Self::OUTER) {
// modifiers.push("OUTER");
// }
}
if self.contains(Self::INNER) {
modifiers.push("INNER");
}
if self.contains(Self::CROSS) {
modifiers.push("CROSS");
}
modifiers.join(" ")
if self.contains(Self::INNER) {
modifiers.push("INNER");
}
if self.contains(Self::CROSS) {
modifiers.push("CROSS");
}
modifiers.join(" ")
};
write!(f, "{}", value)
}
}
@@ -479,7 +476,7 @@ impl ToSqlString for ast::Window {
impl ToSqlString for ast::FrameClause {
fn to_sql_string<C: ToSqlContext>(&self, context: &C) -> String {
let mut ret = Vec::new();
ret.push(self.mode.to_sql_string(context));
ret.push(self.mode.to_string());
let start_sql = self.start.to_sql_string(context);
if let Some(end) = &self.end {
ret.push(format!(
@@ -491,21 +488,16 @@ impl ToSqlString for ast::FrameClause {
ret.push(start_sql);
}
if let Some(exclude) = &self.exclude {
ret.push(exclude.to_sql_string(context));
ret.push(exclude.to_string());
}
ret.join(" ")
}
}
impl ToSqlString for ast::FrameMode {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
match self {
Self::Groups => "GROUPS",
Self::Range => "RANGE",
Self::Rows => "ROWS",
}
.to_string()
impl Display for ast::FrameMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
@@ -521,15 +513,17 @@ impl ToSqlString for ast::FrameBound {
}
}
impl ToSqlString for ast::FrameExclude {
fn to_sql_string<C: ToSqlContext>(&self, _context: &C) -> String {
let clause = match self {
Self::CurrentRow => "CURRENT ROW",
Self::Group => "GROUP",
Self::NoOthers => "NO OTHERS",
Self::Ties => "TIES",
};
format!("EXCLUDE {}", clause)
impl Display for ast::FrameExclude {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", {
let clause = match self {
Self::CurrentRow => "CURRENT ROW",
Self::Group => "GROUP",
Self::NoOthers => "NO OTHERS",
Self::Ties => "TIES",
};
format!("EXCLUDE {}", clause)
})
}
}
@@ -658,4 +652,22 @@ mod tests {
);
to_sql_string_test!(test_select_with_aggregate_window, "SELECT a, SUM(b) OVER (PARTITION BY c ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS running_sum FROM t;");
to_sql_string_test!(
test_select_with_exclude,
"SELECT
c.name,
o.order_id,
o.order_amount,
SUM(o.order_amount) OVER (PARTITION BY c.id
ORDER BY o.order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
EXCLUDE CURRENT ROW) AS running_total_excluding_current
FROM customers c
JOIN orders o ON c.id = o.customer_id
WHERE EXISTS (SELECT 1
FROM orders o2
WHERE o2.customer_id = c.id
AND o2.order_amount > 1000);"
);
}

View File

@@ -10,14 +10,14 @@ impl ToSqlString for ast::Update {
)),
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {} ",
conflict.to_sql_string(context)
conflict.to_string()
)),
self.tbl_name.to_sql_string(context),
self.indexed
.as_ref()
.map_or("".to_string(), |indexed| format!(
" {}",
indexed.to_sql_string(context)
indexed.to_string()
)),
self.sets
.iter()