Skip to main content

grorm/orm/
model.rs

1use crate::types::Value;
2
3/// Metadata about a single column in a model's table schema.
4///
5/// Generated automatically by `#[derive(DeriveModel)]` and used by
6/// [`QueryBuilder::create_table`] to generate DDL statements.
7///
8/// # Example
9///
10/// ```rust
11/// use grorm::{DeriveModel, ColumnInfo, Model};
12///
13/// #[derive(Debug, DeriveModel)]
14/// #[table = "users"]
15/// struct User {
16///     id: i64,
17///     #[index]
18///     name: String,
19///     #[unique]
20///     email: String,
21///     age: i32,
22/// }
23///
24/// let schema = User::table_schema();
25/// assert_eq!(schema.len(), 4);
26/// assert!(schema[0].is_primary_key);
27/// assert!(schema[1].is_index);
28/// assert!(schema[2].is_unique);
29/// ```
30#[derive(Debug, Clone)]
31pub struct ColumnInfo {
32    /// Column name in the database
33    pub name: &'static str,
34    /// Rust type name (e.g. `"i64"`, `"String"`)
35    pub rust_type: &'static str,
36    /// Whether this column is part of the primary key
37    pub is_primary_key: bool,
38    /// Whether this column is auto-increment (integer primary key)
39    pub is_auto_increment: bool,
40    /// Whether a regular index should be created on this column (`#[index]`)
41    pub is_index: bool,
42    /// Whether a unique constraint should be created on this column (`#[unique]`)
43    pub is_unique: bool,
44    /// Name of the composite unique index group (`#[unique_index = "name"]`).
45    /// Columns with the same name form a composite unique index.
46    pub unique_index_name: Option<&'static str>,
47}
48
49/// Trait implemented by `#[derive(DeriveModel)]` for ORM model types.
50///
51/// Provides table metadata, column information, and row serialization/deserialization.
52///
53/// # Derivable
54///
55/// This trait is typically derived using `#[derive(DeriveModel)]`:
56///
57/// ```rust
58/// use grorm::DeriveModel;
59///
60/// #[derive(Debug, DeriveModel)]
61/// #[table = "users"]
62/// struct User {
63///     id: i64,
64///     name: String,
65///     email: String,
66///     age: i32,
67/// }
68/// ```
69///
70/// # Attributes
71///
72/// | Attribute | Scope | Description |
73/// |-----------|-------|-------------|
74/// | `#[table = "name"]` | struct | Override table name (default: lowercase struct name + "s") |
75/// | `#[primary_key = "col"]` | struct | Override primary key column (default: `id`) |
76/// | `#[index]` | field | Create a regular index on this column |
77/// | `#[unique]` | field | Create a unique constraint on this column |
78/// | `#[unique_index = "name"]` | field | Group columns into a composite unique index |
79pub trait Model: Sized {
80    /// Returns the database table name
81    fn table_name() -> &'static str;
82    /// Returns the primary key column name
83    fn primary_key() -> &'static str;
84    /// Returns all column names in order
85    fn columns() -> &'static [&'static str];
86    /// Returns full column metadata for DDL generation
87    fn table_schema() -> &'static [ColumnInfo];
88    /// Deserialize a database row into this model
89    fn from_row(row: &[Value]) -> Result<Self, String>;
90    /// Serialize this model into database values
91    fn to_values(&self) -> Vec<Value>;
92}