// 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::{boxed::Box, format, string::String, vec, vec::Vec};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};

use crate::ast::{
    ClusteredBy, ColumnDef, CommentDef, CreateTable, CreateTableLikeKind, CreateTableOptions,
    DistStyle, Expr, FileFormat, ForValues, HiveDistributionStyle, HiveFormat, Ident,
    InitializeKind, ObjectName, OnCommit, OneOrManyWithParens, Query, RefreshModeKind,
    RowAccessPolicy, Statement, StorageLifecyclePolicy, StorageSerializationPolicy,
    TableConstraint, TableVersion, Tag, WrappedCollection,
};

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::from(vec![Ident::new("table_name")]))
///    .if_not_exists(true)
///    .columns(vec![ColumnDef {
///        name: Ident::new("c1"),
///        data_type: DataType::Int(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))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateTableBuilder {
    /// Whether the statement uses `OR REPLACE`.
    pub or_replace: bool,
    /// Whether the table is `TEMPORARY`.
    pub temporary: bool,
    /// Whether the table is `EXTERNAL`.
    pub external: bool,
    /// Optional `GLOBAL` flag for dialects that support it.
    pub global: Option<bool>,
    /// Whether `IF NOT EXISTS` was specified.
    pub if_not_exists: bool,
    /// Whether `TRANSIENT` was specified.
    pub transient: bool,
    /// Whether `VOLATILE` was specified.
    pub volatile: bool,
    /// Iceberg-specific table flag.
    pub iceberg: bool,
    /// `SNAPSHOT` table flag.
    pub snapshot: bool,
    /// Whether `DYNAMIC` table option is set.
    pub dynamic: bool,
    /// The table name.
    pub name: ObjectName,
    /// Column definitions for the table.
    pub columns: Vec<ColumnDef>,
    /// Table-level constraints.
    pub constraints: Vec<TableConstraint>,
    /// Hive distribution style.
    pub hive_distribution: HiveDistributionStyle,
    /// Optional Hive format settings.
    pub hive_formats: Option<HiveFormat>,
    /// Optional file format for storage.
    pub file_format: Option<FileFormat>,
    /// Optional storage location.
    pub location: Option<String>,
    /// Optional `AS SELECT` query for the table.
    pub query: Option<Box<Query>>,
    /// Whether `WITHOUT ROWID` is set.
    pub without_rowid: bool,
    /// Optional `LIKE` clause kind.
    pub like: Option<CreateTableLikeKind>,
    /// Optional `CLONE` source object name.
    pub clone: Option<ObjectName>,
    /// Optional table version.
    pub version: Option<TableVersion>,
    /// Optional table comment.
    pub comment: Option<CommentDef>,
    /// Optional `ON COMMIT` behavior.
    pub on_commit: Option<OnCommit>,
    /// Optional cluster identifier.
    pub on_cluster: Option<Ident>,
    /// Optional primary key expression.
    pub primary_key: Option<Box<Expr>>,
    /// Optional `ORDER BY` for clustering/sorting.
    pub order_by: Option<OneOrManyWithParens<Expr>>,
    /// Optional `PARTITION BY` expression.
    pub partition_by: Option<Box<Expr>>,
    /// Optional `CLUSTER BY` expressions.
    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
    /// Optional `CLUSTERED BY` clause.
    pub clustered_by: Option<ClusteredBy>,
    /// Optional parent tables (`INHERITS`).
    pub inherits: Option<Vec<ObjectName>>,
    /// Optional partitioned table (`PARTITION OF`)
    pub partition_of: Option<ObjectName>,
    /// Range of values associated with the partition (`FOR VALUES`)
    pub for_values: Option<ForValues>,
    /// `STRICT` table flag.
    pub strict: bool,
    /// Whether to copy grants from the source.
    pub copy_grants: bool,
    /// Optional flag for schema evolution support.
    pub enable_schema_evolution: Option<bool>,
    /// Optional change tracking flag.
    pub change_tracking: Option<bool>,
    /// Optional data retention time in days.
    pub data_retention_time_in_days: Option<u64>,
    /// Optional max data extension time in days.
    pub max_data_extension_time_in_days: Option<u64>,
    /// Optional default DDL collation.
    pub default_ddl_collation: Option<String>,
    /// Optional aggregation policy object name.
    pub with_aggregation_policy: Option<ObjectName>,
    /// Optional row access policy applied to the table.
    pub with_row_access_policy: Option<RowAccessPolicy>,
    /// Optional storage lifecycle policy applied to the table.
    pub with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
    /// Optional tags/labels attached to the table metadata.
    pub with_tags: Option<Vec<Tag>>,
    /// Optional base location for staged data.
    pub base_location: Option<String>,
    /// Optional external volume identifier.
    pub external_volume: Option<String>,
    /// Optional catalog name.
    pub catalog: Option<String>,
    /// Optional catalog synchronization option.
    pub catalog_sync: Option<String>,
    /// Optional storage serialization policy.
    pub storage_serialization_policy: Option<StorageSerializationPolicy>,
    /// Parsed table options from the statement.
    pub table_options: CreateTableOptions,
    /// Optional target lag configuration.
    pub target_lag: Option<String>,
    /// Optional warehouse identifier.
    pub warehouse: Option<Ident>,
    /// Optional refresh mode for materialized tables.
    pub refresh_mode: Option<RefreshModeKind>,
    /// Optional initialization kind for the table.
    pub initialize: Option<InitializeKind>,
    /// Whether operations require a user identity.
    pub require_user: bool,
    /// Redshift `DISTSTYLE` option.
    pub diststyle: Option<DistStyle>,
    /// Redshift `DISTKEY` option.
    pub distkey: Option<Expr>,
    /// Redshift `SORTKEY` option.
    pub sortkey: Option<Vec<Expr>>,
    /// Redshift `BACKUP` option.
    pub backup: Option<bool>,
}

