sqlw 0.1.0

Compile-time SQL query building with schema-safe field references and automatic parameter binding
Documentation
//! Table schema definitions.
//!
//! Use the [`schema!`](crate::schema!) macro to generate a schema type that
//! provides both **typed field constants** for SQL generation and a **value struct**
//! with one public field per column. Alternatively, implement [`Schema`] manually
//! for fully custom definitions.
//!
//! # Example
//!
//! ```ignore
//! use sqlw::schema;
//!
//! schema!(User "users" {
//!     ID: i64 "id",
//!     NAME: String "name",
//!     EMAIL: String "email",
//! });
//!
//! // Generated value struct (field names from column strings):
//! // #[derive(Debug, Default)]
//! // pub struct User {
//! //     pub id: i64,
//! //     pub name: String,
//! //     pub email: String,
//! // }
//!
//! // Generated constants:
//! // User::TABLE -> Def<User>             = "users"
//! // User::ID    -> Def<User, Typed<i64>>  = "id"
//! // User::NAME  -> Def<User, Typed<String>> = "name"
//! // User::EMAIL -> Def<User, Typed<String>> = "email"
//! ```

use std::marker::PhantomData;

use crate::Value;

/// Marker trait for schema types.
///
/// Schema types provide `TABLE` and field constants for schema-safe
/// SQL generation. Typically derived via the [`schema!`](crate::schema!) macro.
pub trait Schema {}

/// Marker for schema defs without a declared bind type.
#[derive(Debug, Clone, Copy)]
pub struct Untyped;

/// Marker for schema defs with a declared bind type.
#[derive(Debug, Clone, Copy)]
pub struct Typed<T>(PhantomData<T>);

/// A schema definition entry for a schema type.
///
/// Used for both table and field constants. The wrapped string can be
/// interpreted as either a table name or a column name depending on context.
/// Access the underlying identifier with [`desc`](Self::desc).
#[derive(Debug, Clone, Copy)]
pub struct Def<S: Schema, K = Untyped> {
    name: &'static str,
    _schema: PhantomData<(S, K)>,
}

impl<S: Schema, K> Def<S, K> {
    /// Creates a new schema definition entry.
    pub const fn new(name: &'static str) -> Self {
        Self {
            name,
            _schema: PhantomData,
        }
    }

    /// Returns the table or column name.
    pub const fn desc(&self) -> &str {
        self.name
    }
}

/// Binding behavior attached to a schema field definition kind.
pub trait BindParam<V> {
    /// Binds a value to this schema definition, producing a [`Value`].
    fn bind(self, value: V) -> Value;
}

impl<S: Schema, K, V> BindParam<V> for Def<S, K>
where
    V: Into<Value>,
{
    fn bind(self, value: V) -> Value {
        value.into()
    }
}

/// Binds a value using the expected type carried by a schema field definition.
pub fn bind<D, V>(def: D, value: V) -> Value
where
    D: BindParam<V>,
{
    def.bind(value)
}