#![cfg(feature = "type-safe-columns")]
use std::marker::PhantomData;
pub trait Schema {
fn schema_table_name() -> &'static str;
}
pub struct Column<T: Schema> {
name: &'static str,
_marker: PhantomData<T>,
}
impl<T: Schema> Clone for Column<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Schema> Copy for Column<T> {}
impl<T: Schema> std::fmt::Debug for Column<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Column")
.field("name", &self.name)
.field("table", &T::schema_table_name())
.finish()
}
}
impl<T: Schema> PartialEq for Column<T> {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl<T: Schema> Eq for Column<T> {}
impl<T: Schema> std::hash::Hash for Column<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl<T: Schema> Column<T> {
pub const fn new(name: &'static str) -> Self {
Column {
name,
_marker: PhantomData,
}
}
pub const fn name(&self) -> &'static str {
self.name
}
pub fn table_name() -> &'static str {
T::schema_table_name()
}
}
impl<T: Schema> std::fmt::Display for Column<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl<T: Schema> std::ops::Deref for Column<T> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.name
}
}
impl<T: Schema> AsRef<str> for Column<T> {
fn as_ref(&self) -> &str {
self.name
}
}
impl<T: Schema> From<&'static str> for Column<T> {
fn from(name: &'static str) -> Self {
Column::new(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestTable;
impl Schema for TestTable {
fn schema_table_name() -> &'static str {
"test_table"
}
}
#[test]
fn test_column_basic() {
let col = Column::<TestTable>::new("id");
assert_eq!(col.name(), "id");
assert_eq!(&*col, "id");
assert_eq!(col.to_string(), "id");
assert_eq!(col.as_ref(), "id");
}
#[test]
fn test_column_table_name() {
assert_eq!(Column::<TestTable>::table_name(), "test_table");
}
#[test]
fn test_column_deref() {
let col = Column::<TestTable>::new("name");
let s: &str = &col;
assert_eq!(s, "name");
}
#[test]
fn test_column_from_str() {
let col: Column<TestTable> = "email".into();
assert_eq!(col.name(), "email");
}
#[test]
fn test_column_copy() {
let col = Column::<TestTable>::new("id");
let col2 = col;
assert_eq!(col.name(), col2.name());
}
#[test]
fn test_column_eq() {
let col1 = Column::<TestTable>::new("id");
let col2 = Column::<TestTable>::new("id");
let col3 = Column::<TestTable>::new("name");
assert_eq!(col1, col2);
assert_ne!(col1, col3);
}
}