1use drizzle_core::{SQL, ToSQL, traits::SQLParam};
2
3#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
9pub enum Number {
10 Integer(i64),
12 Real(f64),
14}
15
16impl Default for Number {
17 fn default() -> Self {
18 Self::Integer(Default::default())
19 }
20}
21
22impl From<i64> for Number {
23 fn from(value: i64) -> Self {
24 Self::Integer(value)
25 }
26}
27
28impl From<f64> for Number {
29 fn from(value: f64) -> Self {
30 Self::Real(value)
31 }
32}
33
34#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
37pub enum JoinType {
38 #[default]
39 Join,
40 Inner,
41 Left,
42 Right,
43 Full,
44 Cross,
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
48pub struct Join {
49 pub natural: bool,
50 pub join_type: JoinType,
51 pub outer: bool, }
53
54impl Join {
55 pub fn new() -> Self {
56 Self::default()
57 }
58
59 pub fn natural(mut self) -> Self {
60 self.natural = true;
61 self
62 }
63
64 pub fn inner(mut self) -> Self {
65 self.join_type = JoinType::Inner;
66 self
67 }
68
69 pub fn left(mut self) -> Self {
70 self.join_type = JoinType::Left;
71 self
72 }
73
74 pub fn right(mut self) -> Self {
75 self.join_type = JoinType::Right;
76 self
77 }
78
79 pub fn full(mut self) -> Self {
80 self.join_type = JoinType::Full;
81 self
82 }
83
84 pub fn cross(mut self) -> Self {
85 self.join_type = JoinType::Cross;
86 self
87 }
88
89 pub fn outer(mut self) -> Self {
90 self.outer = true;
91 self
92 }
93}
94impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for Join {
95 fn to_sql(&self) -> SQL<'a, V> {
96 let mut parts = Vec::new();
97
98 if self.natural {
99 parts.push("NATURAL");
100 }
101
102 match self.join_type {
103 JoinType::Inner => parts.push("INNER"),
104 JoinType::Left => {
105 parts.push("LEFT");
106 if self.outer {
107 parts.push("OUTER");
108 }
109 }
110 JoinType::Right => {
111 parts.push("RIGHT");
112 if self.outer {
113 parts.push("OUTER");
114 }
115 }
116 JoinType::Full => {
117 parts.push("FULL");
118 if self.outer {
119 parts.push("OUTER");
120 }
121 }
122 JoinType::Cross => parts.push("CROSS"),
123 JoinType::Join => {}
124 }
125
126 parts.push("JOIN");
127 SQL::raw(parts.join(" "))
128 }
129}
130
131#[cfg(any(feature = "turso", feature = "libsql", feature = "rusqlite"))]
136#[cfg(test)]
137mod tests {
138 use drizzle_rs::prelude::*;
139 use std::borrow::Cow;
140
141 #[derive(SQLiteEnum, Default, Debug, Clone, PartialEq)]
144 enum Role {
145 #[default]
146 User,
147 Admin,
148 Moderator,
149 }
150
151 #[derive(SQLiteEnum, Default, Debug, Clone, PartialEq)]
153 enum Status {
154 Active = 1,
155 #[default]
156 Inactive = 0,
157 Banned = -1,
158 }
159
160 #[test]
161 fn test_into_sqlite_value_impls() {
162 assert_eq!(
163 SQLiteValue::from("hello"),
164 SQLiteValue::Text(Cow::Borrowed("hello"))
165 );
166 assert_eq!(
167 SQLiteValue::from(String::from("world")),
168 SQLiteValue::Text(Cow::Owned("world".to_string()))
169 );
170 assert_eq!(SQLiteValue::from(42i64), SQLiteValue::Integer(42));
171 assert_eq!(SQLiteValue::from(123i32), SQLiteValue::Integer(123));
172 assert_eq!(SQLiteValue::from(3.14f64), SQLiteValue::Real(3.14));
173 assert_eq!(SQLiteValue::from(true), SQLiteValue::Integer(1));
174 assert_eq!(SQLiteValue::from(false), SQLiteValue::Integer(0));
175 let blob_vec: Vec<u8> = vec![1, 2, 3];
176 assert_eq!(
177 SQLiteValue::from(blob_vec.clone()),
178 SQLiteValue::Blob(Cow::Owned(blob_vec.clone()))
179 );
180 let blob_slice: &[u8] = &[4, 5, 6];
181 assert_eq!(
182 SQLiteValue::from(blob_slice),
183 SQLiteValue::Blob(Cow::Borrowed(blob_slice))
184 );
185 assert_eq!(SQLiteValue::from(Option::<String>::None), SQLiteValue::Null);
186 assert_eq!(
187 SQLiteValue::from(Some("optional")),
188 SQLiteValue::Text(Cow::Borrowed("optional"))
189 );
190 }
191
192 #[test]
193 fn test_sqlite_enum_derives() {
194 let role = Role::Admin;
196 let status = Status::Active;
197
198 assert_eq!(format!("{}", role), "Admin");
200 assert_eq!(format!("{}", status), "Active");
201
202 assert_eq!("User".parse::<Role>().unwrap(), Role::User);
204 assert_eq!("Banned".parse::<Status>().unwrap(), Status::Banned);
205 }
206}