impl CreateTableBuilder {
    /// Create a new `CreateTableBuilder` for the given table name.
    pub fn new(name: ObjectName) -> Self {
        Self {
            or_replace: false,
            temporary: false,
            external: false,
            global: None,
            if_not_exists: false,
            transient: false,
            volatile: false,
            iceberg: false,
            snapshot: false,
            dynamic: false,
            name,
            columns: vec![],
            constraints: vec![],
            hive_distribution: HiveDistributionStyle::NONE,
            hive_formats: None,
            file_format: None,
            location: None,
            query: None,
            without_rowid: false,
            like: None,
            clone: None,
            version: None,
            comment: None,
            on_commit: None,
            on_cluster: None,
            primary_key: None,
            order_by: None,
            partition_by: None,
            cluster_by: None,
            clustered_by: None,
            inherits: None,
            partition_of: None,
            for_values: None,
            strict: false,
            copy_grants: false,
            enable_schema_evolution: None,
            change_tracking: None,
            data_retention_time_in_days: None,
            max_data_extension_time_in_days: None,
            default_ddl_collation: None,
            with_aggregation_policy: None,
            with_row_access_policy: None,
            with_storage_lifecycle_policy: None,
            with_tags: None,
            base_location: None,
            external_volume: None,
            catalog: None,
            catalog_sync: None,
            storage_serialization_policy: None,
            table_options: CreateTableOptions::None,
            target_lag: None,
            warehouse: None,
            refresh_mode: None,
            initialize: None,
            require_user: false,
            diststyle: None,
            distkey: None,
            sortkey: None,
            backup: None,
        }
    }
    /// Set `OR REPLACE` for the CREATE TABLE statement.
    pub fn or_replace(mut self, or_replace: bool) -> Self {
        self.or_replace = or_replace;
        self
    }
    /// Mark the table as `TEMPORARY`.
    pub fn temporary(mut self, temporary: bool) -> Self {
        self.temporary = temporary;
        self
    }
    /// Mark the table as `EXTERNAL`.
    pub fn external(mut self, external: bool) -> Self {
        self.external = external;
        self
    }
    /// Set optional `GLOBAL` flag (dialect-specific).
    pub fn global(mut self, global: Option<bool>) -> Self {
        self.global = global;
        self
    }
    /// Set `IF NOT EXISTS`.
    pub fn if_not_exists(mut self, if_not_exists: bool) -> Self {
        self.if_not_exists = if_not_exists;
        self
    }
    /// Set `TRANSIENT` flag.
    pub fn transient(mut self, transient: bool) -> Self {
        self.transient = transient;
        self
    }
    /// Set `VOLATILE` flag.
    pub fn volatile(mut self, volatile: bool) -> Self {
        self.volatile = volatile;
        self
    }
    /// Enable Iceberg table semantics.
    pub fn iceberg(mut self, iceberg: bool) -> Self {
        self.iceberg = iceberg;
        self
    }
    /// Set `SNAPSHOT` table flag (BigQuery).
    pub fn snapshot(mut self, snapshot: bool) -> Self {
        self.snapshot = snapshot;
        self
    }
    /// Set `DYNAMIC` table option.
    pub fn dynamic(mut self, dynamic: bool) -> Self {
        self.dynamic = dynamic;
        self
    }
    /// Set the table column definitions.
    pub fn columns(mut self, columns: Vec<ColumnDef>) -> Self {
        self.columns = columns;
        self
    }
    /// Set table-level constraints.
    pub fn constraints(mut self, constraints: Vec<TableConstraint>) -> Self {
        self.constraints = constraints;
        self
    }
    /// Set Hive distribution style.
    pub fn hive_distribution(mut self, hive_distribution: HiveDistributionStyle) -> Self {
        self.hive_distribution = hive_distribution;
        self
    }
    /// Set Hive-specific formats.
    pub fn hive_formats(mut self, hive_formats: Option<HiveFormat>) -> Self {
        self.hive_formats = hive_formats;
        self
    }
    /// Set file format for the table (e.g., PARQUET).
    pub fn file_format(mut self, file_format: Option<FileFormat>) -> Self {
        self.file_format = file_format;
        self
    }
    /// Set storage `location` for the table.
    pub fn location(mut self, location: Option<String>) -> Self {
        self.location = location;
        self
    }
    /// Set an underlying `AS SELECT` query for the table.
    pub fn query(mut self, query: Option<Box<Query>>) -> Self {
        self.query = query;
        self
    }
    /// Set `WITHOUT ROWID` option.
    pub fn without_rowid(mut self, without_rowid: bool) -> Self {
        self.without_rowid = without_rowid;
        self
    }
    /// Set `LIKE` clause for the table.
    pub fn like(mut self, like: Option<CreateTableLikeKind>) -> Self {
        self.like = like;
        self
    }
    // Different name to allow the object to be cloned
    /// Set `CLONE` source object name.
    pub fn clone_clause(mut self, clone: Option<ObjectName>) -> Self {
        self.clone = clone;
        self
    }
    /// Set table `VERSION`.
    pub fn version(mut self, version: Option<TableVersion>) -> Self {
        self.version = version;
        self
    }
    /// Set a comment for the table or following column definitions.
    pub fn comment_after_column_def(mut self, comment: Option<CommentDef>) -> Self {
        self.comment = comment;
        self
    }
    /// Set `ON COMMIT` behavior for temporary tables.
    pub fn on_commit(mut self, on_commit: Option<OnCommit>) -> Self {
        self.on_commit = on_commit;
        self
    }
    /// Set cluster identifier for the table.
    pub fn on_cluster(mut self, on_cluster: Option<Ident>) -> Self {
        self.on_cluster = on_cluster;
        self
    }
    /// Set a primary key expression for the table.
    pub fn primary_key(mut self, primary_key: Option<Box<Expr>>) -> Self {
        self.primary_key = primary_key;
        self
    }
    /// Set `ORDER BY` clause for clustered/sorted tables.
    pub fn order_by(mut self, order_by: Option<OneOrManyWithParens<Expr>>) -> Self {
        self.order_by = order_by;
        self
    }
    /// Set `PARTITION BY` expression.
    pub fn partition_by(mut self, partition_by: Option<Box<Expr>>) -> Self {
        self.partition_by = partition_by;
        self
    }
    /// Set `CLUSTER BY` expression(s).
    pub fn cluster_by(mut self, cluster_by: Option<WrappedCollection<Vec<Expr>>>) -> Self {
        self.cluster_by = cluster_by;
        self
    }
    /// Set `CLUSTERED BY` clause.
    pub fn clustered_by(mut self, clustered_by: Option<ClusteredBy>) -> Self {
        self.clustered_by = clustered_by;
        self
    }
    /// Set parent tables via `INHERITS`.
    pub fn inherits(mut self, inherits: Option<Vec<ObjectName>>) -> Self {
        self.inherits = inherits;
        self
    }

