#![warn(missing_docs)]

//! # Schema Module
//!
//! This module provides the core schema definition functionality for Lume.
//! It includes the schema trait, column definitions, and the powerful `define_schema!` macro.
//!
//! ## Key Components
//!
//! - [`Schema`] trait: Core trait for all database schemas
//! - [`Column<T>`]: Type-safe column definition with constraints
//! - [`Value`]: Enum for storing and converting between database values
//! - [`define_schema!`]: Macro for ergonomic schema definition
//!
//! ## Example
//!
//! ```no_run,ignore
//! use lume::define_schema;
//!
//! define_schema! {
//!     User {
//!         id: i32 [primary_key().not_null()],
//!         name: String [not_null()],
//!         email: String [unique()],
//!         age: i32,
//!         active: bool [default_value(true)],
//!     }
//! }
//! ```

mod column;

use std::collections::HashMap;
use std::marker::PhantomData;

use crate::schema::column::GeneratedColumn;
use crate::table::TableDefinition;
pub use column::Column;
pub use column::Value;
pub use column::convert_to_value;
use std::fmt::Debug;

/// Helper macro: decides field type as `Option<T>` if `default_value(...)` or
/// `auto_increment()` is present in the column args; otherwise keeps it as `T`.
#[macro_export]
macro_rules! __lume_option_type {
    ($ty:ty) => { $ty };
    ($ty:ty, []) => { $ty };
    // If args contain default_value(...), make it Option
    ($ty:ty, [ default_value ( $($inner:tt)* ) $($tail:tt)* ]) => { Option<$ty> };
    // If args contain auto_increment(), make it Option
    ($ty:ty, [ auto_increment ( ) $($tail:tt)* ]) => { Option<$ty> };
    // Recurse through any other tokens
    ($ty:ty, [ $head:tt $($tail:tt)* ]) => { $crate::__lume_option_type!($ty, [ $($tail)* ]) };
}

/// Core trait that all database schemas must implement.
///
/// This trait provides the interface for schema registration, column retrieval,
/// and table metadata. It's automatically implemented by the `define_schema!` macro.
///
/// # Example
///
/// ```rust
/// use lume::define_schema;
/// use lume::schema::{Schema, ColumnInfo};
///
/// define_schema! {
///     Product {
///         id: i32 [primary_key()],
///         name: String [not_null()],
///     }
/// }
///
/// // The Schema trait is automatically implemented
/// assert_eq!(Product::table_name(), "Product");
/// let columns = Product::get_all_columns();
/// ```
pub trait Schema {
    /// Returns the table name for this schema.
    ///
    /// This is used for SQL generation and table registry.
    fn table_name() -> &'static str;

    /// Returns metadata for all columns in this schema.
    ///
    /// This includes column names, types, constraints, and other metadata
    /// needed for SQL generation and type checking.
    fn get_all_columns() -> Vec<ColumnInfo>;

    /// Ensures the schema is registered in the table registry.
    ///
    /// This method is idempotent and can be called multiple times safely.
    /// It's automatically called when using the generated schema methods.
    fn ensure_registered();

    /// Returns a map of column names to their corresponding values for this schema instance.
    ///
    /// This method is used to extract the values of all fields in the schema as a
    /// `HashMap<String, Value>`, where each key is the column name and each value is
    /// the associated database value. This is primarily used for insert and update
    /// operations to serialize the struct into a form suitable for database interaction.
    fn values(&self) -> HashMap<String, Value>;
}

