Skip to content

Commit 12655c2

Browse files
authored
Merge pull request #14 from Embucket/issues/510_create_database
Snowflake create database
2 parents 97c03c0 + fa5fab0 commit 12655c2

File tree

12 files changed

+679
-23
lines changed

12 files changed

+679
-23
lines changed

src/ast/helpers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
// under the License.
1717
pub mod attached_token;
1818
pub mod key_value_options;
19+
pub mod stmt_create_database;
1920
pub mod stmt_create_table;
2021
pub mod stmt_data_loading;
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
#[cfg(not(feature = "std"))]
19+
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
20+
21+
#[cfg(feature = "serde")]
22+
use serde::{Deserialize, Serialize};
23+
24+
#[cfg(feature = "visitor")]
25+
use sqlparser_derive::{Visit, VisitMut};
26+
27+
use crate::ast::{
28+
CatalogSyncNamespaceMode, ContactEntry, ObjectName, Statement, StorageSerializationPolicy, Tag,
29+
};
30+
use crate::parser::ParserError;
31+
32+
/// Builder for create database statement variant ([1]).
33+
///
34+
/// This structure helps building and accessing a create database with more ease, without needing to:
35+
/// - Match the enum itself a lot of times; or
36+
/// - Moving a lot of variables around the code.
37+
///
38+
/// # Example
39+
/// ```rust
40+
/// use sqlparser::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
41+
/// use sqlparser::ast::{ColumnDef, Ident, ObjectName};
42+
/// let builder = CreateDatabaseBuilder::new(ObjectName::from(vec![Ident::new("database_name")]))
43+
/// .if_not_exists(true);
44+
/// // You can access internal elements with ease
45+
/// assert!(builder.if_not_exists);
46+
/// // Convert to a statement
47+
/// assert_eq!(
48+
/// builder.build().to_string(),
49+
/// "CREATE DATABASE IF NOT EXISTS database_name"
50+
/// )
51+
/// ```
52+
///
53+
/// [1]: Statement::CreateDatabase
54+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
57+
pub struct CreateDatabaseBuilder {
58+
pub db_name: ObjectName,
59+
pub if_not_exists: bool,
60+
pub location: Option<String>,
61+
pub managed_location: Option<String>,
62+
pub or_replace: bool,
63+
pub transient: bool,
64+
pub clone: Option<ObjectName>,
65+
pub data_retention_time_in_days: Option<u64>,
66+
pub max_data_extension_time_in_days: Option<u64>,
67+
pub external_volume: Option<String>,
68+
pub catalog: Option<String>,
69+
pub replace_invalid_characters: Option<bool>,
70+
pub default_ddl_collation: Option<String>,
71+
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
72+
pub comment: Option<String>,
73+
pub catalog_sync: Option<String>,
74+
pub catalog_sync_namespace_mode: Option<CatalogSyncNamespaceMode>,
75+
pub catalog_sync_namespace_flatten_delimiter: Option<String>,
76+
pub with_tags: Option<Vec<Tag>>,
77+
pub with_contacts: Option<Vec<ContactEntry>>,
78+
}
79+
80+
impl CreateDatabaseBuilder {
81+
pub fn new(name: ObjectName) -> Self {
82+
Self {
83+
db_name: name,
84+
if_not_exists: false,
85+
location: None,
86+
managed_location: None,
87+
or_replace: false,
88+
transient: false,
89+
clone: None,
90+
data_retention_time_in_days: None,
91+
max_data_extension_time_in_days: None,
92+
external_volume: None,
93+
catalog: None,
94+
replace_invalid_characters: None,
95+
default_ddl_collation: None,
96+
storage_serialization_policy: None,
97+
comment: None,
98+
catalog_sync: None,
99+
catalog_sync_namespace_mode: None,
100+
catalog_sync_namespace_flatten_delimiter: None,
101+
with_tags: None,
102+
with_contacts: None,
103+
}
104+
}
105+
106+
pub fn location(mut self, location: Option<String>) -> Self {
107+
self.location = location;
108+
self
109+
}
110+
111+
pub fn managed_location(mut self, managed_location: Option<String>) -> Self {
112+
self.managed_location = managed_location;
113+
self
114+
}
115+
116+
pub fn or_replace(mut self, or_replace: bool) -> Self {
117+
self.or_replace = or_replace;
118+
self
119+
}
120+
121+
pub fn transient(mut self, transient: bool) -> Self {
122+
self.transient = transient;
123+
self
124+
}
125+
126+
pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
127+
self.if_not_exists = if_not_exists;
128+
self
129+
}
130+
131+
pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
132+
self.clone = clone;
133+
self
134+
}
135+
136+
pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
137+
self.data_retention_time_in_days = data_retention_time_in_days;
138+
self
139+
}
140+
141+
pub fn max_data_extension_time_in_days(
142+
mut self,
143+
max_data_extension_time_in_days: Option<u64>,
144+
) -> Self {
145+
self.max_data_extension_time_in_days = max_data_extension_time_in_days;
146+
self
147+
}
148+
149+
pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
150+
self.external_volume = external_volume;
151+
self
152+
}
153+
154+
pub fn catalog(mut self, catalog: Option<String>) -> Self {
155+
self.catalog = catalog;
156+
self
157+
}
158+
159+
pub fn replace_invalid_characters(mut self, replace_invalid_characters: Option<bool>) -> Self {
160+
self.replace_invalid_characters = replace_invalid_characters;
161+
self
162+
}
163+
164+
pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
165+
self.default_ddl_collation = default_ddl_collation;
166+
self
167+
}
168+
169+
pub fn storage_serialization_policy(
170+
mut self,
171+
storage_serialization_policy: Option<StorageSerializationPolicy>,
172+
) -> Self {
173+
self.storage_serialization_policy = storage_serialization_policy;
174+
self
175+
}
176+
177+
pub fn comment(mut self, comment: Option<String>) -> Self {
178+
self.comment = comment;
179+
self
180+
}
181+
182+
pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
183+
self.catalog_sync = catalog_sync;
184+
self
185+
}
186+
187+
pub fn catalog_sync_namespace_mode(
188+
mut self,
189+
catalog_sync_namespace_mode: Option<CatalogSyncNamespaceMode>,
190+
) -> Self {
191+
self.catalog_sync_namespace_mode = catalog_sync_namespace_mode;
192+
self
193+
}
194+
195+
pub fn catalog_sync_namespace_flatten_delimiter(
196+
mut self,
197+
catalog_sync_namespace_flatten_delimiter: Option<String>,
198+
) -> Self {
199+
self.catalog_sync_namespace_flatten_delimiter = catalog_sync_namespace_flatten_delimiter;
200+
self
201+
}
202+
203+
pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
204+
self.with_tags = with_tags;
205+
self
206+
}
207+
208+
pub fn with_contacts(mut self, with_contacts: Option<Vec<ContactEntry>>) -> Self {
209+
self.with_contacts = with_contacts;
210+
self
211+
}
212+
213+
pub fn build(self) -> Statement {
214+
Statement::CreateDatabase {
215+
db_name: self.db_name,
216+
if_not_exists: self.if_not_exists,
217+
managed_location: self.managed_location,
218+
location: self.location,
219+
or_replace: self.or_replace,
220+
transient: self.transient,
221+
clone: self.clone,
222+
data_retention_time_in_days: self.data_retention_time_in_days,
223+
max_data_extension_time_in_days: self.max_data_extension_time_in_days,
224+
external_volume: self.external_volume,
225+
catalog: self.catalog,
226+
replace_invalid_characters: self.replace_invalid_characters,
227+
default_ddl_collation: self.default_ddl_collation,
228+
storage_serialization_policy: self.storage_serialization_policy,
229+
comment: self.comment,
230+
catalog_sync: self.catalog_sync,
231+
catalog_sync_namespace_mode: self.catalog_sync_namespace_mode,
232+
catalog_sync_namespace_flatten_delimiter: self.catalog_sync_namespace_flatten_delimiter,
233+
with_tags: self.with_tags,
234+
with_contacts: self.with_contacts,
235+
}
236+
}
237+
}
238+
239+
impl TryFrom<Statement> for CreateDatabaseBuilder {
240+
type Error = ParserError;
241+
242+
fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
243+
match stmt {
244+
Statement::CreateDatabase {
245+
db_name,
246+
if_not_exists,
247+
location,
248+
managed_location,
249+
or_replace,
250+
transient,
251+
clone,
252+
data_retention_time_in_days,
253+
max_data_extension_time_in_days,
254+
external_volume,
255+
catalog,
256+
replace_invalid_characters,
257+
default_ddl_collation,
258+
storage_serialization_policy,
259+
comment,
260+
catalog_sync,
261+
catalog_sync_namespace_mode,
262+
catalog_sync_namespace_flatten_delimiter,
263+
with_tags,
264+
with_contacts,
265+
} => Ok(Self {
266+
db_name,
267+
if_not_exists,
268+
location,
269+
managed_location,
270+
or_replace,
271+
transient,
272+
clone,
273+
data_retention_time_in_days,
274+
max_data_extension_time_in_days,
275+
external_volume,
276+
catalog,
277+
replace_invalid_characters,
278+
default_ddl_collation,
279+
storage_serialization_policy,
280+
comment,
281+
catalog_sync,
282+
catalog_sync_namespace_mode,
283+
catalog_sync_namespace_flatten_delimiter,
284+
with_tags,
285+
with_contacts,
286+
}),
287+
_ => Err(ParserError::ParserError(format!(
288+
"Expected create database statement, but received: {stmt}"
289+
))),
290+
}
291+
}
292+
}
293+
294+
#[cfg(test)]
295+
mod tests {
296+
use crate::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
297+
use crate::ast::{Ident, ObjectName, Statement};
298+
use crate::parser::ParserError;
299+
300+
#[test]
301+
pub fn test_from_valid_statement() {
302+
let builder = CreateDatabaseBuilder::new(ObjectName::from(vec![Ident::new("db_name")]));
303+
304+
let stmt = builder.clone().build();
305+
306+
assert_eq!(builder, CreateDatabaseBuilder::try_from(stmt).unwrap());
307+
}
308+
309+
#[test]
310+
pub fn test_from_invalid_statement() {
311+
let stmt = Statement::Commit {
312+
chain: false,
313+
end: false,
314+
modifier: None,
315+
};
316+
317+
assert_eq!(
318+
CreateDatabaseBuilder::try_from(stmt).unwrap_err(),
319+
ParserError::ParserError(
320+
"Expected create database statement, but received: COMMIT".to_owned()
321+
)
322+
);
323+
}
324+
}

0 commit comments

Comments
 (0)