-
Notifications
You must be signed in to change notification settings - Fork 602
Create table builder structure #659
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod stmt_create_table; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
#[cfg(not(feature = "std"))] | ||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec}; | ||
|
||
#[cfg(feature = "serde")] | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::ast::{ | ||
ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, ObjectName, OnCommit, Query, | ||
SqlOption, Statement, TableConstraint, | ||
}; | ||
use crate::parser::ParserError; | ||
|
||
/// Builder for create table statement variant ([1]). | ||
/// | ||
/// This structure helps building and accessing a create table 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_table::CreateTableBuilder; | ||
/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName}; | ||
/// let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")])) | ||
/// .if_not_exists(true) | ||
/// .columns(vec![ColumnDef { | ||
/// name: Ident::new("c1"), | ||
/// data_type: DataType::Int(None), | ||
/// collation: None, | ||
/// options: vec![], | ||
/// }]); | ||
/// // You can access internal elements with ease | ||
/// assert!(builder.if_not_exists); | ||
/// // Convert to a statement | ||
/// assert_eq!( | ||
/// builder.build().to_string(), | ||
/// "CREATE TABLE IF NOT EXISTS table_name (c1 INT)" | ||
/// ) | ||
/// ``` | ||
/// | ||
/// [1]: crate::ast::Statement::CreateTable | ||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct CreateTableBuilder { | ||
pub or_replace: bool, | ||
pub temporary: bool, | ||
pub external: bool, | ||
pub global: Option<bool>, | ||
pub if_not_exists: bool, | ||
pub name: ObjectName, | ||
pub columns: Vec<ColumnDef>, | ||
pub constraints: Vec<TableConstraint>, | ||
pub hive_distribution: HiveDistributionStyle, | ||
pub hive_formats: Option<HiveFormat>, | ||
pub table_properties: Vec<SqlOption>, | ||
pub with_options: Vec<SqlOption>, | ||
pub file_format: Option<FileFormat>, | ||
pub location: Option<String>, | ||
pub query: Option<Box<Query>>, | ||
pub without_rowid: bool, | ||
pub like: Option<ObjectName>, | ||
pub clone: Option<ObjectName>, | ||
pub engine: Option<String>, | ||
pub default_charset: Option<String>, | ||
pub collation: Option<String>, | ||
pub on_commit: Option<OnCommit>, | ||
pub on_cluster: Option<String>, | ||
} | ||
|
||
impl CreateTableBuilder { | ||
pub fn new(name: ObjectName) -> Self { | ||
Self { | ||
or_replace: false, | ||
temporary: false, | ||
external: false, | ||
global: None, | ||
if_not_exists: false, | ||
name, | ||
columns: vec![], | ||
constraints: vec![], | ||
hive_distribution: HiveDistributionStyle::NONE, | ||
hive_formats: None, | ||
table_properties: vec![], | ||
with_options: vec![], | ||
file_format: None, | ||
location: None, | ||
query: None, | ||
without_rowid: false, | ||
like: None, | ||
clone: None, | ||
engine: None, | ||
default_charset: None, | ||
collation: None, | ||
on_commit: None, | ||
on_cluster: None, | ||
} | ||
} | ||
pub fn or_replace(mut self, or_replace: bool) -> Self { | ||
self.or_replace = or_replace; | ||
self | ||
} | ||
|
||
pub fn temporary(mut self, temporary: bool) -> Self { | ||
self.temporary = temporary; | ||
self | ||
} | ||
|
||
pub fn external(mut self, external: bool) -> Self { | ||
self.external = external; | ||
self | ||
} | ||
|
||
pub fn global(mut self, global: Option<bool>) -> Self { | ||
self.global = global; | ||
self | ||
} | ||
|
||
pub fn if_not_exists(mut self, if_not_exists: bool) -> Self { | ||
self.if_not_exists = if_not_exists; | ||
self | ||
} | ||
|
||
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self { | ||
self.columns = columns; | ||
self | ||
} | ||
|
||
pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self { | ||
self.constraints = constraints; | ||
self | ||
} | ||
|
||
pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self { | ||
self.hive_distribution = hive_distribution; | ||
self | ||
} | ||
|
||
pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self { | ||
self.hive_formats = hive_formats; | ||
self | ||
} | ||
|
||
pub fn table_properties(mut self, table_properties: Vec<SqlOption>) -> Self { | ||
self.table_properties = table_properties; | ||
self | ||
} | ||
|
||
pub fn with_options(mut self, with_options: Vec<SqlOption>) -> Self { | ||
self.with_options = with_options; | ||
self | ||
} | ||
pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self { | ||
self.file_format = file_format; | ||
self | ||
} | ||
pub fn location(mut self, location: Option<String>) -> Self { | ||
self.location = location; | ||
self | ||
} | ||
|
||
pub fn query(mut self, query: Option<Box<Query>>) -> Self { | ||
self.query = query; | ||
self | ||
} | ||
pub fn without_rowid(mut self, without_rowid: bool) -> Self { | ||
self.without_rowid = without_rowid; | ||
self | ||
} | ||
|
||
pub fn like(mut self, like: Option<ObjectName>) -> Self { | ||
self.like = like; | ||
self | ||
} | ||
|
||
// Different name to allow the object to be cloned | ||
pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self { | ||
self.clone = clone; | ||
self | ||
} | ||
|
||
pub fn engine(mut self, engine: Option<String>) -> Self { | ||
self.engine = engine; | ||
self | ||
} | ||
|
||
pub fn default_charset(mut self, default_charset: Option<String>) -> Self { | ||
self.default_charset = default_charset; | ||
self | ||
} | ||
|
||
pub fn collation(mut self, collation: Option<String>) -> Self { | ||
self.collation = collation; | ||
self | ||
} | ||
|
||
pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self { | ||
self.on_commit = on_commit; | ||
self | ||
} | ||
|
||
pub fn on_cluster(mut self, on_cluster: Option<String>) -> Self { | ||
self.on_cluster = on_cluster; | ||
self | ||
} | ||
|
||
pub fn build(self) -> Statement { | ||
Statement::CreateTable { | ||
or_replace: self.or_replace, | ||
temporary: self.temporary, | ||
external: self.external, | ||
global: self.global, | ||
if_not_exists: self.if_not_exists, | ||
name: self.name, | ||
columns: self.columns, | ||
constraints: self.constraints, | ||
hive_distribution: self.hive_distribution, | ||
hive_formats: self.hive_formats, | ||
table_properties: self.table_properties, | ||
with_options: self.with_options, | ||
file_format: self.file_format, | ||
location: self.location, | ||
query: self.query, | ||
without_rowid: self.without_rowid, | ||
like: self.like, | ||
clone: self.clone, | ||
engine: self.engine, | ||
default_charset: self.default_charset, | ||
collation: self.collation, | ||
on_commit: self.on_commit, | ||
on_cluster: self.on_cluster, | ||
} | ||
} | ||
} | ||
|
||
impl TryFrom<Statement> for CreateTableBuilder { | ||
type Error = ParserError; | ||
|
||
// As the builder can be transformed back to a statement, it shouldn't be a problem to take the | ||
// ownership. | ||
fn try_from(stmt: Statement) -> Result<Self, Self::Error> { | ||
match stmt { | ||
Statement::CreateTable { | ||
or_replace, | ||
temporary, | ||
external, | ||
global, | ||
if_not_exists, | ||
name, | ||
columns, | ||
constraints, | ||
hive_distribution, | ||
hive_formats, | ||
table_properties, | ||
with_options, | ||
file_format, | ||
location, | ||
query, | ||
without_rowid, | ||
like, | ||
clone, | ||
engine, | ||
default_charset, | ||
collation, | ||
on_commit, | ||
on_cluster, | ||
} => Ok(Self { | ||
or_replace, | ||
temporary, | ||
external, | ||
global, | ||
if_not_exists, | ||
name, | ||
columns, | ||
constraints, | ||
hive_distribution, | ||
hive_formats, | ||
table_properties, | ||
with_options, | ||
file_format, | ||
location, | ||
query, | ||
without_rowid, | ||
like, | ||
clone, | ||
engine, | ||
default_charset, | ||
collation, | ||
on_commit, | ||
on_cluster, | ||
}), | ||
_ => Err(ParserError::ParserError(format!( | ||
"Expected create table statement, but received: {stmt}" | ||
))), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::ast::helpers::stmt_create_table::CreateTableBuilder; | ||
use crate::ast::{Ident, ObjectName, Statement}; | ||
use crate::parser::ParserError; | ||
|
||
#[test] | ||
pub fn test_from_valid_statement() { | ||
let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")])); | ||
|
||
let stmt = builder.clone().build(); | ||
|
||
assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap()); | ||
} | ||
|
||
#[test] | ||
pub fn test_from_invalid_statement() { | ||
let stmt = Statement::Commit { chain: false }; | ||
|
||
assert_eq!( | ||
CreateTableBuilder::try_from(stmt).unwrap_err(), | ||
ParserError::ParserError( | ||
"Expected create table statement, but received: COMMIT".to_owned() | ||
) | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