/// Trait for extracting updated column values for SQL UPDATE operations.
///
/// The `UpdateTrait` trait is implemented by update structs generated by the
/// `define_schema!` macro. It provides a method to retrieve a vector of
/// column-value pairs representing the fields to be updated in the database.
pub trait UpdateTrait {
    /// Returns a vector of (column name, value) pairs to be updated.
    ///
    /// Only fields that are set (e.g., `Some(value)`) should be included.
    fn get_updated(self) -> Vec<(&'static str, Value)>;
}

/// Trait for specifying column selection in queries.
///
/// The `Select` trait is used to define which columns should be included
/// in a SQL SELECT statement. It is typically implemented by selection
/// structs generated by the `define_schema!` macro, and is used by the
/// query builder to determine which columns to fetch from the database.
///
/// # Example
///
/// ```rust
/// use lume::define_schema;
/// use lume::schema::Select;
/// use lume::schema::ColumnInfo;
/// use lume::schema::Schema;
///
/// define_schema! {
///     User {
///         id: i32 [primary_key()],
///         name: String [not_null()],
///         age: i32,
///     }
/// }
///
/// // The macro generates a selection struct (e.g., SelectUser) that implements Select.
/// // You can use it to specify which columns to select in a query.
/// // let selection = SelectUser::default();
/// // let columns = selection.get_selected();
/// ```
pub trait Select {
    /// Returns the default selection schema.
    ///
    /// This is typically all columns, but can be customized.
    fn default() -> Self;

