1use core::fmt;
2use std::fmt::Formatter;
3use std::str;
4
5use nom::bytes::complete::tag_no_case;
6use nom::character::complete::multispace0;
7use nom::character::complete::multispace1;
8use nom::combinator::{map, opt};
9use nom::multi::many0;
10use nom::sequence::{delimited, terminated, tuple};
11use nom::IResult;
12
13use base::error::ParseSQLError;
14use base::CommonParser;
15
16#[derive(Default, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
20pub struct DropViewStatement {
21 pub if_exists: bool,
22 pub views: Vec<String>,
24 pub if_restrict: bool,
25 pub if_cascade: bool,
26}
27
28impl DropViewStatement {
29 pub fn parse(i: &str) -> IResult<&str, DropViewStatement, ParseSQLError<&str>> {
33 let mut parser = tuple((
34 tag_no_case("DROP "),
35 multispace0,
36 tag_no_case("VIEW "),
37 CommonParser::parse_if_exists,
38 multispace0,
39 map(
40 many0(terminated(
41 CommonParser::sql_identifier,
42 opt(CommonParser::ws_sep_comma),
43 )),
44 |x| x.iter().map(|v| String::from(*v)).collect::<Vec<String>>(),
45 ),
46 opt(delimited(multispace1, tag_no_case("RESTRICT"), multispace0)),
47 opt(delimited(multispace1, tag_no_case("CASCADE"), multispace0)),
48 CommonParser::statement_terminator,
49 ));
50 let (
51 remaining_input,
52 (_, _, _, opt_if_exists, _, views, opt_if_restrict, opt_if_cascade, _),
53 ) = parser(i)?;
54
55 Ok((
56 remaining_input,
57 DropViewStatement {
58 views,
59 if_exists: opt_if_exists.is_some(),
60 if_restrict: opt_if_restrict.is_some(),
61 if_cascade: opt_if_cascade.is_some(),
62 },
63 ))
64 }
65}
66
67impl fmt::Display for DropViewStatement {
68 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69 write!(f, "DROP VIEW")?;
70 if self.if_exists {
71 write!(f, " IF EXISTS")?;
72 }
73
74 let view_name = self.views.join(", ");
75 write!(f, " {}", view_name)?;
76
77 if self.if_restrict {
78 write!(f, " RESTRICT")?;
79 }
80 if self.if_cascade {
81 write!(f, " CASCADE")?;
82 }
83 Ok(())
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use dds::drop_view::DropViewStatement;
90
91 #[test]
92 fn parse_drop_view() {
93 let sqls = [
94 "DROP VIEW view_name;",
95 "DROP VIEW IF EXISTS view_name;",
96 "DROP VIEW view_name CASCADE;",
97 "DROP VIEW view_name1, view_name2;",
98 "DROP VIEW view_name1, view_name2 RESTRICT;",
99 ];
100
101 let exp_statements = [
102 DropViewStatement {
103 if_exists: false,
104 views: vec!["view_name".to_string()],
105 if_restrict: false,
106 if_cascade: false,
107 },
108 DropViewStatement {
109 if_exists: true,
110 views: vec!["view_name".to_string()],
111 if_restrict: false,
112 if_cascade: false,
113 },
114 DropViewStatement {
115 if_exists: false,
116 views: vec!["view_name".to_string()],
117 if_restrict: false,
118 if_cascade: true,
119 },
120 DropViewStatement {
121 if_exists: false,
122 views: vec!["view_name1".to_string(), "view_name2".to_string()],
123 if_restrict: false,
124 if_cascade: false,
125 },
126 DropViewStatement {
127 if_exists: false,
128 views: vec!["view_name1".to_string(), "view_name2".to_string()],
129 if_restrict: true,
130 if_cascade: false,
131 },
132 ];
133
134 for i in 0..sqls.len() {
135 let res = DropViewStatement::parse(sqls[i]);
136 assert!(res.is_ok());
137 assert_eq!(res.unwrap().1, exp_statements[i]);
138 }
139 }
140}