drizzle_core/traits/
table.rs

1use crate::prelude::*;
2use crate::{SQL, SQLColumnInfo, SQLParam, SQLSchema, SQLSchemaType, ToSQL};
3use core::any::Any;
4
5pub trait SQLModel<'a, V: SQLParam>: ToSQL<'a, V> {
6    /// Columns referenced by this model.
7    /// Static models can return a borrowed slice; dynamic models can allocate.
8    fn columns(&self) -> Cow<'static, [&'static dyn SQLColumnInfo]>;
9    fn values(&self) -> SQL<'a, V>;
10}
11
12/// Trait for models that support partial selection of fields
13pub trait SQLPartial<'a, Value: SQLParam> {
14    /// The type representing a partial model where all fields are optional
15    /// for selective querying
16    type Partial: SQLModel<'a, Value> + Default + 'a;
17
18    fn partial() -> Self::Partial {
19        Default::default()
20    }
21}
22
23pub trait SQLTable<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
24    SQLSchema<'a, Type, Value> + SQLTableInfo + Default + Clone
25{
26    type Select: SQLModel<'a, Value> + SQLPartial<'a, Value> + Default + 'a;
27
28    /// The type representing a model for INSERT operations on this table.
29    /// Uses PhantomData with tuple markers to track which fields are set
30    type Insert<T>: SQLModel<'a, Value> + Default;
31
32    /// The type representing a model for UPDATE operations on this table.
33    /// This would be generated by the table macro.
34    type Update: SQLModel<'a, Value> + Default + 'a;
35
36    /// The aliased version of this table for self-joins and CTEs.
37    /// For a table `Users`, this would be `AliasedUsers`.
38    type Aliased: SQLTable<'a, Type, Value>;
39
40    /// Creates an aliased version of this table with the given name.
41    /// Used for self-joins and CTEs.
42    fn alias(name: &'static str) -> Self::Aliased;
43}
44
45pub trait SQLTableInfo: Any + Send + Sync {
46    fn name(&self) -> &str;
47    fn columns(&self) -> &'static [&'static dyn SQLColumnInfo];
48    fn dependencies(&self) -> &'static [&'static dyn SQLTableInfo];
49
50    /// Lookup a column by name.
51    fn column_named(&self, name: &str) -> Option<&'static dyn SQLColumnInfo> {
52        self.columns()
53            .iter()
54            .copied()
55            .find(|col| col.name() == name)
56    }
57}
58
59// Blanket implementation for static references
60impl<T: SQLTableInfo> SQLTableInfo for &'static T {
61    fn name(&self) -> &str {
62        (*self).name()
63    }
64
65    fn columns(&self) -> &'static [&'static dyn SQLColumnInfo] {
66        (*self).columns()
67    }
68
69    fn dependencies(&self) -> &'static [&'static dyn SQLTableInfo] {
70        (*self).dependencies()
71    }
72}
73
74impl core::fmt::Debug for dyn SQLTableInfo {
75    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76        f.debug_struct("SQLTableInfo")
77            .field("name", &self.name())
78            .field("columns", &self.columns())
79            .finish()
80    }
81}
82
83pub trait AsTableInfo: Sized + SQLTableInfo {
84    fn as_table(&self) -> &dyn SQLTableInfo {
85        self
86    }
87}