Skip to main content

fletch_orm/
entity.rs

1//! Entity trait for database-backed types.
2
3use std::fmt::Debug;
4use std::hash::Hash;
5
6use crate::column::Column;
7use crate::value::Value;
8
9/// Describes the schema of a database-backed entity.
10///
11/// Implementors specify the table name, columns, and primary key column
12/// so that fletch can generate SQL for CRUD operations.
13pub trait Entity: Send + Sync + Sized {
14    /// The Rust type of the primary key (e.g. `i64`, `String`, `Uuid`).
15    type Id: Debug + Clone + PartialEq + Eq + Hash + Send + Sync + Into<Value>;
16
17    /// The database table name for this entity.
18    fn table_name() -> &'static str;
19
20    /// The name of the primary key column.
21    fn id_column() -> &'static str;
22
23    /// All columns for this entity (including the id column).
24    fn columns() -> &'static [Column];
25
26    /// Returns the primary key value of this entity instance.
27    fn id(&self) -> Self::Id;
28
29    /// Returns the values for all columns, in the same order as [`columns`](Entity::columns).
30    fn values(&self) -> Vec<Value>;
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36    use crate::column::ColumnType;
37
38    struct TestEntity {
39        id: i64,
40        name: String,
41    }
42
43    impl Entity for TestEntity {
44        type Id = i64;
45
46        fn table_name() -> &'static str {
47            "test_entities"
48        }
49
50        fn id_column() -> &'static str {
51            "id"
52        }
53
54        fn columns() -> &'static [Column] {
55            static COLS: [Column; 2] = [
56                Column::new("id", ColumnType::Integer),
57                Column::new("name", ColumnType::Text),
58            ];
59            &COLS
60        }
61
62        fn id(&self) -> Self::Id {
63            self.id
64        }
65
66        fn values(&self) -> Vec<Value> {
67            vec![Value::I64(self.id), Value::Text(self.name.clone())]
68        }
69    }
70
71    #[test]
72    fn entity_table_name() {
73        assert_eq!(TestEntity::table_name(), "test_entities");
74    }
75
76    #[test]
77    fn entity_id_column() {
78        assert_eq!(TestEntity::id_column(), "id");
79    }
80
81    #[test]
82    fn entity_columns() {
83        let cols = TestEntity::columns();
84        assert_eq!(cols.len(), 2);
85        assert_eq!(cols[0].name(), "id");
86        assert_eq!(cols[0].column_type(), ColumnType::Integer);
87        assert_eq!(cols[1].name(), "name");
88        assert_eq!(cols[1].column_type(), ColumnType::Text);
89    }
90
91    #[test]
92    fn entity_id() {
93        let e = TestEntity {
94            id: 42,
95            name: "Alice".into(),
96        };
97        assert_eq!(e.id(), 42);
98    }
99
100    #[test]
101    fn entity_values() {
102        let e = TestEntity {
103            id: 1,
104            name: "Bob".into(),
105        };
106        let vals = e.values();
107        assert_eq!(vals.len(), 2);
108        assert_eq!(vals[0], Value::I64(1));
109        assert_eq!(vals[1], Value::Text("Bob".into()));
110    }
111
112    #[test]
113    fn column_type_debug() {
114        assert_eq!(format!("{:?}", ColumnType::Text), "Text");
115        assert_eq!(format!("{:?}", ColumnType::Integer), "Integer");
116        assert_eq!(format!("{:?}", ColumnType::Uuid), "Uuid");
117    }
118}