impl ToSqlString for CREATE TRIGGER stmt

This commit is contained in:
pedrocarlo
2025-05-28 11:44:40 -03:00
parent ba215c8ba9
commit a22d06cd66
2 changed files with 238 additions and 0 deletions

View File

@@ -0,0 +1,236 @@
use crate::{ast, to_sql_string::ToSqlString};
impl ToSqlString for ast::CreateTrigger {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
format!(
"CREATE{} TRIGGER {}{} {}{} ON {} {}{} BEGIN {} END",
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.tbl_name.to_sql_string(context),
self.for_each_row.then_some("FOR EACH ROW ").unwrap_or(""),
self.when_clause
.as_ref()
.map_or("".to_string(), |expr| expr.to_string()),
self.commands
.iter()
.map(|command| command.to_sql_string(context))
.collect::<Vec<_>>()
.join("; ")
)
}
}
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 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 ToSqlString for ast::TriggerCmd {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
match self {
Self::Delete(delete) => delete.to_sql_string(context),
Self::Insert(insert) => insert.to_sql_string(context),
Self::Select(select) => select.to_sql_string(context),
Self::Update(update) => update.to_sql_string(context),
}
}
}
impl ToSqlString for ast::TriggerCmdDelete {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
// https://sqlite.org/lang_createtrigger.html
// TODO: no CTEs and returning clause present in ast for delete
// Also for tbl_name it should be a qualified table name with indexed by clauses
format!(
"DELETE FROM {}{}",
self.tbl_name.0,
self.where_clause
.as_ref()
.map_or("".to_string(), |expr| format!(
" {}",
expr.to_sql_string(context)
))
)
}
}
impl ToSqlString for ast::TriggerCmdInsert {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
// https://sqlite.org/lang_createtrigger.html
// FOR TRIGGER SHOULD JUST USE REGULAR INSERT AST
// TODO: no ALIAS after table name
// TODO: no DEFAULT VALUES
format!(
"INSERT {}INTO {} {}{}{}{}",
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {} ",
conflict.to_sql_string(context)
)),
self.tbl_name.0,
self.col_names
.as_ref()
.map_or("".to_string(), |col_names| format!(
"({}) ",
col_names
.iter()
.map(|name| name.0.clone())
.collect::<Vec<_>>()
.join(", ")
)),
self.select.to_sql_string(context),
self.upsert
.as_ref()
.map_or("".to_string(), |upsert| format!(
" {}",
upsert.to_sql_string(context)
)),
self.returning
.as_ref()
.map_or("".to_string(), |returning| format!(
" RETURNING {}",
returning
.iter()
.map(|col| col.to_sql_string(context))
.collect::<Vec<_>>()
.join(", ")
))
)
}
}
impl ToSqlString for ast::Upsert {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
format!(
"ON CONFLICT {}{}{}",
self.index.as_ref().map_or("".to_string(), |index| format!(
"{} ",
index.to_sql_string(context)
)),
self.do_clause.to_sql_string(context),
self.next.as_ref().map_or("".to_string(), |next| format!(
" {}",
next.to_sql_string(context)
))
)
}
}
impl ToSqlString for ast::UpsertIndex {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
format!(
"({}){}",
self.targets
.iter()
.map(|target| target.to_sql_string(context))
.collect::<Vec<_>>()
.join(", "),
self.where_clause
.as_ref()
.map_or("".to_string(), |expr| format!(
" WHERE {}",
expr.to_sql_string(context)
))
)
}
}
impl ToSqlString for ast::UpsertDo {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
match self {
Self::Nothing => "NOTHING".to_string(),
Self::Set { sets, where_clause } => {
format!(
"UPDATE SET {}{}",
sets.iter()
.map(|set| set.to_sql_string(context))
.collect::<Vec<_>>()
.join(", "),
where_clause.as_ref().map_or("".to_string(), |expr| format!(
" WHERE {}",
expr.to_sql_string(context)
))
)
}
}
}
}
impl ToSqlString for ast::Set {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
if self.col_names.len() == 1 {
format!(
"{} = {}",
&self.col_names[0],
self.expr.to_sql_string(context)
)
} else {
format!(
"({}) = {}",
self.col_names
.iter()
.map(|name| name.0.clone())
.collect::<Vec<_>>()
.join(", "),
self.expr.to_sql_string(context)
)
}
}
}
impl ToSqlString for ast::TriggerCmdUpdate {
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
format!(
"UPDATE {}{} SET {}{}{}",
self.or_conflict.map_or("".to_string(), |conflict| format!(
"OR {}",
conflict.to_sql_string(context)
)),
self.tbl_name.0, // TODO: should be a qualified table name,
self.sets
.iter()
.map(|set| set.to_sql_string(context))
.collect::<Vec<_>>()
.join(", "),
self.from.as_ref().map_or("".to_string(), |from| format!(
" {}",
from.to_sql_string(context)
)),
self.where_clause
.as_ref()
.map_or("".to_string(), |expr| format!(
" WHERE {}",
expr.to_sql_string(context)
))
)
}
}

View File

@@ -4,6 +4,7 @@ use super::ToSqlString;
mod alter_table;
mod create_table;
mod create_trigger;
mod select;
impl ToSqlString for ast::Stmt {
@@ -91,6 +92,7 @@ impl ToSqlString for ast::Stmt {
body.to_sql_string(context)
)
}
Self::CreateTrigger(trigger) => trigger.to_sql_string(context),
Self::Select(select) => select.to_sql_string(context),
_ => todo!(),
}