    /// Sets the table which is partitioned to create the current table.
    pub fn partition_of(mut self, partition_of: Option<ObjectName>) -> Self {
        self.partition_of = partition_of;
        self
    }

    /// Sets the range of values associated with the partition.
    pub fn for_values(mut self, for_values: Option<ForValues>) -> Self {
        self.for_values = for_values;
        self
    }

    /// Set `STRICT` option.
    pub fn strict(mut self, strict: bool) -> Self {
        self.strict = strict;
        self
    }
    /// Enable copying grants from source object.
    pub fn copy_grants(mut self, copy_grants: bool) -> Self {
        self.copy_grants = copy_grants;
        self
    }
    /// Enable or disable schema evolution features.
    pub fn enable_schema_evolution(mut self, enable_schema_evolution: Option<bool>) -> Self {
        self.enable_schema_evolution = enable_schema_evolution;
        self
    }
    /// Enable or disable change tracking.
    pub fn change_tracking(mut self, change_tracking: Option<bool>) -> Self {
        self.change_tracking = change_tracking;
        self
    }
    /// Set data retention time (in days).
    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
    }
    /// Set maximum data extension time (in days).
    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
    }
    /// Set default DDL collation.
    pub fn default_ddl_collation(mut self, default_ddl_collation: Option<String>) -> Self {
        self.default_ddl_collation = default_ddl_collation;
        self
    }
    /// Set aggregation policy object.
    pub fn with_aggregation_policy(mut self, with_aggregation_policy: Option<ObjectName>) -> Self {
        self.with_aggregation_policy = with_aggregation_policy;
        self
    }
    /// Attach a row access policy to the table.
    pub fn with_row_access_policy(
        mut self,
        with_row_access_policy: Option<RowAccessPolicy>,
    ) -> Self {
        self.with_row_access_policy = with_row_access_policy;
        self
    }
    /// Attach a storage lifecycle policy to the table.
    pub fn with_storage_lifecycle_policy(
        mut self,
        with_storage_lifecycle_policy: Option<StorageLifecyclePolicy>,
    ) -> Self {
        self.with_storage_lifecycle_policy = with_storage_lifecycle_policy;
        self
    }
    /// Attach tags/labels to the table metadata.
    pub fn with_tags(mut self, with_tags: Option<Vec<Tag>>) -> Self {
        self.with_tags = with_tags;
        self
    }
    /// Set a base storage location for staged data.
    pub fn base_location(mut self, base_location: Option<String>) -> Self {
        self.base_location = base_location;
        self
    }
    /// Set an external volume identifier.
    pub fn external_volume(mut self, external_volume: Option<String>) -> Self {
        self.external_volume = external_volume;
        self
    }
    /// Set the catalog name for the table.
    pub fn catalog(mut self, catalog: Option<String>) -> Self {
        self.catalog = catalog;
        self
    }
    /// Set catalog synchronization option.
    pub fn catalog_sync(mut self, catalog_sync: Option<String>) -> Self {
        self.catalog_sync = catalog_sync;
        self
    }
    /// Set a storage serialization policy.
    pub fn storage_serialization_policy(
        mut self,
        storage_serialization_policy: Option<StorageSerializationPolicy>,
    ) -> Self {
        self.storage_serialization_policy = storage_serialization_policy;
        self
    }
    /// Set arbitrary table options parsed from the statement.
    pub fn table_options(mut self, table_options: CreateTableOptions) -> Self {
        self.table_options = table_options;
        self
    }
    /// Set a target lag configuration (dialect-specific).
    pub fn target_lag(mut self, target_lag: Option<String>) -> Self {
        self.target_lag = target_lag;
        self
    }
    /// Associate the table with a warehouse identifier.
    pub fn warehouse(mut self, warehouse: Option<Ident>) -> Self {
        self.warehouse = warehouse;
        self
    }
    /// Set refresh mode for materialized/managed tables.
    pub fn refresh_mode(mut self, refresh_mode: Option<RefreshModeKind>) -> Self {
        self.refresh_mode = refresh_mode;
        self
    }
    /// Set initialization mode for the table.
    pub fn initialize(mut self, initialize: Option<InitializeKind>) -> Self {
        self.initialize = initialize;
        self
    }
    /// Require a user identity for table operations.
    pub fn require_user(mut self, require_user: bool) -> Self {
        self.require_user = require_user;
        self
    }
    /// Set Redshift `DISTSTYLE` option.
    pub fn diststyle(mut self, diststyle: Option<DistStyle>) -> Self {
        self.diststyle = diststyle;
        self
    }
    /// Set Redshift `DISTKEY` option.
    pub fn distkey(mut self, distkey: Option<Expr>) -> Self {
        self.distkey = distkey;
        self
    }
    /// Set Redshift `SORTKEY` option.
    pub fn sortkey(mut self, sortkey: Option<Vec<Expr>>) -> Self {
        self.sortkey = sortkey;
        self
    }
    /// Set the Redshift `BACKUP` option.
    pub fn backup(mut self, backup: Option<bool>) -> Self {
        self.backup = backup;
        self
    }
    /// Consume the builder and produce a `CreateTable`.
    pub fn build(self) -> CreateTable {
        CreateTable {
            or_replace: self.or_replace,
            temporary: self.temporary,
            external: self.external,
            global: self.global,
            if_not_exists: self.if_not_exists,
            transient: self.transient,
            volatile: self.volatile,
            iceberg: self.iceberg,
            snapshot: self.snapshot,
            dynamic: self.dynamic,
            name: self.name,
            columns: self.columns,
            constraints: self.constraints,
            hive_distribution: self.hive_distribution,
            hive_formats: self.hive_formats,
            file_format: self.file_format,
            location: self.location,
            query: self.query,
            without_rowid: self.without_rowid,
            like: self.like,
            clone: self.clone,
            version: self.version,
            comment: self.comment,
            on_commit: self.on_commit,
            on_cluster: self.on_cluster,
            primary_key: self.primary_key,
            order_by: self.order_by,
            partition_by: self.partition_by,
            cluster_by: self.cluster_by,
            clustered_by: self.clustered_by,
            inherits: self.inherits,
            partition_of: self.partition_of,
            for_values: self.for_values,
            strict: self.strict,
            copy_grants: self.copy_grants,
            enable_schema_evolution: self.enable_schema_evolution,
            change_tracking: self.change_tracking,
            data_retention_time_in_days: self.data_retention_time_in_days,
            max_data_extension_time_in_days: self.max_data_extension_time_in_days,
            default_ddl_collation: self.default_ddl_collation,
            with_aggregation_policy: self.with_aggregation_policy,
            with_row_access_policy: self.with_row_access_policy,
            with_storage_lifecycle_policy: self.with_storage_lifecycle_policy,
            with_tags: self.with_tags,
            base_location: self.base_location,
            external_volume: self.external_volume,
            catalog: self.catalog,
            catalog_sync: self.catalog_sync,
            storage_serialization_policy: self.storage_serialization_policy,
            table_options: self.table_options,
            target_lag: self.target_lag,
            warehouse: self.warehouse,
            refresh_mode: self.refresh_mode,
            initialize: self.initialize,
            require_user: self.require_user,
            diststyle: self.diststyle,
            distkey: self.distkey,
            sortkey: self.sortkey,
            backup: self.backup,
        }
    }
}

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(create_table) => Ok(create_table.into()),
            _ => Err(ParserError::ParserError(format!(
                "Expected create table statement, but received: {stmt}"
            ))),
        }
    }
}

