drizzle_core/traits/
table.rs1use crate::prelude::*;
2use crate::{ColumnRef, SQL, SQLParam, SQLSchema, SQLSchemaType, TableRef, ToSQL};
3use core::marker::PhantomData;
4use core::ops::Deref;
5
6pub struct Empty;
8pub struct NonEmpty;
10
11pub trait Tag {
13 const NAME: &'static str;
14}
15
16#[macro_export]
33macro_rules! tag {
34 ($vis:vis $name:ident, $sql_name:expr) => {
35 $vis struct $name;
36 impl $crate::Tag for $name {
37 const NAME: &'static str = $sql_name;
38 }
39 };
40}
41
42#[derive(Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
44pub struct Tagged<T, Name: Tag> {
45 inner: T,
46 _tag: PhantomData<fn() -> Name>,
47}
48
49impl<T: Copy, Name: Tag> Copy for Tagged<T, Name> {}
50
51impl<T: Copy, Name: Tag> Clone for Tagged<T, Name> {
52 fn clone(&self) -> Self {
53 *self
54 }
55}
56
57impl<T, Name: Tag> Tagged<T, Name> {
58 pub const fn new(inner: T) -> Self {
59 Self {
60 inner,
61 _tag: PhantomData,
62 }
63 }
64
65 pub fn into_inner(self) -> T {
66 self.inner
67 }
68}
69
70impl<T, Name: Tag> Deref for Tagged<T, Name> {
71 type Target = T;
72
73 fn deref(&self) -> &Self::Target {
74 &self.inner
75 }
76}
77
78#[diagnostic::on_unimplemented(
79 message = "`{Self}` is not a SQL model (Select, Insert, or Update)",
80 label = "this type cannot be used as a query model"
81)]
82pub trait SQLModel<'a, V: SQLParam>: ToSQL<'a, V> {
83 fn columns(&self) -> Cow<'static, [ColumnRef]>;
86 fn values(&self) -> SQL<'a, V>;
87}
88
89#[diagnostic::on_unimplemented(
91 message = "`{Self}` does not support partial field selection",
92 label = "this table's Select model does not implement SQLPartial"
93)]
94pub trait SQLPartial<'a, Value: SQLParam> {
95 type Partial: SQLModel<'a, Value> + Default + 'a;
98
99 #[must_use]
100 fn partial() -> Self::Partial {
101 Default::default()
102 }
103}
104
105#[diagnostic::on_unimplemented(
106 message = "`{Self}` is not a SQL table for this dialect",
107 label = "ensure this type was derived with #[SQLiteTable] or #[PostgresTable]"
108)]
109pub trait SQLTable<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
110 SQLSchema<'a, Type, Value> + SQLTableInfo + Default + Clone + Copy
111{
112 type Select: SQLModel<'a, Value> + SQLPartial<'a, Value> + 'a;
113 type ForeignKeys;
114 type PrimaryKey;
115 type Constraints;
116
117 type Insert<T>: SQLModel<'a, Value> + Default;
120
121 type Update: SQLModel<'a, Value> + 'a;
124
125 type Aliased<Name: Tag + 'static>: SQLTable<'a, Type, Value>;
127
128 fn alias<Name: Tag + 'static>() -> Self::Aliased<Name>;
130}
131
132pub trait DrizzleTable: Send + Sync + 'static {
138 const NAME: &'static str;
140
141 const QUALIFIED_NAME: &'static str;
143
144 const SCHEMA: Option<&'static str> = None;
146
147 const DEPENDENCY_NAMES: &'static [&'static str] = &[];
149
150 const TABLE_REF: TableRef;
152}
153
154impl<T: DrizzleTable> SQLTableInfo for T {
156 fn name(&self) -> &'static str {
157 T::NAME
158 }
159
160 fn schema(&self) -> Option<&'static str> {
161 T::SCHEMA
162 }
163
164 fn qualified_name(&self) -> Cow<'static, str> {
165 Cow::Borrowed(T::QUALIFIED_NAME)
166 }
167}
168
169impl<'a, Type, Value, T> SQLTable<'a, Type, Value> for &T
170where
171 Type: SQLSchemaType,
172 Value: SQLParam + 'a,
173 T: SQLTable<'a, Type, Value>,
174 for<'r> &'r T: SQLSchema<'a, Type, Value> + SQLTableInfo + Default + Clone,
175{
176 type Select = T::Select;
177 type ForeignKeys = T::ForeignKeys;
178 type PrimaryKey = T::PrimaryKey;
179 type Constraints = T::Constraints;
180 type Insert<I> = T::Insert<I>;
181 type Update = T::Update;
182 type Aliased<Name: Tag + 'static> = T::Aliased<Name>;
183
184 fn alias<Name: Tag + 'static>() -> Self::Aliased<Name> {
185 T::alias::<Name>()
186 }
187}
188
189#[diagnostic::on_unimplemented(
190 message = "`{Self}` does not implement SQLTableInfo",
191 label = "ensure this type was derived with #[SQLiteTable] or #[PostgresTable]"
192)]
193pub trait SQLTableInfo: Send + Sync {
194 fn name(&self) -> &'static str;
196
197 fn schema(&self) -> Option<&'static str> {
199 None
200 }
201
202 fn qualified_name(&self) -> Cow<'static, str> {
204 self.schema().map_or_else(
205 || Cow::Borrowed(self.name()),
206 |schema| Cow::Owned(format!("{schema}.{}", self.name())),
207 )
208 }
209}
210
211impl core::fmt::Debug for dyn SQLTableInfo {
212 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
213 f.debug_struct("SQLTableInfo")
214 .field("name", &self.name())
215 .field("schema", &self.schema())
216 .finish()
217 }
218}