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;
9pub struct NonEmpty;
11
12pub trait Tag: 'static {
19 const NAME: &'static str;
21}
22
23#[macro_export]
42macro_rules! tag {
43 ($vis:vis $name:ident, $sql_name:expr) => {
44 $vis struct $name;
45 impl $crate::Tag for $name {
46 const NAME: &'static str = $sql_name;
47 }
48 };
49}
50
51#[derive(Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
55pub struct Tagged<T, Name: Tag> {
56 inner: T,
57 _tag: PhantomData<fn() -> Name>,
58}
59
60impl<T: Copy, Name: Tag> Copy for Tagged<T, Name> {}
61
62impl<T: Copy, Name: Tag> Clone for Tagged<T, Name> {
63 fn clone(&self) -> Self {
64 *self
65 }
66}
67
68impl<T, Name: Tag> Tagged<T, Name> {
69 pub const fn new(inner: T) -> Self {
71 Self {
72 inner,
73 _tag: PhantomData,
74 }
75 }
76
77 pub fn into_inner(self) -> T {
79 self.inner
80 }
81}
82
83impl<T, Name: Tag> Deref for Tagged<T, Name> {
84 type Target = T;
85
86 fn deref(&self) -> &Self::Target {
87 &self.inner
88 }
89}
90
91#[diagnostic::on_unimplemented(
94 message = "`{Self}` is not a SQL model (Select, Insert, or Update)",
95 label = "this type cannot be used as a query model"
96)]
97pub trait SQLModel<'a, V: SQLParam>: ToSQL<'a, V> {
98 fn columns(&self) -> Cow<'static, [ColumnRef]>;
103 fn values(&self) -> SQL<'a, V>;
106}
107
108#[diagnostic::on_unimplemented(
110 message = "`{Self}` does not support partial field selection",
111 label = "this table's Select model does not implement SQLPartial"
112)]
113pub trait SQLPartial<'a, Value: SQLParam> {
114 type Partial: SQLModel<'a, Value> + Default + 'a;
116
117 #[must_use]
119 fn partial() -> Self::Partial {
120 Default::default()
121 }
122}
123
124#[diagnostic::on_unimplemented(
129 message = "`{Self}` is not a SQL table for this dialect",
130 label = "ensure this type was derived with #[SQLiteTable], #[PostgresTable], or #[MySQLTable]"
131)]
132pub trait SQLTable<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
133 SQLSchema<'a, Type, Value> + SQLTableInfo + Default + Clone + Copy
134{
135 type Select: SQLModel<'a, Value> + SQLPartial<'a, Value> + 'a;
137 type ForeignKeys;
139 type PrimaryKey;
141 type Constraints;
143
144 type Insert<T>: SQLModel<'a, Value> + Default;
147
148 type Update: SQLModel<'a, Value> + 'a;
150
151 type Aliased<Name: Tag + 'static>: SQLTable<'a, Type, Value>;
153
154 fn alias<Name: Tag + 'static>() -> Self::Aliased<Name>;
156}
157
158pub trait DrizzleTable: Send + Sync + 'static {
163 const NAME: &'static str;
165
166 const QUALIFIED_NAME: &'static str;
168
169 const SCHEMA: Option<&'static str> = None;
171
172 const DEPENDENCY_NAMES: &'static [&'static str] = &[];
174
175 const TABLE_REF: TableRef;
177}
178
179impl<T: DrizzleTable> SQLTableInfo for T {
181 fn name(&self) -> &'static str {
182 T::NAME
183 }
184
185 fn schema(&self) -> Option<&'static str> {
186 T::SCHEMA
187 }
188
189 fn qualified_name(&self) -> Cow<'static, str> {
190 Cow::Borrowed(T::QUALIFIED_NAME)
191 }
192}
193
194impl<'a, Type, Value, T> SQLTable<'a, Type, Value> for &T
195where
196 Type: SQLSchemaType,
197 Value: SQLParam + 'a,
198 T: SQLTable<'a, Type, Value>,
199 for<'r> &'r T: SQLSchema<'a, Type, Value> + SQLTableInfo + Default + Clone,
200{
201 type Select = T::Select;
202 type ForeignKeys = T::ForeignKeys;
203 type PrimaryKey = T::PrimaryKey;
204 type Constraints = T::Constraints;
205 type Insert<I> = T::Insert<I>;
206 type Update = T::Update;
207 type Aliased<Name: Tag + 'static> = T::Aliased<Name>;
208
209 fn alias<Name: Tag + 'static>() -> Self::Aliased<Name> {
210 T::alias::<Name>()
211 }
212}
213
214#[diagnostic::on_unimplemented(
216 message = "`{Self}` does not implement SQLTableInfo",
217 label = "ensure this type was derived with #[SQLiteTable], #[PostgresTable], or #[MySQLTable]"
218)]
219pub trait SQLTableInfo: Send + Sync {
220 fn name(&self) -> &'static str;
222
223 fn schema(&self) -> Option<&'static str> {
225 None
226 }
227
228 fn qualified_name(&self) -> Cow<'static, str> {
230 self.schema().map_or_else(
231 || Cow::Borrowed(self.name()),
232 |schema| Cow::Owned(format!("{schema}.{}", self.name())),
233 )
234 }
235}
236
237impl core::fmt::Debug for dyn SQLTableInfo {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 f.debug_struct("SQLTableInfo")
240 .field("name", &self.name())
241 .field("schema", &self.schema())
242 .finish()
243 }
244}