qusql_parse/create_view.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12use crate::{
13 QualifiedName, Span, Spanned, Statement,
14 create_option::CreateOption,
15 keywords::Keyword,
16 parser::{ParseError, Parser},
17 qualified_name::parse_qualified_name_unreserved,
18 statement::parse_compound_query,
19};
20use alloc::vec::Vec;
21
22/// Represent a create view statement
23/// ```
24/// # use qusql_parse::{SQLDialect, SQLArguments, ParseOptions, parse_statements, CreateView, Statement, Issues};
25/// # let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
26/// #
27/// let sql = "CREATE ALGORITHM=UNDEFINED DEFINER=`phpmyadmin`@`localhost` SQL SECURITY DEFINER
28/// VIEW `v1`
29/// AS SELECT
30/// `t1`.`id` AS `id`,
31/// `t1`.`c1` AS `c1`,
32/// (SELECT `t2`.`c2` FROM `t2` WHERE `t2`.`id` = `t1`.`c3`) AS `c2`
33/// FROM `t1` WHERE `t1`.`deleted` IS NULL;";
34/// let mut issues = Issues::new(sql);
35/// let mut stmts = parse_statements(sql, &mut issues, &options);
36///
37/// # assert!(issues.is_ok());
38/// let create: CreateView = match stmts.pop() {
39/// Some(Statement::CreateView(c)) => * c,
40/// _ => panic!("We should get an create view statement")
41/// };
42///
43/// assert!(create.name.identifier.as_str() == "v1");
44/// println!("{:#?}", create.select)
45/// ```
46
47#[derive(Clone, Debug)]
48pub struct CreateView<'a> {
49 /// Span of "CREATE"
50 pub create_span: Span,
51 /// Options after "CREATE"
52 pub create_options: Vec<CreateOption<'a>>,
53 /// Span of "VIEW"
54 pub view_span: Span,
55 /// Span of "IF NOT EXISTS" if specified
56 pub if_not_exists: Option<Span>,
57 /// Name of the created view
58 pub name: QualifiedName<'a>,
59 /// Span of "AS"
60 pub as_span: Span,
61 /// The select statement following "AS"
62 pub select: Statement<'a>,
63}
64
65impl<'a> Spanned for CreateView<'a> {
66 fn span(&self) -> Span {
67 self.create_span
68 .join_span(&self.create_options)
69 .join_span(&self.view_span)
70 .join_span(&self.if_not_exists)
71 .join_span(&self.name)
72 .join_span(&self.as_span)
73 .join_span(&self.select)
74 }
75}
76
77pub(crate) fn parse_create_view<'a>(
78 parser: &mut Parser<'a, '_>,
79 create_span: Span,
80 create_options: Vec<CreateOption<'a>>,
81) -> Result<CreateView<'a>, ParseError> {
82 let view_span = parser.consume_keyword(Keyword::VIEW)?;
83
84 let if_not_exists = if let Some(if_) = parser.skip_keyword(Keyword::IF) {
85 Some(
86 parser
87 .consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?
88 .join_span(&if_),
89 )
90 } else {
91 None
92 };
93
94 let name = parse_qualified_name_unreserved(parser)?;
95 // TODO (column_list)
96
97 let as_span = parser.consume_keyword(Keyword::AS)?;
98
99 let select = parse_compound_query(parser)?;
100
101 // TODO [WITH [CASCADED | LOCAL] CHECK OPTION]
102
103 Ok(CreateView {
104 create_span,
105 create_options,
106 view_span,
107 if_not_exists,
108 name,
109 as_span,
110 select,
111 })
112}