    /// Returns a vector of column names to be selected.
    ///
    /// This determines which columns will be included in the SQL SELECT clause.
    fn get_selected(self) -> Vec<&'static str>;
}

/// Metadata information for a database column.
///
/// This struct contains all the necessary information about a column
/// for SQL generation, type checking, and constraint validation.
///
/// # Fields
///
/// - `name`: The column name in the database
/// - `data_type`: The SQL data type (e.g., "INTEGER", "VARCHAR(255)")
/// - `nullable`: Whether the column allows NULL values
/// - `unique`: Whether the column has a UNIQUE constraint
/// - `primary_key`: Whether the column is a primary key
/// - `indexed`: Whether the column has an index
/// - `has_default`: Whether the column has a default value
/// - `default_sql`: The SQL representation of the default value
#[derive(Debug, Clone)]
pub struct ColumnInfo {
    /// The column name in the database
    pub name: &'static str,
    /// The SQL data type (e.g., "INTEGER", "VARCHAR(255)")
    pub data_type: &'static str,
    /// Whether the column allows NULL values
    pub nullable: bool,
    /// Whether the data should be an email
    pub email: bool,
    /// Whether the column is a link
    pub link: bool,
    /// Minimum length of the column
    pub min_len: Option<i32>,
    /// Maximum length of the column
    pub max_len: Option<i32>,
    /// Minimum value of the column
    pub min: Option<usize>,
    /// Maximum value of the column
    pub max: Option<usize>,
    /// Whether the column has a UNIQUE constraint
    pub unique: bool,
    /// Whether the column is a primary key
    pub primary_key: bool,
    /// Whether the column has an index
    pub indexed: bool,
    /// Whether the column has a default value
    pub has_default: bool,
    /// The SQL representation of the default value
    pub default_sql: Option<String>,
    /// Whether this column auto-increments (MySQL AUTO_INCREMENT)
    pub auto_increment: bool,
    /// Optional column comment (MySQL COMMENT)
    pub comment: Option<&'static str>,
    /// Optional character set (MySQL CHARACTER SET)
    pub charset: Option<&'static str>,
    /// Optional collation (MySQL COLLATE)
    pub collate: Option<&'static str>,
    /// Whether column has ON UPDATE CURRENT_TIMESTAMP behavior (MySQL)
    pub on_update_current_timestamp: bool,
    /// Whether this column is invisible (MySQL 8: INVISIBLE)
    pub invisible: bool,
    /// Optional CHECK constraint expression (MySQL 8)
    pub check: Option<&'static str>,
    /// Optional generated column definition (VIRTUAL or STORED)
    pub generated: Option<GeneratedColumn>,
}

/// Defines a database schema with type-safe columns and constraints.
///
/// This macro creates a schema struct that implements the [`Schema`] trait
/// and provides type-safe access to column definitions.
///
/// # Syntax
///
/// ```rust
/// use lume::define_schema;
/// use lume::schema::{Schema, ColumnInfo};
///
/// define_schema! {
///     TableName {
///         column_name: i32 [primary_key()],
///         another_column: String [not_null()],
///     }
/// }
/// ```
///
/// # Column Constraints
///
/// - `primary_key()` - Sets the column as primary key
/// - `not_null()` - Makes the column NOT NULL
/// - `unique()` - Adds a UNIQUE constraint
/// - `indexed()` - Creates an index on the column
/// - `default_value(value)` - Sets a default value
///
/// # Example
///
/// ```rust
/// use lume::define_schema;
/// use lume::schema::{Schema, ColumnInfo};
///
/// define_schema! {
///     User {
///         id: i32 [primary_key().not_null()],
///         username: String [not_null().unique()],
///         email: String [not_null()],
///         age: i32,
///         is_active: bool [default_value(true)],
///         created_at: i64 [not_null()],
///     }
/// }
///
/// // Access columns type-safely
/// let id_col = User::id();
/// let username_col = User::username();
///
/// // Get schema information
/// assert_eq!(User::table_name(), "User");
/// let columns = User::get_all_columns();
/// ```
///
/// # Generated Code
///
/// This macro generates:
/// - A struct with the given name
/// - Column accessor methods that return `&'static Column<T>`
/// - Implementation of the [`Schema`] trait
/// - Automatic table registration
#[macro_export]
macro_rules! define_schema {
    (
        $(
            $struct_name:ident {
            $(
                $name:ident: $type:ty $([ $($args:tt)* ])?
            ),* $(,)?
        }
    )*
    ) => {
    // Auto-register the table when the struct is defined
    #[allow(non_upper_case_globals)]
    static _REGISTER: std::sync::Once = std::sync::Once::new();
    use $crate::table::register_table;
    use $crate::schema::type_to_sql_string;
    use $crate::schema::DefaultToSql;
    use std::collections::HashMap;
    use $crate::schema::Value;

        $(
        #[derive(Debug)]
        pub struct $struct_name {
            $(
                pub $name: $crate::__lume_option_type!($type $(, [ $($args)* ])? ),
            )*
        }

        paste::paste! {
            #[derive(Debug)]
            pub struct [<Update $struct_name>] {
                $(
                    pub $name: Option<$type>,
                )*
            }

            impl Default for [<Update $struct_name>] {
                fn default() -> Self {
                    Self {
                        $(
                            $name: None,
                        )*
                    }
                }
            }

            impl [<Update $struct_name>] {
                $(
                    pub fn $name() -> &'static $crate::schema::Column<$type> {
                        static COL: std::sync::OnceLock<$crate::schema::Column<$type>> = std::sync::OnceLock::new();
                        COL.get_or_init(|| {
                            $crate::schema::Column::<$type>::new(stringify!($name), stringify!($struct_name))
                                $(.$($args)*)?
                        })
                    }
                )*

            }
            impl $crate::schema::UpdateTrait for [<Update $struct_name>] {

                fn get_updated(self) -> Vec<(&'static str, Value)> {
                    let mut vec = Vec::new();

                    $(
                        if self.$name.is_some() {
                            vec.push((stringify!($struct_name.$name), $crate::schema::convert_to_value(&self.$name)));
                        }
                    )*

                    vec
                }
            }



            impl $crate::schema::Schema for [<Update $struct_name>] {
                fn table_name() -> &'static str {
                    stringify!($struct_name)
                }

                fn values(&self) -> HashMap<String, Value> {
                    let mut map = HashMap::new();
                    $(
                        map.insert(
                            stringify!($name).to_string(),
                            $crate::schema::convert_to_value(&self.$name)
                        );
                    )*
                    map
                }
                fn ensure_registered() {
                    // Function-local static to avoid name collisions across macro expansions
                    static REGISTER: std::sync::Once = std::sync::Once::new();
                    REGISTER.call_once(|| {
                        register_table::<$struct_name>();
                    });
                }

                fn get_all_columns() -> Vec<$crate::schema::ColumnInfo> {
                    vec![
                        $(
                            {
                                let col = Self::$name();

                                $crate::schema::ColumnInfo {
                                    name: col.name(),
                                    data_type: type_to_sql_string::<$type>(),
                                    nullable: col.is_nullable(),
                                    unique: col.is_unique(),
                                    primary_key: col.is_primary_key(),
                                    indexed: col.is_indexed(),
                                    has_default: col.get_default().is_some(),
                                    default_sql: col.default_to_sql(),
                                    auto_increment: col.is_auto_increment(),
                                    comment: col.get_comment(),
                                    charset: col.get_charset(),
                                    collate: col.get_collate(),
                                    on_update_current_timestamp: col.has_on_update_current_timestamp(),
                                    invisible: col.is_invisible(),
                                    check: col.get_check(),
                                    generated: col.get_generated(),
                                    email: col.is_email(),
                                    min: col.min,
                                    max: col.max,
                                    min_len: col.min_len,
                                    max_len: col.max_len,
                                    link: col.is_link(),
                                }
                            }
                        ),*
                    ]
                }
            }
        }

        paste::paste! {
            #[derive(Debug)]
            pub struct [<Select $struct_name>] {
                $(
                    pub $name: bool,
                )*
            }

            impl [<Select $struct_name>] {

                $(
                    fn $name(mut self) -> Self {
                        self.$name = true;
                        self
                    }
                )*

                #[allow(dead_code)]
                fn selected() -> Self {
                    Self {
                        $(
                            $name: false,
                        )*
                    }
                }

                fn all(mut self) -> Self {
                    $(
                        self.$name = true;
                    )*

                    self
                }
            }

            impl Default for [<Select $struct_name>] {
                fn default() -> Self {
                    Self {
                        $(
                            $name: false,
                        )*
                    }
                }
            }

            impl $crate::schema::Select for [<Select $struct_name>] {
                fn default() -> Self {
                    Self {
                        $(
                            $name: true,
                        )*
                    }
                }


                fn get_selected(self) -> Vec<&'static str> {
                    let mut vec = Vec::new();

                    $(
                        if self.$name {
                            vec.push(stringify!($struct_name.$name))
                        }
                    )*

                    vec
                }
            }
        }