impl From<CreateTable> for CreateTableBuilder {
    fn from(table: CreateTable) -> Self {
        Self {
            or_replace: table.or_replace,
            temporary: table.temporary,
            external: table.external,
            global: table.global,
            if_not_exists: table.if_not_exists,
            transient: table.transient,
            volatile: table.volatile,
            iceberg: table.iceberg,
            snapshot: table.snapshot,
            dynamic: table.dynamic,
            name: table.name,
            columns: table.columns,
            constraints: table.constraints,
            hive_distribution: table.hive_distribution,
            hive_formats: table.hive_formats,
            file_format: table.file_format,
            location: table.location,
            query: table.query,
            without_rowid: table.without_rowid,
            like: table.like,
            clone: table.clone,
            version: table.version,
            comment: table.comment,
            on_commit: table.on_commit,
            on_cluster: table.on_cluster,
            primary_key: table.primary_key,
            order_by: table.order_by,
            partition_by: table.partition_by,
            cluster_by: table.cluster_by,
            clustered_by: table.clustered_by,
            inherits: table.inherits,
            partition_of: table.partition_of,
            for_values: table.for_values,
            strict: table.strict,
            copy_grants: table.copy_grants,
            enable_schema_evolution: table.enable_schema_evolution,
            change_tracking: table.change_tracking,
            data_retention_time_in_days: table.data_retention_time_in_days,
            max_data_extension_time_in_days: table.max_data_extension_time_in_days,
            default_ddl_collation: table.default_ddl_collation,
            with_aggregation_policy: table.with_aggregation_policy,
            with_row_access_policy: table.with_row_access_policy,
            with_storage_lifecycle_policy: table.with_storage_lifecycle_policy,
            with_tags: table.with_tags,
            base_location: table.base_location,
            external_volume: table.external_volume,
            catalog: table.catalog,
            catalog_sync: table.catalog_sync,
            storage_serialization_policy: table.storage_serialization_policy,
            table_options: table.table_options,
            target_lag: table.target_lag,
            warehouse: table.warehouse,
            refresh_mode: table.refresh_mode,
            initialize: table.initialize,
            require_user: table.require_user,
            diststyle: table.diststyle,
            distkey: table.distkey,
            sortkey: table.sortkey,
            backup: table.backup,
        }
    }
}

/// Helper return type when parsing configuration for a `CREATE TABLE` statement.
#[derive(Default)]
pub(crate) struct CreateTableConfiguration {
    pub partition_by: Option<Box<Expr>>,
    pub cluster_by: Option<WrappedCollection<Vec<Expr>>>,
    pub inherits: Option<Vec<ObjectName>>,
    pub table_options: CreateTableOptions,
}

#[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::from(vec![Ident::new("table_name")]));

        let create_table = builder.clone().build();
        let stmt: Statement = create_table.into();

        assert_eq!(builder, CreateTableBuilder::try_from(stmt).unwrap());
    }

    #[test]
    pub fn test_from_invalid_statement() {
        let stmt = Statement::Commit {
            chain: false,
            end: false,
            modifier: None,
        };

        assert_eq!(
            CreateTableBuilder::try_from(stmt).unwrap_err(),
            ParserError::ParserError(
                "Expected create table statement, but received: COMMIT".to_owned()
            )
        );
    }
}
