oxide-sql-core 0.2.0

Type-safe SQL parser and builder with compile-time validation
Documentation
//! Schema traits for type-safe table and column definitions.
//!
//! This module provides traits that are implemented by the `#[derive(Table)]`
//! macro to enable compile-time checked SQL queries.

/// Trait for table metadata.
///
/// Implemented by types generated from `#[derive(Table)]` to provide
/// table-level information.
pub trait Table {
    /// The row type (the original struct).
    type Row;

    /// The SQL table name.
    const NAME: &'static str;

    /// List of all column names.
    const COLUMNS: &'static [&'static str];

    /// The primary key column name, if any.
    const PRIMARY_KEY: Option<&'static str>;
}

/// Trait for column metadata.
///
/// Implemented by column types generated from `#[derive(Table)]` to provide
/// column-level information and enable type-safe queries.
pub trait Column {
    /// The table this column belongs to.
    type Table: Table;

    /// The Rust type of this column.
    type Type;

    /// The SQL column name.
    const NAME: &'static str;

    /// Whether this column is nullable.
    const NULLABLE: bool;

    /// Whether this column is the primary key.
    const PRIMARY_KEY: bool;
}

/// Marker trait for columns with a specific Rust type.
///
/// Used for compile-time type checking of values in queries.
pub trait TypedColumn<T>: Column<Type = T> {}

/// Trait for selecting specific columns from a table.
///
/// Implemented for tuples of column types to enable type-safe SELECT queries.
pub trait Selectable<T: Table> {
    /// Returns the column names to select.
    fn column_names() -> &'static [&'static str];
}

// Implement Selectable for single columns
impl<T: Table, C: Column<Table = T>> Selectable<T> for C {
    fn column_names() -> &'static [&'static str] {
        // Return as a slice containing just this column
        // This is a compile-time constant
        &[C::NAME]
    }
}

/// Runtime column metadata (generated by derive macro).
#[derive(Debug, Clone)]
pub struct ColumnSchema {
    /// The SQL column name.
    pub name: &'static str,
    /// The Rust type name as a canonical string (spaces stripped).
    pub rust_type: &'static str,
    /// Whether this column is nullable.
    pub nullable: bool,
    /// Whether this column is the primary key.
    pub primary_key: bool,
    /// Whether this column has a UNIQUE constraint.
    pub unique: bool,
    /// Whether this column auto-increments.
    pub autoincrement: bool,
    /// Raw SQL default expression, if any.
    pub default_expr: Option<&'static str>,
}

/// Tables that provide full column schema for DDL generation.
///
/// Implemented by the `#[derive(Table)]` macro alongside the `Table`
/// trait. While `Table` gives you column *names*, `TableSchema` gives
/// you full column metadata (types, constraints, defaults) needed to
/// generate CREATE TABLE statements.
pub trait TableSchema: Table {
    /// Complete schema for every column in declaration order.
    const SCHEMA: &'static [ColumnSchema];
}

/// Maps Rust type names to SQL data types.
///
/// Each dialect implements this to provide its own mapping from the
/// canonical Rust type string (e.g. `"String"`, `"i64"`) to a SQL
/// [`DataType`](crate::ast::DataType).
pub trait RustTypeMapping {
    /// Maps a Rust type name to the dialect-specific SQL data type.
    fn map_type(&self, rust_type: &str) -> crate::ast::DataType;
}

// Implement Selectable for tuples of columns (up to 12)
macro_rules! impl_selectable_tuple {
    ($($idx:tt: $col:ident),+) => {
        impl<T: Table, $($col: Column<Table = T>),+> Selectable<T> for ($($col,)+) {
            fn column_names() -> &'static [&'static str] {
                &[$($col::NAME),+]
            }
        }
    };
}

impl_selectable_tuple!(0: C0);
impl_selectable_tuple!(0: C0, 1: C1);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9, 10: C10);
impl_selectable_tuple!(0: C0, 1: C1, 2: C2, 3: C3, 4: C4, 5: C5, 6: C6, 7: C7, 8: C8, 9: C9, 10: C10, 11: C11);