scylladb_parse/statements/
trigger.rs1use super::*;
2
3#[derive(ParseFromStr, Clone, Debug, TryInto, From, ToTokens, PartialEq, Eq)]
4#[parse_via(TaggedTriggerStatement)]
5pub enum TriggerStatement {
6 Create(CreateTriggerStatement),
7 Drop(DropTriggerStatement),
8}
9
10impl TryFrom<TaggedTriggerStatement> for TriggerStatement {
11 type Error = anyhow::Error;
12
13 fn try_from(value: TaggedTriggerStatement) -> Result<Self, Self::Error> {
14 Ok(match value {
15 TaggedTriggerStatement::Create(value) => TriggerStatement::Create(value.try_into()?),
16 TaggedTriggerStatement::Drop(value) => TriggerStatement::Drop(value.try_into()?),
17 })
18 }
19}
20
21#[derive(ParseFromStr, Clone, Debug, TryInto, From, ToTokens, PartialEq, Eq)]
22#[tokenize_as(TriggerStatement)]
23pub enum TaggedTriggerStatement {
24 Create(TaggedCreateTriggerStatement),
25 Drop(TaggedDropTriggerStatement),
26}
27
28impl Parse for TaggedTriggerStatement {
29 type Output = Self;
30 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
31 Ok(if s.check::<CREATE>() {
32 Self::Create(s.parse()?)
33 } else if s.check::<DROP>() {
34 Self::Drop(s.parse()?)
35 } else {
36 anyhow::bail!("Expected a trigger statement, found {}", s.info())
37 })
38 }
39}
40
41impl Display for TriggerStatement {
42 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43 match self {
44 Self::Create(stmt) => stmt.fmt(f),
45 Self::Drop(stmt) => stmt.fmt(f),
46 }
47 }
48}
49
50#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
51#[parse_via(TaggedCreateTriggerStatement)]
52pub struct CreateTriggerStatement {
53 #[builder(setter(name = "set_if_not_exists"), default)]
54 pub if_not_exists: bool,
55 #[builder(setter(into))]
56 pub name: Name,
57 #[builder(setter(into))]
58 pub table: KeyspaceQualifiedName,
59 #[builder(setter(into))]
60 pub using: LitStr,
61}
62
63impl TryFrom<TaggedCreateTriggerStatement> for CreateTriggerStatement {
64 type Error = anyhow::Error;
65
66 fn try_from(value: TaggedCreateTriggerStatement) -> Result<Self, Self::Error> {
67 Ok(Self {
68 if_not_exists: value.if_not_exists,
69 name: value.name.into_value()?,
70 table: value.table.try_into()?,
71 using: value.using.into_value()?,
72 })
73 }
74}
75
76#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
77#[tokenize_as(CreateTriggerStatement)]
78pub struct TaggedCreateTriggerStatement {
79 #[builder(setter(name = "set_if_not_exists"), default)]
80 pub if_not_exists: bool,
81 pub name: Tag<Name>,
82 pub table: TaggedKeyspaceQualifiedName,
83 pub using: Tag<LitStr>,
84}
85
86impl CreateTriggerStatementBuilder {
87 pub fn if_not_exists(&mut self) -> &mut Self {
90 self.if_not_exists.replace(true);
91 self
92 }
93}
94
95impl Parse for TaggedCreateTriggerStatement {
96 type Output = Self;
97 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
98 s.parse::<(CREATE, TRIGGER)>()?;
99 let mut res = TaggedCreateTriggerStatementBuilder::default();
100 res.set_if_not_exists(s.parse::<Option<(IF, NOT, EXISTS)>>()?.is_some())
101 .name(s.parse()?)
102 .table(s.parse::<(ON, _)>()?.1)
103 .using(s.parse::<(USING, _)>()?.1);
104 s.parse::<Option<Semicolon>>()?;
105 Ok(res
106 .build()
107 .map_err(|e| anyhow::anyhow!("Invalid CREATE TRIGGER statement: {}", e))?)
108 }
109}
110
111impl Display for CreateTriggerStatement {
112 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
113 write!(
114 f,
115 "CREATE TRIGGER{} {} ON {} USING {}",
116 if self.if_not_exists { " IF NOT EXISTS" } else { "" },
117 self.name,
118 self.table,
119 self.using
120 )
121 }
122}
123
124#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
125#[parse_via(TaggedDropTriggerStatement)]
126pub struct DropTriggerStatement {
127 #[builder(setter(name = "set_if_exists"), default)]
128 pub if_exists: bool,
129 #[builder(setter(into))]
130 pub name: Name,
131 #[builder(setter(into))]
132 pub table: KeyspaceQualifiedName,
133}
134
135impl TryFrom<TaggedDropTriggerStatement> for DropTriggerStatement {
136 type Error = anyhow::Error;
137 fn try_from(value: TaggedDropTriggerStatement) -> Result<Self, Self::Error> {
138 Ok(Self {
139 if_exists: value.if_exists,
140 name: value.name.into_value()?,
141 table: value.table.try_into()?,
142 })
143 }
144}
145
146#[derive(ParseFromStr, Builder, Clone, Debug, ToTokens, PartialEq, Eq)]
147#[tokenize_as(DropTriggerStatement)]
148pub struct TaggedDropTriggerStatement {
149 #[builder(setter(name = "set_if_exists"), default)]
150 pub if_exists: bool,
151 pub name: Tag<Name>,
152 pub table: TaggedKeyspaceQualifiedName,
153}
154
155impl DropTriggerStatementBuilder {
156 pub fn if_exists(&mut self) -> &mut Self {
159 self.if_exists.replace(true);
160 self
161 }
162}
163
164impl Parse for TaggedDropTriggerStatement {
165 type Output = Self;
166 fn parse(s: &mut StatementStream<'_>) -> anyhow::Result<Self::Output> {
167 s.parse::<(DROP, TRIGGER)>()?;
168 let mut res = TaggedDropTriggerStatementBuilder::default();
169 res.set_if_exists(s.parse::<Option<(IF, EXISTS)>>()?.is_some())
170 .name(s.parse()?)
171 .table(s.parse::<(ON, _)>()?.1);
172 s.parse::<Option<Semicolon>>()?;
173 Ok(res
174 .build()
175 .map_err(|e| anyhow::anyhow!("Invalid DROP TRIGGER statement: {}", e))?)
176 }
177}
178
179impl Display for DropTriggerStatement {
180 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
181 write!(
182 f,
183 "DROP TRIGGER{} {} ON {}",
184 if self.if_exists { " IF EXISTS" } else { "" },
185 self.name,
186 self.table
187 )
188 }
189}
190
191#[cfg(test)]
192mod test {
193 use super::*;
194 use crate::KeyspaceQualifyExt;
195
196 #[test]
197 fn test_parse_create_trigger() {
198 let mut builder = CreateTriggerStatementBuilder::default();
199 builder.name("test_trigger");
200 assert!(builder.build().is_err());
201 builder.table("test_keyspace".dot("my_table"));
202 assert!(builder.build().is_err());
203 builder.using("test_trigger_function");
204 let statement = builder.build().unwrap().to_string();
205 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
206 builder.if_not_exists();
207 let statement = builder.build().unwrap().to_string();
208 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
209 }
210
211 #[test]
212 fn test_parse_drop_trigger() {
213 let mut builder = DropTriggerStatementBuilder::default();
214 builder.name("test_trigger");
215 assert!(builder.build().is_err());
216 builder.table("test_keyspace".dot("my_table"));
217 let statement = builder.build().unwrap().to_string();
218 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
219 builder.if_exists();
220 let statement = builder.build().unwrap().to_string();
221 assert_eq!(builder.build().unwrap(), statement.parse().unwrap());
222 }
223}