1use std::any::Any;
2mod tuple;
3
4#[cfg(any(feature = "rusqlite", feature = "libsql", feature = "turso"))]
5use crate::error::DrizzleError;
6use crate::{SQL, SQLSchemaType, ToSQL};
7
8pub trait SQLParam: Clone + std::fmt::Debug {}
13
14impl SQLParam for String {}
16impl SQLParam for &str {}
17impl SQLParam for i8 {}
18impl SQLParam for i16 {}
19impl SQLParam for i32 {}
20impl SQLParam for i64 {}
21impl SQLParam for isize {}
22impl SQLParam for u8 {}
23impl SQLParam for u16 {}
24impl SQLParam for u32 {}
25impl SQLParam for u64 {}
26impl SQLParam for usize {}
27impl SQLParam for f32 {}
28impl SQLParam for f64 {}
29impl SQLParam for bool {}
30impl<T: SQLParam> SQLParam for Option<T> {}
31impl<T: SQLParam> SQLParam for Vec<T> {}
32impl<T: SQLParam> SQLParam for &[T] {}
33impl<T: SQLParam> SQLParam for &T {}
34impl<const N: usize, T: SQLParam> SQLParam for [T; N] {}
35
36pub trait SQLSchema<'a, T, V: SQLParam + 'a>: ToSQL<'a, V> {
37 const NAME: &'a str;
38 const TYPE: T;
39 const SQL: SQL<'a, V>;
40
41 fn sql(&self) -> SQL<'a, V> {
43 Self::SQL
44 }
45}
46
47#[cfg(feature = "libsql")]
48use libsql::Connection;
49#[cfg(feature = "rusqlite")]
50use rusqlite::Connection;
51#[cfg(feature = "turso")]
52use turso::Connection;
53
54pub trait SQLColumnInfo: Any + Send + Sync {
55 fn is_not_null(&self) -> bool;
56 fn is_primary_key(&self) -> bool;
57 fn is_unique(&self) -> bool;
58 fn name(&self) -> &str;
59 fn r#type(&self) -> &str;
60 fn table(&self) -> &dyn SQLTableInfo;
61 fn has_default(&self) -> bool;
62}
63
64pub trait SQLSchemaImpl: Any + Send + Sync {
65 #[cfg(feature = "rusqlite")]
66 fn create(&self, conn: &Connection) -> Result<(), DrizzleError>;
67 #[cfg(any(feature = "turso", feature = "libsql"))]
68 fn create(&self, conn: &Connection) -> impl Future<Output = Result<(), DrizzleError>>;
69}
70
71pub trait AsColumnInfo: SQLColumnInfo {
72 fn as_column(&self) -> &dyn SQLColumnInfo;
73}
74
75impl<T: SQLColumnInfo> AsColumnInfo for T {
76 fn as_column(&self) -> &dyn SQLColumnInfo {
77 self
78 }
79}
80
81pub trait SQLColumn<'a, Value: SQLParam + 'a>:
82 SQLColumnInfo + Default + SQLSchema<'a, &'a str, Value>
83{
84 type Table: SQLTable<'a, Value>;
85 type Type: TryInto<Value>;
86
87 const PRIMARY_KEY: bool = false;
88 const NOT_NULL: bool = false;
89 const UNIQUE: bool = false;
90 const DEFAULT: Option<Self::Type> = None;
91
92 fn default_fn(&'a self) -> Option<impl Fn() -> Self::Type> {
93 None::<fn() -> Self::Type>
94 }
95}
96
97impl std::fmt::Debug for dyn SQLColumnInfo {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.debug_struct("SQLColumnInfo")
100 .field("name", &self.name())
101 .field("type", &self.r#type())
102 .field("not_null", &self.is_not_null())
103 .field("primary_key", &self.is_primary_key())
104 .field("unique", &self.is_unique())
105 .field("table", &self.table())
106 .field("has_default", &self.has_default())
107 .finish()
108 }
109}
110
111pub trait SQLModel<'a, V: SQLParam>: ToSQL<'a, V> {
112 fn columns(&self) -> Box<[&'static dyn SQLColumnInfo]>;
113 fn values(&self) -> crate::SQL<'a, V>;
114}
115
116pub trait SQLPartial<'a, Value: SQLParam> {
118 type Partial: ToSQL<'a, Value> + SQLModel<'a, Value> + Default + 'a;
121
122 fn partial() -> Self::Partial {
123 Default::default()
124 }
125}
126
127pub trait SQLTable<'a, Value: SQLParam + 'a>:
128 SQLSchema<'a, SQLSchemaType, Value> + SQLTableInfo + Default + Clone
129{
130 #[cfg(not(any(feature = "turso", feature = "libsql")))]
133 type Select: SQLModel<'a, Value> + SQLPartial<'a, Value> + Default + 'a;
134 #[cfg(any(feature = "turso", feature = "libsql"))]
135 type Select: SQLModel<'a, Value> + Default + 'a;
136
137 type Insert<T>: SQLModel<'a, Value> + Default;
140
141 type Update: SQLModel<'a, Value> + Default + 'a;
144}
145
146pub trait SQLTableInfo: Any + Send + Sync {
147 fn name(&self) -> &str;
148 fn r#type(&self) -> SQLSchemaType;
149 fn columns(&self) -> Box<[&'static dyn SQLColumnInfo]>;
150 fn without_rowid(&self) -> bool;
151 fn strict(&self) -> bool;
152}
153
154impl std::fmt::Debug for dyn SQLTableInfo {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 f.debug_struct("SQLTableInfo")
157 .field("name", &self.name())
158 .field("type", &self.r#type())
159 .field("columns", &self.columns())
160 .finish()
161 }
162}
163
164pub trait AsTableInfo: SQLTableInfo {
165 fn as_table(&self) -> &dyn SQLTableInfo;
166}
167
168impl<T: SQLTableInfo> AsTableInfo for T {
169 fn as_table(&self) -> &dyn SQLTableInfo {
170 self
171 }
172}
173
174pub trait SQLComparable<'a, V: SQLParam, Rhs> {}
176
177pub trait SQLAlias {
178 fn alias(&self) -> &'static str;
180}
181
182impl<'a, V, L, R> SQLComparable<'a, V, R> for L
219where
220 V: SQLParam + 'a,
221 L: ToSQL<'a, V>,
222 R: ToSQL<'a, V> + Into<V>,
223{
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn test_sql_param_implementations() {
232 fn assert_sql_param<T: SQLParam>(_: &T) {}
234
235 assert_sql_param(&String::new());
236 assert_sql_param(&"test");
237 assert_sql_param(&42i32);
238 assert_sql_param(&42i64);
239 assert_sql_param(&true);
240 assert_sql_param(&Some(42));
241 assert_sql_param(&None::<i32>);
242 assert_sql_param(&vec![1, 2, 3]);
243 }
244
245 #[test]
246 fn test_option_sql_param() {
247 fn accepts_sql_param<T: SQLParam>(_: T) {}
248
249 accepts_sql_param(Some(42i32));
250 accepts_sql_param(None::<String>);
251 accepts_sql_param(Some("test".to_string()));
252 }
253
254 #[test]
255 fn test_vec_sql_param() {
256 fn accepts_sql_param<T: SQLParam>(_: T) {}
257
258 accepts_sql_param(vec![1, 2, 3]);
259 accepts_sql_param(vec!["a", "b"]);
260 accepts_sql_param(Vec::<i32>::new());
261 }
262}
263
264pub trait IsInSchema<S> {}
266
267pub trait SQLIndex<'a, Value: SQLParam + 'a>: ToSQL<'a, Value> {
270 type Table: SQLTable<'a, Value>;
272
273 fn name(&self) -> &'static str;
275
276 fn is_unique(&self) -> bool {
278 false
279 }
280}