1#[cfg(not(feature = "std"))]
19use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
20
21#[cfg(feature = "serde")]
22use serde::{Deserialize, Serialize};
23
24#[cfg(feature = "visitor")]
25use yachtsql_sqlparser_derive::{Visit, VisitMut};
26
27use crate::ast::{
28 ClusteredBy, ColumnDef, CommentDef, CreateTable, CreateTableLikeKind, CreateTableOptions, Expr,
29 FileFormat, HiveDistributionStyle, HiveFormat, Ident, InitializeKind, ObjectName, OnCommit,
30 OneOrManyWithParens, Query, RefreshModeKind, RowAccessPolicy, Statement,
31 StorageSerializationPolicy, TableConstraint, TableVersion, Tag, WrappedCollection,
32};
33
34use crate::parser::ParserError;
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
66pub struct CreateTableBuilder {
67 pub or_replace: bool,
68 pub temporary: bool,
69 pub external: bool,
70 pub global: Option<bool>,
71 pub if_not_exists: bool,
72 pub transient: bool,
73 pub volatile: bool,
74 pub iceberg: bool,
75 pub dynamic: bool,
76 pub name: ObjectName,
77 pub columns: Vec<ColumnDef>,
78 pub constraints: Vec<TableConstraint>,
79 pub hive_distribution: HiveDistributionStyle,
80 pub hive_formats: Option<HiveFormat>,
81 pub file_format: Option<FileFormat>,
82 pub location: Option<String>,
83 pub query: Option<Box<Query>>,
84 pub without_rowid: bool,
85 pub like: Option<CreateTableLikeKind>,
86 pub clone: Option<ObjectName>,
87 pub copy: Option<ObjectName>,
88 pub version: Option<TableVersion>,
89 pub comment: Option<CommentDef>,
90 pub on_commit: Option<OnCommit>,
91 pub on_cluster: Option<Ident>,
92 pub primary_key: Option<Box<Expr>>,
93 pub order_by: Option<OneOrManyWithParens<Expr>>,
94 pub partition_by: Option<Box<Expr>>,
95 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
96 pub clustered_by: Option<ClusteredBy>,
97 pub inherits: Option<Vec<ObjectName>>,
98 pub strict: bool,
99 pub copy_grants: bool,
100 pub enable_schema_evolution: Option<bool>,
101 pub change_tracking: Option<bool>,
102 pub data_retention_time_in_days: Option<u64>,
103 pub max_data_extension_time_in_days: Option<u64>,
104 pub default_ddl_collation: Option<String>,
105 pub with_aggregation_policy: Option<ObjectName>,
106 pub with_row_access_policy: Option<RowAccessPolicy>,
107 pub with_tags: Option<Vec<Tag>>,
108 pub base_location: Option<String>,
109 pub external_volume: Option<String>,
110 pub catalog: Option<String>,
111 pub catalog_sync: Option<String>,
112 pub storage_serialization_policy: Option<StorageSerializationPolicy>,
113 pub table_options: CreateTableOptions,
114 pub target_lag: Option<String>,
115 pub warehouse: Option<Ident>,
116 pub refresh_mode: Option<RefreshModeKind>,
117 pub initialize: Option<InitializeKind>,
118 pub require_user: bool,
119}
120
121impl CreateTableBuilder {
122 pub fn new(name: ObjectName) -> Self {
123 Self {
124 or_replace: false,
125 temporary: false,
126 external: false,
127 global: None,
128 if_not_exists: false,
129 transient: false,
130 volatile: false,
131 iceberg: false,
132 dynamic: false,
133 name,
134 columns: vec![],
135 constraints: vec![],
136 hive_distribution: HiveDistributionStyle::NONE,
137 hive_formats: None,
138 file_format: None,
139 location: None,
140 query: None,
141 without_rowid: false,
142 like: None,
143 clone: None,
144 copy: None,
145 version: None,
146 comment: None,
147 on_commit: None,
148 on_cluster: None,
149 primary_key: None,
150 order_by: None,
151 partition_by: None,
152 cluster_by: None,
153 clustered_by: None,
154 inherits: None,
155 strict: false,
156 copy_grants: false,
157 enable_schema_evolution: None,
158 change_tracking: None,
159 data_retention_time_in_days: None,
160 max_data_extension_time_in_days: None,
161 default_ddl_collation: None,
162 with_aggregation_policy: None,
163 with_row_access_policy: None,
164 with_tags: None,
165 base_location: None,
166 external_volume: None,
167 catalog: None,
168 catalog_sync: None,
169 storage_serialization_policy: None,
170 table_options: CreateTableOptions::None,
171 target_lag: None,
172 warehouse: None,
173 refresh_mode: None,
174 initialize: None,
175 require_user: false,
176 }
177 }
178 pub fn or_replace(mut self, or_replace: bool) -> Self {
179 self.or_replace = or_replace;
180 self
181 }
182
183 pub fn temporary(mut self, temporary: bool) -> Self {
184 self.temporary = temporary;
185 self
186 }
187
188 pub fn external(mut self, external: bool) -> Self {
189 self.external = external;
190 self
191 }
192
193 pub fn global(mut self, global: Option<bool>) -> Self {
194 self.global = global;
195 self
196 }
197
198 pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
199 self.if_not_exists = if_not_exists;
200 self
201 }
202
203 pub fn transient(mut self, transient: bool) -> Self {
204 self.transient = transient;
205 self
206 }
207
208 pub fn volatile(mut self, volatile: bool) -> Self {
209 self.volatile = volatile;
210 self
211 }
212
213 pub fn iceberg(mut self, iceberg: bool) -> Self {
214 self.iceberg = iceberg;
215 self
216 }
217
218 pub fn dynamic(mut self, dynamic: bool) -> Self {
219 self.dynamic = dynamic;
220 self
221 }
222
223 pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
224 self.columns = columns;
225 self
226 }
227
228 pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
229 self.constraints = constraints;
230 self
231 }
232
233 pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
234 self.hive_distribution = hive_distribution;
235 self
236 }
237
238 pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
239 self.hive_formats = hive_formats;
240 self
241 }
242
243 pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
244 self.file_format = file_format;
245 self
246 }
247 pub fn location(mut self, location: Option<String>) -> Self {
248 self.location = location;
249 self
250 }
251
252 pub fn query(mut self, query: Option<Box<Query>>) -> Self {
253 self.query = query;
254 self
255 }
256 pub fn without_rowid(mut self, without_rowid: bool) -> Self {
257 self.without_rowid = without_rowid;
258 self
259 }
260
261 pub fn like(mut self, like: Option<CreateTableLikeKind>) -> Self {
262 self.like = like;
263 self
264 }
265
266 pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
268 self.clone = clone;
269 self
270 }
271
272 pub fn copy_clause(mut self, copy: Option<ObjectName>) -> Self {
273 self.copy = copy;
274 self
275 }
276
277 pub fn version(mut self, version: Option<TableVersion>) -> Self {
278 self.version = version;
279 self
280 }
281
282 pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
283 self.comment = comment;
284 self
285 }
286
287 pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
288 self.on_commit = on_commit;
289 self
290 }
291
292 pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
293 self.on_cluster = on_cluster;
294 self
295 }
296
297 pub fn primary_key(mut self, primary_key: Option<Box<Expr>>) -> Self {
298 self.primary_key = primary_key;
299 self
300 }
301
302 pub fn order_by(mut self, order_by: Option<OneOrManyWithParens<Expr>>) -> Self {
303 self.order_by = order_by;
304 self
305 }
306
307 pub fn partition_by(mut self, partition_by: Option<Box<Expr>>) -> Self {
308 self.partition_by = partition_by;
309 self
310 }
311
312 pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
313 self.cluster_by = cluster_by;
314 self
315 }
316
317 pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
318 self.clustered_by = clustered_by;
319 self
320 }
321
322 pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
323 self.inherits = inherits;
324 self
325 }
326
327 pub fn strict(mut self, strict: bool) -> Self {
328 self.strict = strict;
329 self
330 }
331
332 pub fn copy_grants(mut self, copy_grants: bool) -> Self {
333 self.copy_grants = copy_grants;
334 self
335 }
336
337 pub fn enable_schema_evolution(mut self, enable_schema_evolution: Option<bool>) -> Self {
338 self.enable_schema_evolution = enable_schema_evolution;
339 self
340 }
341
342 pub fn change_tracking(mut self, change_tracking: Option<bool>) -> Self {
343 self.change_tracking = change_tracking;
344 self
345 }
346
347 pub fn data_retention_time_in_days(mut self, data_retention_time_in_days: Option<u64>) -> Self {
348 self.data_retention_time_in_days = data_retention_time_in_days;
349 self
350 }
351
352 pub fn max_data_extension_time_in_days(
353 mut self,
354 max_data_extension_time_in_days: Option<u64>,
355 ) -> Self {
356 self.max_data_extension_time_in_days = max_data_extension_time_in_days;
357 self
358 }
359
360 pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
361 self.default_ddl_collation = default_ddl_collation;
362 self
363 }
364
365 pub fn with_aggregation_policy(mut self, with_aggregation_policy: Option<ObjectName>) -> Self {
366 self.with_aggregation_policy = with_aggregation_policy;
367 self
368 }
369
370 pub fn with_row_access_policy(
371 mut self,
372 with_row_access_policy: Option<RowAccessPolicy>,
373 ) -> Self {
374 self.with_row_access_policy = with_row_access_policy;
375 self
376 }
377
378 pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
379 self.with_tags = with_tags;
380 self
381 }
382
383 pub fn base_location(mut self, base_location: Option<String>) -> Self {
384 self.base_location = base_location;
385 self
386 }
387
388 pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
389 self.external_volume = external_volume;
390 self
391 }
392
393 pub fn catalog(mut self, catalog: Option<String>) -> Self {
394 self.catalog = catalog;
395 self
396 }
397
398 pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
399 self.catalog_sync = catalog_sync;
400 self
401 }
402
403 pub fn storage_serialization_policy(
404 mut self,
405 storage_serialization_policy: Option<StorageSerializationPolicy>,
406 ) -> Self {
407 self.storage_serialization_policy = storage_serialization_policy;
408 self
409 }
410
411 pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
412 self.table_options = table_options;
413 self
414 }
415
416 pub fn target_lag(mut self, target_lag: Option<String>) -> Self {
417 self.target_lag = target_lag;
418 self
419 }
420
421 pub fn warehouse(mut self, warehouse: Option<Ident>) -> Self {
422 self.warehouse = warehouse;
423 self
424 }
425
426 pub fn refresh_mode(mut self, refresh_mode: Option<RefreshModeKind>) -> Self {
427 self.refresh_mode = refresh_mode;
428 self
429 }
430
431 pub fn initialize(mut self, initialize: Option<InitializeKind>) -> Self {
432 self.initialize = initialize;
433 self
434 }
435
436 pub fn require_user(mut self, require_user: bool) -> Self {
437 self.require_user = require_user;
438 self
439 }
440
441 pub fn build(self) -> Statement {
442 CreateTable {
443 or_replace: self.or_replace,
444 temporary: self.temporary,
445 external: self.external,
446 global: self.global,
447 if_not_exists: self.if_not_exists,
448 transient: self.transient,
449 volatile: self.volatile,
450 iceberg: self.iceberg,
451 dynamic: self.dynamic,
452 name: self.name,
453 columns: self.columns,
454 constraints: self.constraints,
455 hive_distribution: self.hive_distribution,
456 hive_formats: self.hive_formats,
457 file_format: self.file_format,
458 location: self.location,
459 query: self.query,
460 without_rowid: self.without_rowid,
461 like: self.like,
462 clone: self.clone,
463 copy: self.copy,
464 version: self.version,
465 comment: self.comment,
466 on_commit: self.on_commit,
467 on_cluster: self.on_cluster,
468 primary_key: self.primary_key,
469 order_by: self.order_by,
470 partition_by: self.partition_by,
471 cluster_by: self.cluster_by,
472 clustered_by: self.clustered_by,
473 inherits: self.inherits,
474 strict: self.strict,
475 copy_grants: self.copy_grants,
476 enable_schema_evolution: self.enable_schema_evolution,
477 change_tracking: self.change_tracking,
478 data_retention_time_in_days: self.data_retention_time_in_days,
479 max_data_extension_time_in_days: self.max_data_extension_time_in_days,
480 default_ddl_collation: self.default_ddl_collation,
481 with_aggregation_policy: self.with_aggregation_policy,
482 with_row_access_policy: self.with_row_access_policy,
483 with_tags: self.with_tags,
484 base_location: self.base_location,
485 external_volume: self.external_volume,
486 catalog: self.catalog,
487 catalog_sync: self.catalog_sync,
488 storage_serialization_policy: self.storage_serialization_policy,
489 table_options: self.table_options,
490 target_lag: self.target_lag,
491 warehouse: self.warehouse,
492 refresh_mode: self.refresh_mode,
493 initialize: self.initialize,
494 require_user: self.require_user,
495 }
496 .into()
497 }
498}
499
500impl TryFrom<Statement> for CreateTableBuilder {
501 type Error = ParserError;
502
503 fn try_from(stmt: Statement) -> Result<Self, Self::Error> {
506 match stmt {
507 Statement::CreateTable(CreateTable {
508 or_replace,
509 temporary,
510 external,
511 global,
512 if_not_exists,
513 transient,
514 volatile,
515 iceberg,
516 dynamic,
517 name,
518 columns,
519 constraints,
520 hive_distribution,
521 hive_formats,
522 file_format,
523 location,
524 query,
525 without_rowid,
526 like,
527 clone,
528 copy,
529 version,
530 comment,
531 on_commit,
532 on_cluster,
533 primary_key,
534 order_by,
535 partition_by,
536 cluster_by,
537 clustered_by,
538 inherits,
539 strict,
540 copy_grants,
541 enable_schema_evolution,
542 change_tracking,
543 data_retention_time_in_days,
544 max_data_extension_time_in_days,
545 default_ddl_collation,
546 with_aggregation_policy,
547 with_row_access_policy,
548 with_tags,
549 base_location,
550 external_volume,
551 catalog,
552 catalog_sync,
553 storage_serialization_policy,
554 table_options,
555 target_lag,
556 warehouse,
557 refresh_mode,
558 initialize,
559 require_user,
560 }) => Ok(Self {
561 or_replace,
562 temporary,
563 external,
564 global,
565 if_not_exists,
566 transient,
567 dynamic,
568 name,
569 columns,
570 constraints,
571 hive_distribution,
572 hive_formats,
573 file_format,
574 location,
575 query,
576 without_rowid,
577 like,
578 clone,
579 copy,
580 version,
581 comment,
582 on_commit,
583 on_cluster,
584 primary_key,
585 order_by,
586 partition_by,
587 cluster_by,
588 clustered_by,
589 inherits,
590 strict,
591 iceberg,
592 copy_grants,
593 enable_schema_evolution,
594 change_tracking,
595 data_retention_time_in_days,
596 max_data_extension_time_in_days,
597 default_ddl_collation,
598 with_aggregation_policy,
599 with_row_access_policy,
600 with_tags,
601 volatile,
602 base_location,
603 external_volume,
604 catalog,
605 catalog_sync,
606 storage_serialization_policy,
607 table_options,
608 target_lag,
609 warehouse,
610 refresh_mode,
611 initialize,
612 require_user,
613 }),
614 _ => Err(ParserError::ParserError(format!(
615 "Expected create table statement, but received: {stmt}"
616 ))),
617 }
618 }
619}
620
621#[derive(Default)]
623pub(crate) struct CreateTableConfiguration {
624 pub partition_by: Option<Box<Expr>>,
625 pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
626 pub inherits: Option<Vec<ObjectName>>,
627 pub table_options: CreateTableOptions,
628}
629
630#[cfg(test)]
631mod tests {
632 use crate::ast::helpers::stmt_create_table::CreateTableBuilder;
633 use crate::ast::{Ident, ObjectName, Statement};
634 use crate::parser::ParserError;
635
636 #[test]
637 pub fn test_from_valid_statement() {
638 let builder = CreateTableBuilder::new(ObjectName::from(vec![Ident::new("table_name")]));
639
640 let stmt = builder.clone().build();
641
642 assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
643 }
644
645 #[test]
646 pub fn test_from_invalid_statement() {
647 let stmt = Statement::Commit {
648 chain: false,
649 end: false,
650 modifier: None,
651 };
652
653 assert_eq!(
654 CreateTableBuilder::try_from(stmt).unwrap_err(),
655 ParserError::ParserError(
656 "Expected create table statement, but received: COMMIT".to_owned()
657 )
658 );
659 }
660}