        impl $struct_name {
            $(
                pub fn $name() -> &'static $crate::schema::Column<$type> {
                    static COL: std::sync::OnceLock<$crate::schema::Column<$type>> = std::sync::OnceLock::new();
                    COL.get_or_init(|| {
                        $crate::schema::Column::<$type>::new(stringify!($name), stringify!($struct_name))
                            $(.$($args)*)?
                    })
                }
            )*
        }


        impl $crate::schema::Schema for $struct_name {
            fn table_name() -> &'static str {
                stringify!($struct_name)
            }

            fn values(&self) -> HashMap<String, Value> {
                let mut map = HashMap::new();
                $(
                    map.insert(
                        stringify!($name).to_string(),
                        $crate::schema::convert_to_value(&self.$name)
                    );
                )*
                map
            }
            fn ensure_registered() {
                // Function-local static to avoid name collisions across macro expansions
                static REGISTER: std::sync::Once = std::sync::Once::new();
                REGISTER.call_once(|| {
                    register_table::<$struct_name>();
                });
            }

            fn get_all_columns() -> Vec<$crate::schema::ColumnInfo> {
                vec![
                    $(
                        {
                            let col = Self::$name();

                            $crate::schema::ColumnInfo {
                                name: col.name(),
                                data_type: type_to_sql_string::<$type>(),
                                nullable: col.is_nullable(),
                                unique: col.is_unique(),
                                primary_key: col.is_primary_key(),
                                indexed: col.is_indexed(),
                                has_default: col.get_default().is_some(),
                                default_sql: col.default_to_sql(),
                                auto_increment: col.is_auto_increment(),
                                comment: col.get_comment(),
                                charset: col.get_charset(),
                                collate: col.get_collate(),
                                on_update_current_timestamp: col.has_on_update_current_timestamp(),
                                invisible: col.is_invisible(),
                                check: col.get_check(),
                                generated: col.get_generated(),
                                email: col.is_email(),
                                min: col.min,
                                max: col.max,
                                min_len: col.min_len,
                                max_len: col.max_len,
                                link: col.is_link(),
                            }
                        }
                    ),*
                ]
            }
        }
        )*
    };
}

