fletch-orm 1.0.0

Lightweight database toolkit built on SQLx
Documentation
//! Entity trait for database-backed types.

use std::fmt::Debug;
use std::hash::Hash;

use crate::column::Column;
use crate::value::Value;

/// Describes the schema of a database-backed entity.
///
/// Implementors specify the table name, columns, and primary key column
/// so that fletch can generate SQL for CRUD operations.
pub trait Entity: Send + Sync + Sized {
    /// The Rust type of the primary key (e.g. `i64`, `String`, `Uuid`).
    type Id: Debug + Clone + PartialEq + Eq + Hash + Send + Sync + Into<Value>;

    /// The database table name for this entity.
    fn table_name() -> &'static str;

    /// The name of the primary key column.
    fn id_column() -> &'static str;

    /// All columns for this entity (including the id column).
    fn columns() -> &'static [Column];

    /// Returns the primary key value of this entity instance.
    fn id(&self) -> Self::Id;

    /// Returns the values for all columns, in the same order as [`columns`](Entity::columns).
    fn values(&self) -> Vec<Value>;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::column::ColumnType;

    struct TestEntity {
        id: i64,
        name: String,
    }

    impl Entity for TestEntity {
        type Id = i64;

        fn table_name() -> &'static str {
            "test_entities"
        }

        fn id_column() -> &'static str {
            "id"
        }

        fn columns() -> &'static [Column] {
            static COLS: [Column; 2] = [
                Column::new("id", ColumnType::Integer),
                Column::new("name", ColumnType::Text),
            ];
            &COLS
        }

        fn id(&self) -> Self::Id {
            self.id
        }

        fn values(&self) -> Vec<Value> {
            vec![Value::I64(self.id), Value::Text(self.name.clone())]
        }
    }

    #[test]
    fn entity_table_name() {
        assert_eq!(TestEntity::table_name(), "test_entities");
    }

    #[test]
    fn entity_id_column() {
        assert_eq!(TestEntity::id_column(), "id");
    }

    #[test]
    fn entity_columns() {
        let cols = TestEntity::columns();
        assert_eq!(cols.len(), 2);
        assert_eq!(cols[0].name(), "id");
        assert_eq!(cols[0].column_type(), ColumnType::Integer);
        assert_eq!(cols[1].name(), "name");
        assert_eq!(cols[1].column_type(), ColumnType::Text);
    }

    #[test]
    fn entity_id() {
        let e = TestEntity {
            id: 42,
            name: "Alice".into(),
        };
        assert_eq!(e.id(), 42);
    }

    #[test]
    fn entity_values() {
        let e = TestEntity {
            id: 1,
            name: "Bob".into(),
        };
        let vals = e.values();
        assert_eq!(vals.len(), 2);
        assert_eq!(vals[0], Value::I64(1));
        assert_eq!(vals[1], Value::Text("Bob".into()));
    }

    #[test]
    fn column_type_debug() {
        assert_eq!(format!("{:?}", ColumnType::Text), "Text");
        assert_eq!(format!("{:?}", ColumnType::Integer), "Integer");
        assert_eq!(format!("{:?}", ColumnType::Uuid), "Uuid");
    }
}