drizzle-core 0.3.1

A type-safe SQL query builder for Rust
Documentation
use crate::expr::Expr;
use crate::{SQLParam, SQLSchema, SQLSchemaType, SQLTable, SQLTableInfo};

/// Runtime metadata of a column, usable as a trait object.
///
/// Generated by the table macros for each column.
pub trait SQLColumnInfo: Send + Sync {
    /// Whether the column is `NOT NULL`.
    fn is_not_null(&self) -> bool;
    /// Whether the column is part of the primary key.
    fn is_primary_key(&self) -> bool;
    /// Whether the column has a `UNIQUE` constraint.
    fn is_unique(&self) -> bool;
    /// The column's SQL name.
    fn name(&self) -> &'static str;
    /// The column's SQL type, as written in `CREATE TABLE`.
    fn r#type(&self) -> &'static str;
    /// Whether the column has a default value.
    fn has_default(&self) -> bool;

    /// The table the column belongs to.
    fn table(&self) -> &'static dyn SQLTableInfo;
}

/// A table column for the dialect whose value type is `Value`.
///
/// Generated by the table macros for each column. A column is also a typed
/// expression ([`Expr`]), so it can be selected, compared and passed to SQL
/// functions.
#[diagnostic::on_unimplemented(
    message = "`{Self}` is not a SQL column for this dialect",
    label = "ensure this column's table was derived with #[SQLiteTable], #[PostgresTable], or #[MySQLTable]"
)]
pub trait SQLColumn<'a, Value: SQLParam + 'a>:
    SQLColumnInfo + Default + SQLSchema<'a, &'a str, Value> + Expr<'a, Value>
{
    /// The table the column belongs to.
    type Table: SQLTable<'a, Self::TableType, Value>;
    /// The table's dialect marker.
    type TableType: SQLSchemaType;
    /// The column's foreign key reference, if any.
    type ForeignKeys;
    /// The Rust type of the column's values.
    type Type: TryInto<Value>;

    /// Whether the column is part of the primary key.
    const PRIMARY_KEY: bool = false;
    /// Whether the column is `NOT NULL`.
    const NOT_NULL: bool = false;
    /// Whether the column has a `UNIQUE` constraint.
    const UNIQUE: bool = false;
    /// The column's constant default value, if any.
    const DEFAULT: Option<Self::Type> = None;

    /// The function that computes the column's default on insert, if any
    /// (`#[column(default_fn = ...)]`).
    fn default_fn(&'a self) -> Option<impl Fn() -> Self::Type> {
        None::<fn() -> Self::Type>
    }

    /// Creates a named placeholder with this column's SQL type and
    /// nullability, for use in prepared statements.
    ///
    /// The placeholder only binds values the column could hold. See
    /// [`TypedPlaceholder`](crate::TypedPlaceholder).
    fn placeholder(
        &self,
        name: &'static str,
    ) -> crate::placeholder::TypedPlaceholder<
        <Self as Expr<'a, Value>>::SQLType,
        <Self as Expr<'a, Value>>::Nullable,
    >
    where
        Self: Sized,
    {
        crate::placeholder::TypedPlaceholder::named(name)
    }
}

// Blanket implementation for references.
impl<T: SQLColumnInfo> SQLColumnInfo for &T {
    fn is_not_null(&self) -> bool {
        (*self).is_not_null()
    }

    fn is_primary_key(&self) -> bool {
        (*self).is_primary_key()
    }

    fn is_unique(&self) -> bool {
        (*self).is_unique()
    }

    fn name(&self) -> &'static str {
        (*self).name()
    }

    fn r#type(&self) -> &'static str {
        (*self).r#type()
    }

    fn has_default(&self) -> bool {
        (*self).has_default()
    }

    fn table(&self) -> &'static dyn SQLTableInfo {
        (*self).table()
    }
}

impl<'a, Value, T> SQLColumn<'a, Value> for &T
where
    Value: SQLParam + 'a,
    T: SQLColumn<'a, Value>,
    for<'r> &'r T: SQLColumnInfo + Default + SQLSchema<'a, &'a str, Value> + Expr<'a, Value>,
{
    type Table = T::Table;
    type TableType = T::TableType;
    type ForeignKeys = T::ForeignKeys;
    type Type = T::Type;

    const PRIMARY_KEY: bool = T::PRIMARY_KEY;
    const NOT_NULL: bool = T::NOT_NULL;
    const UNIQUE: bool = T::UNIQUE;
    const DEFAULT: Option<Self::Type> = T::DEFAULT;

    fn default_fn(&'a self) -> Option<impl Fn() -> Self::Type> {
        <T as SQLColumn<'a, Value>>::default_fn(*self)
    }
}

impl core::fmt::Debug for dyn SQLColumnInfo {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("SQLColumnInfo")
            .field("name", &self.name())
            .field("type", &self.r#type())
            .field("not_null", &self.is_not_null())
            .field("primary_key", &self.is_primary_key())
            .field("unique", &self.is_unique())
            .field("table", &self.table().name())
            .field("has_default", &self.has_default())
            .finish()
    }
}