sqlparser_mysql/dds/
drop_view.rs

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/// parse `DROP VIEW [IF EXISTS]
17///     view_name [, view_name] ...
18///     [RESTRICT | CASCADE]`
19#[derive(Default, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
20pub struct DropViewStatement {
21    pub if_exists: bool,
22    /// A name of a table, view, custom type, etc., possibly multipart, i.e. db.schema.obj
23    pub views: Vec<String>,
24    pub if_restrict: bool,
25    pub if_cascade: bool,
26}
27
28impl DropViewStatement {
29    /// DROP VIEW [IF EXISTS]
30    ///     view_name [, view_name] ...
31    ///     [RESTRICT | CASCADE]
32    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}