sqlparser/ast/helpers/
stmt_create_table.rs

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