use keelson_core::clause::Set;
use keelson_core::expr::{Expr, IntoExpr, IntoExprList};
use keelson_core::{Mod, mod_fn};
use crate::extras::Overriding;
use crate::statement::{MergeAction, MergeInsert, MergeMatchKind, MergeQuery, MergeWhen};
pub use crate::shared::{
cross_join, from_item as using, full_join, inner_join, left_join, returning, right_join, set,
set_col, target_table as into, with,
};
pub fn on(condition: impl IntoExpr) -> impl Mod<MergeQuery> {
let condition = condition.into_expr();
mod_fn(move |q: &mut MergeQuery| q.on.push(condition))
}
pub fn when_matched() -> MatchedChain {
MatchedChain {
kind: MergeMatchKind::Matched,
condition: Vec::new(),
}
}
pub fn when_not_matched_by_source() -> MatchedChain {
MatchedChain {
kind: MergeMatchKind::NotMatchedBySource,
condition: Vec::new(),
}
}
pub fn when_not_matched() -> NotMatchedChain {
NotMatchedChain {
by_target: false,
condition: Vec::new(),
}
}
#[derive(Debug, Clone)]
pub struct MatchedChain {
kind: MergeMatchKind,
condition: Vec<Expr>,
}
impl MatchedChain {
#[must_use]
pub fn and(mut self, condition: impl IntoExpr) -> MatchedChain {
self.condition.push(condition.into_expr());
self
}
pub fn then_update(self, body: impl Mod<Set>) -> MergeWhenMod {
let mut set = Set::default();
body.apply(&mut set);
self.finish(MergeAction::Update(set))
}
pub fn then_delete(self) -> MergeWhenMod {
self.finish(MergeAction::Delete)
}
pub fn then_do_nothing(self) -> MergeWhenMod {
self.finish(MergeAction::DoNothing)
}
fn finish(self, action: MergeAction) -> MergeWhenMod {
MergeWhenMod {
when: MergeWhen {
kind: self.kind,
condition: self.condition,
action,
},
}
}
}
#[derive(Debug, Clone)]
pub struct NotMatchedChain {
by_target: bool,
condition: Vec<Expr>,
}
impl NotMatchedChain {
#[must_use]
pub fn by_target(mut self) -> NotMatchedChain {
self.by_target = true;
self
}
#[must_use]
pub fn and(mut self, condition: impl IntoExpr) -> NotMatchedChain {
self.condition.push(condition.into_expr());
self
}
pub fn then_insert(self) -> MergeInsertChain {
MergeInsertChain {
when: self,
insert: MergeInsert::default(),
}
}
pub fn then_do_nothing(self) -> MergeWhenMod {
MergeWhenMod {
when: MergeWhen {
kind: MergeMatchKind::NotMatched {
by_target: self.by_target,
},
condition: self.condition,
action: MergeAction::DoNothing,
},
}
}
}
#[derive(Debug, Clone)]
pub struct MergeInsertChain {
when: NotMatchedChain,
insert: MergeInsert,
}
impl MergeInsertChain {
#[must_use]
pub fn columns(
mut self,
columns: impl IntoIterator<Item = impl Into<std::borrow::Cow<'static, str>>>,
) -> MergeInsertChain {
self.insert.columns = columns.into_iter().map(Into::into).collect();
self
}
#[must_use]
pub fn overriding_system(mut self) -> MergeInsertChain {
self.insert.overriding = Some(Overriding::System);
self
}
#[must_use]
pub fn overriding_user(mut self) -> MergeInsertChain {
self.insert.overriding = Some(Overriding::User);
self
}
#[must_use]
pub fn values(mut self, row: impl IntoExprList) -> MergeInsertChain {
self.insert.row = row.into_expr_list();
self
}
}
impl Mod<MergeQuery> for MergeInsertChain {
fn apply(self, q: &mut MergeQuery) {
q.whens.push(MergeWhen {
kind: MergeMatchKind::NotMatched {
by_target: self.when.by_target,
},
condition: self.when.condition,
action: MergeAction::Insert(self.insert),
});
}
}
#[derive(Debug, Clone)]
pub struct MergeWhenMod {
when: MergeWhen,
}
impl Mod<MergeQuery> for MergeWhenMod {
fn apply(self, q: &mut MergeQuery) {
q.whens.push(self.when);
}
}