use serde::{Deserialize, Serialize};
use crate::identifier::{Identifier, QualifiedName};
use crate::ir::constraint::Deferrable;
use crate::ir::default_expr::NormalizedExpr;
use crate::ir::eq::DiffMacro;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, DiffMacro)]
pub struct Trigger {
pub qname: QualifiedName,
pub table: QualifiedName,
#[diff(via_debug)]
pub timing: TriggerTiming,
#[diff(via_debug)]
pub events: Vec<TriggerEvent>,
#[diff(via_debug)]
pub level: TriggerLevel,
#[diff(via_debug)]
pub when_clause: Option<NormalizedExpr>,
#[diff(via_debug)]
pub transition_tables: Vec<TransitionTable>,
pub function_qname: QualifiedName,
#[diff(via_debug)]
pub function_args: Vec<String>,
pub is_constraint: bool,
#[diff(via_debug)]
pub deferrable: Deferrable,
#[diff(via_debug)]
pub comment: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TriggerTiming {
Before,
After,
InsteadOf,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum TriggerEvent {
Insert,
Update {
columns: Vec<Identifier>,
},
Delete,
Truncate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TriggerLevel {
Row,
Statement,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TransitionTable {
pub name: Identifier,
pub kind: TransitionKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TransitionKind {
NewTable,
OldTable,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ir::eq::Diff;
fn id(s: &str) -> Identifier {
Identifier::from_unquoted(s).unwrap()
}
fn qn(schema: &str, name: &str) -> QualifiedName {
QualifiedName::new(id(schema), id(name))
}
fn trg(name: &str) -> Trigger {
Trigger {
qname: qn("app", name),
table: qn("app", "users"),
timing: TriggerTiming::Before,
events: vec![TriggerEvent::Insert],
level: TriggerLevel::Row,
when_clause: None,
transition_tables: vec![],
function_qname: qn("app", "fn"),
function_args: vec![],
is_constraint: false,
deferrable: Deferrable::NotDeferrable,
comment: None,
}
}
#[test]
fn identical_triggers_diff_empty() {
assert!(trg("t1").canonical_eq(&trg("t1")));
}
#[test]
fn different_timing_diffs_reports_timing() {
let a = trg("t1");
let mut b = trg("t1");
b.timing = TriggerTiming::After;
let d = a.diff(&b);
assert!(d.iter().any(|x| x.path == "timing"));
}
#[test]
fn different_events_diffs() {
let a = trg("t1");
let mut b = trg("t1");
b.events = vec![TriggerEvent::Delete];
let d = a.diff(&b);
assert!(d.iter().any(|x| x.path == "events"));
}
}