Skip to content

Commit a3194dd

Browse files
authored
Create table builder structure (#659)
* Create table builder structure * Adding comments and examples and adjusting file structure
1 parent 6392a21 commit a3194dd

File tree

6 files changed

+360
-53
lines changed

6 files changed

+360
-53
lines changed

src/ast/helpers/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod stmt_create_table;

src/ast/helpers/stmt_create_table.rs

+323
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
#[cfg(not(feature = "std"))]
2+
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
3+
4+
#[cfg(feature = "serde")]
5+
use serde::{Deserialize, Serialize};
6+
7+
use crate::ast::{
8+
ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, ObjectName, OnCommit, Query,
9+
SqlOption, Statement, TableConstraint,
10+
};
11+
use crate::parser::ParserError;
12+
13+
/// Builder for create table statement variant ([1]).
14+
///
15+
/// This structure helps building and accessing a create table with more ease, without needing to:
16+
/// - Match the enum itself a lot of times; or
17+
/// - Moving a lot of variables around the code.
18+
///
19+
/// # Example
20+
/// ```rust
21+
/// use sqlparser::ast::helpers::stmt_create_table::CreateTableBuilder;
22+
/// use sqlparser::ast::{ColumnDef, DataType, Ident, ObjectName};
23+
/// let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")]))
24+
/// .if_not_exists(true)
25+
/// .columns(vec![ColumnDef {
26+
/// name: Ident::new("c1"),
27+
/// data_type: DataType::Int(None),
28+
/// collation: None,
29+
/// options: vec![],
30+
/// }]);
31+
/// // You can access internal elements with ease
32+
/// assert!(builder.if_not_exists);
33+
/// // Convert to a statement
34+
/// assert_eq!(
35+
/// builder.build().to_string(),
36+
/// "CREATE TABLE IF NOT EXISTS table_name (c1 INT)"
37+
/// )
38+
/// ```
39+
///
40+
/// [1]: crate::ast::Statement::CreateTable
41+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43+
pub struct CreateTableBuilder {
44+
pub or_replace: bool,
45+
pub temporary: bool,
46+
pub external: bool,
47+
pub global: Option<bool>,
48+
pub if_not_exists: bool,
49+
pub name: ObjectName,
50+
pub columns: Vec<ColumnDef>,
51+
pub constraints: Vec<TableConstraint>,
52+
pub hive_distribution: HiveDistributionStyle,
53+
pub hive_formats: Option<HiveFormat>,
54+
pub table_properties: Vec<SqlOption>,
55+
pub with_options: Vec<SqlOption>,
56+
pub file_format: Option<FileFormat>,
57+
pub location: Option<String>,
58+
pub query: Option<Box<Query>>,
59+
pub without_rowid: bool,
60+
pub like: Option<ObjectName>,
61+
pub clone: Option<ObjectName>,
62+
pub engine: Option<String>,
63+
pub default_charset: Option<String>,
64+
pub collation: Option<String>,
65+
pub on_commit: Option<OnCommit>,
66+
pub on_cluster: Option<String>,
67+
}
68+
69+
impl CreateTableBuilder {
70+
pub fn new(name: ObjectName) -> Self {
71+
Self {
72+
or_replace: false,
73+
temporary: false,
74+
external: false,
75+
global: None,
76+
if_not_exists: false,
77+
name,
78+
columns: vec![],
79+
constraints: vec![],
80+
hive_distribution: HiveDistributionStyle::NONE,
81+
hive_formats: None,
82+
table_properties: vec![],
83+
with_options: vec![],
84+
file_format: None,
85+
location: None,
86+
query: None,
87+
without_rowid: false,
88+
like: None,
89+
clone: None,
90+
engine: None,
91+
default_charset: None,
92+
collation: None,
93+
on_commit: None,
94+
on_cluster: None,
95+
}
96+
}
97+
pub fn or_replace(mut self, or_replace: bool) -> Self {
98+
self.or_replace = or_replace;
99+
self
100+
}
101+
102+
pub fn temporary(mut self, temporary: bool) -> Self {
103+
self.temporary = temporary;
104+
self
105+
}
106+
107+
pub fn external(mut self, external: bool) -> Self {
108+
self.external = external;
109+
self
110+
}
111+
112+
pub fn global(mut self, global: Option<bool>) -> Self {
113+
self.global = global;
114+
self
115+
}
116+
117+
pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
118+
self.if_not_exists = if_not_exists;
119+
self
120+
}
121+
122+
pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
123+
self.columns = columns;
124+
self
125+
}
126+
127+
pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
128+
self.constraints = constraints;
129+
self
130+
}
131+
132+
pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
133+
self.hive_distribution = hive_distribution;
134+
self
135+
}
136+
137+
pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
138+
self.hive_formats = hive_formats;
139+
self
140+
}
141+
142+
pub fn table_properties(mut self, table_properties: Vec<SqlOption>) -> Self {
143+
self.table_properties = table_properties;
144+
self
145+
}
146+
147+
pub fn with_options(mut self, with_options: Vec<SqlOption>) -> Self {
148+
self.with_options = with_options;
149+
self
150+
}
151+
pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
152+
self.file_format = file_format;
153+
self
154+
}
155+
pub fn location(mut self, location: Option<String>) -> Self {
156+
self.location = location;
157+
self
158+
}
159+
160+
pub fn query(mut self, query: Option<Box<Query>>) -> Self {
161+
self.query = query;
162+
self
163+
}
164+
pub fn without_rowid(mut self, without_rowid: bool) -> Self {
165+
self.without_rowid = without_rowid;
166+
self
167+
}
168+
169+
pub fn like(mut self, like: Option<ObjectName>) -> Self {
170+
self.like = like;
171+
self
172+
}
173+
174+
// Different name to allow the object to be cloned
175+
pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
176+
self.clone = clone;
177+
self
178+
}
179+
180+
pub fn engine(mut self, engine: Option<String>) -> Self {
181+
self.engine = engine;
182+
self
183+
}
184+
185+
pub fn default_charset(mut self, default_charset: Option<String>) -> Self {
186+
self.default_charset = default_charset;
187+
self
188+
}
189+
190+
pub fn collation(mut self, collation: Option<String>) -> Self {
191+
self.collation = collation;
192+
self
193+
}
194+
195+
pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
196+
self.on_commit = on_commit;
197+
self
198+
}
199+
200+
pub fn on_cluster(mut self, on_cluster: Option<String>) -> Self {
201+
self.on_cluster = on_cluster;
202+
self
203+
}
204+
205+
pub fn build(self) -> Statement {
206+
Statement::CreateTable {
207+
or_replace: self.or_replace,
208+
temporary: self.temporary,
209+
external: self.external,
210+
global: self.global,
211+
if_not_exists: self.if_not_exists,
212+
name: self.name,
213+
columns: self.columns,
214+
constraints: self.constraints,
215+
hive_distribution: self.hive_distribution,
216+
hive_formats: self.hive_formats,
217+
table_properties: self.table_properties,
218+
with_options: self.with_options,
219+
file_format: self.file_format,
220+
location: self.location,
221+
query: self.query,
222+
without_rowid: self.without_rowid,
223+
like: self.like,
224+
clone: self.clone,
225+
engine: self.engine,
226+
default_charset: self.default_charset,
227+
collation: self.collation,
228+
on_commit: self.on_commit,
229+
on_cluster: self.on_cluster,
230+
}
231+
}
232+
}
233+
234+
impl TryFrom<Statement> for CreateTableBuilder {
235+
type Error = ParserError;
236+
237+
// As the builder can be transformed back to a statement, it shouldn't be a problem to take the
238+
// ownership.
239+
fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
240+
match stmt {
241+
Statement::CreateTable {
242+
or_replace,
243+
temporary,
244+
external,
245+
global,
246+
if_not_exists,
247+
name,
248+
columns,
249+
constraints,
250+
hive_distribution,
251+
hive_formats,
252+
table_properties,
253+
with_options,
254+
file_format,
255+
location,
256+
query,
257+
without_rowid,
258+
like,
259+
clone,
260+
engine,
261+
default_charset,
262+
collation,
263+
on_commit,
264+
on_cluster,
265+
} => Ok(Self {
266+
or_replace,
267+
temporary,
268+
external,
269+
global,
270+
if_not_exists,
271+
name,
272+
columns,
273+
constraints,
274+
hive_distribution,
275+
hive_formats,
276+
table_properties,
277+
with_options,
278+
file_format,
279+
location,
280+
query,
281+
without_rowid,
282+
like,
283+
clone,
284+
engine,
285+
default_charset,
286+
collation,
287+
on_commit,
288+
on_cluster,
289+
}),
290+
_ => Err(ParserError::ParserError(format!(
291+
"Expected create table statement, but received: {stmt}"
292+
))),
293+
}
294+
}
295+
}
296+
297+
#[cfg(test)]
298+
mod tests {
299+
use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
300+
use crate::ast::{Ident, ObjectName, Statement};
301+
use crate::parser::ParserError;
302+
303+
#[test]
304+
pub fn test_from_valid_statement() {
305+
let builder = CreateTableBuilder::new(ObjectName(vec![Ident::new("table_name")]));
306+
307+
let stmt = builder.clone().build();
308+
309+
assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
310+
}
311+
312+
#[test]
313+
pub fn test_from_invalid_statement() {
314+
let stmt = Statement::Commit { chain: false };
315+
316+
assert_eq!(
317+
CreateTableBuilder::try_from(stmt).unwrap_err(),
318+
ParserError::ParserError(
319+
"Expected create table statement, but received: COMMIT".to_owned()
320+
)
321+
);
322+
}
323+
}

src/ast/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! SQL Abstract Syntax Tree (AST) types
1414
mod data_type;
1515
mod ddl;
16+
pub mod helpers;
1617
mod operator;
1718
mod query;
1819
mod value;

src/ast/value.rs

-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13-
#[cfg(not(feature = "std"))]
14-
use alloc::boxed::Box;
1513
#[cfg(not(feature = "std"))]
1614
use alloc::string::String;
1715
use core::fmt;

0 commit comments

Comments
 (0)