//! Typed column references. Generated by `#[derive(Model)]`.
//!
//! The point of `Column<M, T>` is compile-time type safety on the where clause:
//! `User::query().where_eq(User::columns().email(), 42)` fails because 42 is `i32`,
//! not `String`.

use std::marker::PhantomData;

use sea_query::DynIden;

#[derive(Debug, Clone, Copy)]
#[allow(clippy::type_complexity)]
pub struct Column<M, T> {
    name: &'static str,
    _marker: PhantomData<(fn() -> M, fn() -> T)>,
}

impl<M, T> Column<M, T> {
    pub const fn new(name: &'static str) -> Self {
        Self {
            name,
            _marker: PhantomData,
        }
    }

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

    pub fn iden(&self) -> sea_query::Alias {
        sea_query::Alias::new(self.name)
    }
}

/// Untyped column reference for the query builder's internal use.
#[derive(Debug, Clone)]
pub struct ColumnRef {
    pub table: Option<&'static str>,
    pub name: &'static str,
}

impl ColumnRef {
    pub fn new(name: &'static str) -> Self {
        Self { table: None, name }
    }

    pub fn qualified(table: &'static str, name: &'static str) -> Self {
        Self {
            table: Some(table),
            name,
        }
    }

    pub fn iden(&self) -> DynIden {
        sea_query::SeaRc::new(sea_query::Alias::new(self.name))
    }
}

impl<M, T> From<Column<M, T>> for ColumnRef {
    fn from(c: Column<M, T>) -> Self {
        ColumnRef::new(c.name)
    }
}
