blob: 58a7b0906bad228fcee9e0027bacbc08f7b447ae [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#[cfg(not(feature = "std"))]
use alloc::{format, string::String, vec::Vec};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use crate::ast::{
CatalogSyncNamespaceMode, ContactEntry, ObjectName, Statement, StorageSerializationPolicy, Tag,
};
use crate::parser::ParserError;
/// Builder for create database statement variant ([1]).
///
/// This structure helps building and accessing a create database with more ease, without needing to:
/// - Match the enum itself a lot of times; or
/// - Moving a lot of variables around the code.
///
/// # Example
/// ```rust
/// use sqlparser::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
/// use sqlparser::ast::{ColumnDef, Ident, ObjectName};
/// let builder = CreateDatabaseBuilder::new(ObjectName::from(vec![Ident::new("database_name")]))
/// .if_not_exists(true);
/// // You can access internal elements with ease
/// assert!(builder.if_not_exists);
/// // Convert to a statement
/// assert_eq!(
/// builder.build().to_string(),
/// "CREATE DATABASE IF NOT EXISTS database_name"
/// )
/// ```
///
/// [1]: Statement::CreateDatabase
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateDatabaseBuilder {
pub db_name: ObjectName,
pub if_not_exists: bool,
pub location: Option<String>,
pub managed_location: Option<String>,
pub or_replace: bool,
pub transient: bool,
pub clone: Option<ObjectName>,
pub data_retention_time_in_days: Option<u64>,
pub max_data_extension_time_in_days: Option<u64>,
pub external_volume: Option<String>,
pub catalog: Option<String>,
pub replace_invalid_characters: Option<bool>,
pub default_ddl_collation: Option<String>,
pub storage_serialization_policy: Option<StorageSerializationPolicy>,
pub comment: Option<String>,
pub catalog_sync: Option<String>,
pub catalog_sync_namespace_mode: Option<CatalogSyncNamespaceMode>,
pub catalog_sync_namespace_flatten_delimiter: Option<String>,
pub with_tags: Option<Vec<Tag>>,
pub with_contacts: Option<Vec<ContactEntry>>,
}
impl CreateDatabaseBuilder {
pub fn new(name: ObjectName) -> Self {
Self {
db_name: name,
if_not_exists: false,
location: None,
managed_location: None,
or_replace: false,
transient: false,
clone: None,
data_retention_time_in_days: None,
max_data_extension_time_in_days: None,
external_volume: None,
catalog: None,
replace_invalid_characters: None,
default_ddl_collation: None,
storage_serialization_policy: None,
comment: None,
catalog_sync: None,
catalog_sync_namespace_mode: None,
catalog_sync_namespace_flatten_delimiter: None,
with_tags: None,
with_contacts: None,
}
}
pub fn location(mut self, location: Option<String>) -> Self {
self.location = location;
self
}
pub fn managed_location(mut self, managed_location: Option<String>) -> Self {
self.managed_location = managed_location;
self
}
pub fn or_replace(mut self, or_replace: bool) -> Self {
self.or_replace = or_replace;
self
}
pub fn transient(mut self, transient: bool) -> Self {
self.transient = transient;
self
}
pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
self.if_not_exists = if_not_exists;
self
}
pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
self.clone = clone;
self
}
pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
self.data_retention_time_in_days = data_retention_time_in_days;
self
}
pub fn max_data_extension_time_in_days(
mut self,
max_data_extension_time_in_days: Option<u64>,
) -> Self {
self.max_data_extension_time_in_days = max_data_extension_time_in_days;
self
}
pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
self.external_volume = external_volume;
self
}
pub fn catalog(mut self, catalog: Option<String>) -> Self {
self.catalog = catalog;
self
}
pub fn replace_invalid_characters(mut self, replace_invalid_characters: Option<bool>) -> Self {
self.replace_invalid_characters = replace_invalid_characters;
self
}
pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
self.default_ddl_collation = default_ddl_collation;
self
}
pub fn storage_serialization_policy(
mut self,
storage_serialization_policy: Option<StorageSerializationPolicy>,
) -> Self {
self.storage_serialization_policy = storage_serialization_policy;
self
}
pub fn comment(mut self, comment: Option<String>) -> Self {
self.comment = comment;
self
}
pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
self.catalog_sync = catalog_sync;
self
}
pub fn catalog_sync_namespace_mode(
mut self,
catalog_sync_namespace_mode: Option<CatalogSyncNamespaceMode>,
) -> Self {
self.catalog_sync_namespace_mode = catalog_sync_namespace_mode;
self
}
pub fn catalog_sync_namespace_flatten_delimiter(
mut self,
catalog_sync_namespace_flatten_delimiter: Option<String>,
) -> Self {
self.catalog_sync_namespace_flatten_delimiter = catalog_sync_namespace_flatten_delimiter;
self
}
pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
self.with_tags = with_tags;
self
}
pub fn with_contacts(mut self, with_contacts: Option<Vec<ContactEntry>>) -> Self {
self.with_contacts = with_contacts;
self
}
pub fn build(self) -> Statement {
Statement::CreateDatabase {
db_name: self.db_name,
if_not_exists: self.if_not_exists,
managed_location: self.managed_location,
location: self.location,
or_replace: self.or_replace,
transient: self.transient,
clone: self.clone,
data_retention_time_in_days: self.data_retention_time_in_days,
max_data_extension_time_in_days: self.max_data_extension_time_in_days,
external_volume: self.external_volume,
catalog: self.catalog,
replace_invalid_characters: self.replace_invalid_characters,
default_ddl_collation: self.default_ddl_collation,
storage_serialization_policy: self.storage_serialization_policy,
comment: self.comment,
catalog_sync: self.catalog_sync,
catalog_sync_namespace_mode: self.catalog_sync_namespace_mode,
catalog_sync_namespace_flatten_delimiter: self.catalog_sync_namespace_flatten_delimiter,
with_tags: self.with_tags,
with_contacts: self.with_contacts,
}
}
}
impl TryFrom<Statement> for CreateDatabaseBuilder {
type Error = ParserError;
fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
match stmt {
Statement::CreateDatabase {
db_name,
if_not_exists,
location,
managed_location,
or_replace,
transient,
clone,
data_retention_time_in_days,
max_data_extension_time_in_days,
external_volume,
catalog,
replace_invalid_characters,
default_ddl_collation,
storage_serialization_policy,
comment,
catalog_sync,
catalog_sync_namespace_mode,
catalog_sync_namespace_flatten_delimiter,
with_tags,
with_contacts,
} => Ok(Self {
db_name,
if_not_exists,
location,
managed_location,
or_replace,
transient,
clone,
data_retention_time_in_days,
max_data_extension_time_in_days,
external_volume,
catalog,
replace_invalid_characters,
default_ddl_collation,
storage_serialization_policy,
comment,
catalog_sync,
catalog_sync_namespace_mode,
catalog_sync_namespace_flatten_delimiter,
with_tags,
with_contacts,
}),
_ => Err(ParserError::ParserError(format!(
"Expected create database statement, but received: {stmt}"
))),
}
}
}
#[cfg(test)]
mod tests {
use crate::ast::helpers::stmt_create_database::CreateDatabaseBuilder;
use crate::ast::{Ident, ObjectName, Statement};
use crate::parser::ParserError;
#[test]
pub fn test_from_valid_statement() {
let builder = CreateDatabaseBuilder::new(ObjectName::from(vec![Ident::new("db_name")]));
let stmt = builder.clone().build();
assert_eq!(builder, CreateDatabaseBuilder::try_from(stmt).unwrap());
}
#[test]
pub fn test_from_invalid_statement() {
let stmt = Statement::Commit {
chain: false,
end: false,
modifier: None,
};
assert_eq!(
CreateDatabaseBuilder::try_from(stmt).unwrap_err(),
ParserError::ParserError(
"Expected create database statement, but received: COMMIT".to_owned()
)
);
}
}