/// Converts a Rust type to its corresponding SQL type string.
///
/// This function provides the mapping between Rust types and SQL column types
/// used in database schema generation.
///
/// # Supported Types
///
/// - `String` → `"VARCHAR(255)"`
/// - `i8` → `"TINYINT"`
/// - `i16` → `"SMALLINT"`
/// - `i32` → `"INTEGER"`
/// - `i64` → `"BIGINT"`
/// - `u8` → `"TINYINT UNSIGNED"`
/// - `u16` → `"SMALLINT UNSIGNED"`
/// - `u32` → `"INTEGER UNSIGNED"`
/// - `u64` → `"BIGINT UNSIGNED"`
/// - `f32` → `"FLOAT"`
/// - `f64` → `"DOUBLE"`
/// - `bool` → `"BOOLEAN"`
/// - All other types → `"TEXT"` (fallback)
///
/// # Example
///
/// ```rust
/// use lume::schema::type_to_sql_string;
///
/// assert_eq!(type_to_sql_string::<String>(), "VARCHAR(255)");
/// assert_eq!(type_to_sql_string::<i32>(), "INTEGER");
/// assert_eq!(type_to_sql_string::<i64>(), "BIGINT");
/// assert_eq!(type_to_sql_string::<u64>(), "BIGINT UNSIGNED");
/// assert_eq!(type_to_sql_string::<bool>(), "BOOLEAN");
/// ```
pub fn type_to_sql_string<T: 'static>() -> &'static str {
    use std::any::TypeId;

    let type_id = TypeId::of::<T>();

    if type_id == TypeId::of::<String>() {
        "VARCHAR(255)"
    } else if type_id == TypeId::of::<i8>() {
        "TINYINT"
    } else if type_id == TypeId::of::<i16>() {
        "SMALLINT"
    } else if type_id == TypeId::of::<i32>() {
        "INTEGER"
    } else if type_id == TypeId::of::<i64>() {
        "BIGINT"
    } else if type_id == TypeId::of::<u8>() {
        "TINYINT UNSIGNED"
    } else if type_id == TypeId::of::<u16>() {
        "SMALLINT UNSIGNED"
    } else if type_id == TypeId::of::<u32>() {
        "INTEGER UNSIGNED"
    } else if type_id == TypeId::of::<u64>() {
        "BIGINT UNSIGNED"
    } else if type_id == TypeId::of::<f32>() {
        "FLOAT"
    } else if type_id == TypeId::of::<f64>() {
        "DOUBLE"
    } else if type_id == TypeId::of::<bool>() {
        "BOOLEAN"
    } else {
        "TEXT" // fallback
    }
}

/// A wrapper around a schema type that implements [`TableDefinition`].
///
/// This struct is used internally to bridge between the [`Schema`] trait
/// and the [`TableDefinition`] trait for table registry and SQL generation.
///
/// # Type Parameters
///
/// - `T`: The schema type that implements [`Schema`]
#[derive(Debug)]
pub(crate) struct SchemaWrapper<T: Schema + Debug> {
    _phantom: PhantomData<T>,
}

// Implement Clone for SchemaWrapper<T>
impl<T: Schema + Debug> Clone for SchemaWrapper<T> {
    fn clone(&self) -> Self {
        Self {
            _phantom: PhantomData,
        }
    }
}

impl<T: Schema + Debug> SchemaWrapper<T> {
    /// Creates a new `SchemaWrapper` instance.
    pub(crate) fn new() -> Self {
        Self {
            _phantom: PhantomData,
        }
    }
}

impl<T: Schema + Debug + Sync + Send + 'static> TableDefinition for SchemaWrapper<T> {
    fn table_name(&self) -> &'static str {
        T::table_name()
    }

    fn get_columns(&self) -> Vec<ColumnInfo> {
        T::get_all_columns()
    }

    fn to_create_sql(&self) -> String {
        let table_name = self.table_name();
        let columns = self.get_columns();

        let mut sql = format!("CREATE TABLE IF NOT EXISTS {} (\n", table_name);

        let column_definitions: Vec<String> = columns
            .iter()
            .map(|col| {
                let mut def = format!("    {} {}", col.name, col.data_type);

                if col.primary_key {
                    def.push_str(" PRIMARY KEY");
                }

                if !col.nullable && !col.primary_key {
                    def.push_str(" NOT NULL");
                }

                if col.unique && !col.primary_key {
                    def.push_str(" UNIQUE");
                }

                if col.auto_increment && col.primary_key && is_mysql_integer_type(col.data_type) {
                    def.push_str(" AUTO_INCREMENT");
                }

                if col.on_update_current_timestamp {
                    def.push_str(" ON UPDATE CURRENT_TIMESTAMP");
                }

                if col.comment.is_some() {
                    let escaped = col.comment.unwrap().replace("'", "''");
                    def.push_str(&format!(" COMMENT '{}'", escaped));
                }

                if col.charset.is_some() {
                    def.push_str(&format!(" CHARACTER SET {}", col.charset.unwrap()));
                }

                if col.collate.is_some() {
                    def.push_str(&format!(" COLLATE {}", col.collate.unwrap()));
                }

                if col.invisible {
                    def.push_str(" INVISIBLE");
                }

                if col.check.is_some() {
                    def.push_str(&format!(" CHECK ({})", col.check.unwrap()));
                }

                if col.generated.is_some() {
                    def.push_str(&format!(" GENERATED {}", col.generated.unwrap()));
                }

                if let Some(ref default) = col.default_sql {
                    def.push_str(&format!(" DEFAULT {}", default));
                }

                def
            })
            .collect();

        sql.push_str(&column_definitions.join(",\n"));
        sql.push_str("\n);");

        // Add indexes
        let indexes: Vec<String> = columns
            .iter()
            .filter(|col| col.indexed && !col.primary_key)
            .map(|col| {
                format!(
                    "CREATE INDEX idx_{}_{} ON {} ({});",
                    table_name, col.name, table_name, col.name
                )
            })
            .collect();

        if !indexes.is_empty() {
            sql.push_str("\n\n");
            sql.push_str(&indexes.join("\n"));
        }

        sql
    }

    fn clone_box(&self) -> Box<dyn TableDefinition> {
        Box::new(self.clone())
    }
}

/// Returns true if a MySQL data type string represents an integer type.
fn is_mysql_integer_type(data_type: &str) -> bool {
    match data_type {
        // Signed
        "TINYINT" | "SMALLINT" | "MEDIUMINT" | "INT" | "INTEGER" | "BIGINT" |
        // Unsigned variants may appear with a space and suffix
        "TINYINT UNSIGNED" | "SMALLINT UNSIGNED" | "MEDIUMINT UNSIGNED" |
        "INT UNSIGNED" | "INTEGER UNSIGNED" | "BIGINT UNSIGNED" => true,
        _ => false,
    }
}

/// Trait for converting column default values to SQL representation.
///
/// This trait is implemented for all supported column types to provide
/// proper SQL formatting of default values in CREATE TABLE statements.
///
/// # Example
///
/// ```rust
/// use lume::schema::{Column, DefaultToSql};
///
/// let string_col = Column::<String>::new("name", "users");
/// let int_col = Column::<i32>::new("age", "users");
/// let bool_col = Column::<bool>::new("active", "users");
///
/// // Set defaults
/// let string_col = string_col.default_value("John".to_string());
/// let int_col = int_col.default_value(25);
/// let bool_col = bool_col.default_value(true);
///
/// // Convert to SQL
/// assert_eq!(string_col.default_to_sql(), Some("'John'".to_string()));
/// assert_eq!(int_col.default_to_sql(), Some("25".to_string()));
/// assert_eq!(bool_col.default_to_sql(), Some("TRUE".to_string()));
/// ```
pub trait DefaultToSql {
    /// Converts the column's default value to its SQL representation.
    ///
    /// Returns `None` if the column has no default value.
    ///
    /// # Returns
    ///
    /// - `Some(String)`: The SQL representation of the default value
    /// - `None`: If no default value is set
    fn default_to_sql(&self) -> Option<String>;
}

// Implement for each column type
impl DefaultToSql for Column<String> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default()
            .map(|v| format!("'{}'", v.replace('\'', "''")))
    }
}

impl DefaultToSql for Column<i32> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<i64> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<f32> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<f64> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<bool> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| {
            if *v {
                "TRUE".to_string()
            } else {
                "FALSE".to_string()
            }
        })
    }
}

// Implement DefaultToSql for all integer types
impl DefaultToSql for Column<i8> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<i16> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<u8> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<u16> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<u32> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}

impl DefaultToSql for Column<u64> {
    fn default_to_sql(&self) -> Option<String> {
        self.get_default().map(|v| v.to_string())
    }
}
