1use drizzle_core::{SQL, SQLIndexInfo, SQLSchemaType, ToSQL, traits::SQLParam};
2
3use crate::traits::SQLiteTableInfo;
4
5#[derive(Debug, Clone)]
7pub enum SQLiteSchemaType {
8 Table(&'static dyn SQLiteTableInfo),
10 View,
12 Index(&'static dyn SQLIndexInfo),
14 Trigger,
16}
17
18impl SQLSchemaType for SQLiteSchemaType {}
19
20#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
26pub enum Number {
27 Integer(i64),
29 Real(f64),
31}
32
33impl Default for Number {
34 fn default() -> Self {
35 Self::Integer(Default::default())
36 }
37}
38
39impl From<i64> for Number {
40 fn from(value: i64) -> Self {
41 Self::Integer(value)
42 }
43}
44
45impl From<f64> for Number {
46 fn from(value: f64) -> Self {
47 Self::Real(value)
48 }
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
54pub enum JoinType {
55 #[default]
56 Join,
57 Inner,
58 Left,
59 Right,
60 Full,
61 Cross,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
65pub struct Join {
66 pub natural: bool,
67 pub join_type: JoinType,
68 pub outer: bool, }
70
71impl Join {
72 pub fn new() -> Self {
73 Self::default()
74 }
75
76 pub fn natural(mut self) -> Self {
77 self.natural = true;
78 self
79 }
80
81 pub fn inner(mut self) -> Self {
82 self.join_type = JoinType::Inner;
83 self
84 }
85
86 pub fn left(mut self) -> Self {
87 self.join_type = JoinType::Left;
88 self
89 }
90
91 pub fn right(mut self) -> Self {
92 self.join_type = JoinType::Right;
93 self
94 }
95
96 pub fn full(mut self) -> Self {
97 self.join_type = JoinType::Full;
98 self
99 }
100
101 pub fn cross(mut self) -> Self {
102 self.join_type = JoinType::Cross;
103 self
104 }
105
106 pub fn outer(mut self) -> Self {
107 self.outer = true;
108 self
109 }
110}
111impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for Join {
112 fn to_sql(&self) -> SQL<'a, V> {
113 let mut parts = Vec::new();
114
115 if self.natural {
116 parts.push("NATURAL");
117 }
118
119 match self.join_type {
120 JoinType::Inner => parts.push("INNER"),
121 JoinType::Left => {
122 parts.push("LEFT");
123 if self.outer {
124 parts.push("OUTER");
125 }
126 }
127 JoinType::Right => {
128 parts.push("RIGHT");
129 if self.outer {
130 parts.push("OUTER");
131 }
132 }
133 JoinType::Full => {
134 parts.push("FULL");
135 if self.outer {
136 parts.push("OUTER");
137 }
138 }
139 JoinType::Cross => parts.push("CROSS"),
140 JoinType::Join => {}
141 }
142
143 parts.push("JOIN");
144 SQL::raw(parts.join(" "))
145 }
146}
147
148#[cfg(any(feature = "turso", feature = "libsql", feature = "rusqlite"))]
153#[cfg(test)]
154mod tests {
155 use crate::common::{Join, JoinType, Number};
156 use crate::*;
157 use std::borrow::Cow;
158
159 #[test]
160 fn test_into_sqlite_value_impls() {
161 assert_eq!(
162 SQLiteValue::from("hello"),
163 SQLiteValue::Text(Cow::Borrowed("hello"))
164 );
165 assert_eq!(
166 SQLiteValue::from(String::from("world")),
167 SQLiteValue::Text(Cow::Owned("world".to_string()))
168 );
169 assert_eq!(SQLiteValue::from(42i64), SQLiteValue::Integer(42));
170 assert_eq!(SQLiteValue::from(123i32), SQLiteValue::Integer(123));
171 assert_eq!(SQLiteValue::from(3.14f64), SQLiteValue::Real(3.14));
172 assert_eq!(SQLiteValue::from(true), SQLiteValue::Integer(1));
173 assert_eq!(SQLiteValue::from(false), SQLiteValue::Integer(0));
174 let blob_vec: Vec<u8> = vec![1, 2, 3];
175 assert_eq!(
176 SQLiteValue::from(blob_vec.clone()),
177 SQLiteValue::Blob(Cow::Owned(blob_vec.clone()))
178 );
179 let blob_slice: &[u8] = &[4, 5, 6];
180 assert_eq!(
181 SQLiteValue::from(blob_slice),
182 SQLiteValue::Blob(Cow::Borrowed(blob_slice))
183 );
184 assert_eq!(SQLiteValue::from(Option::<String>::None), SQLiteValue::Null);
185 assert_eq!(
186 SQLiteValue::from(Some("optional")),
187 SQLiteValue::Text(Cow::Borrowed("optional"))
188 );
189 }
190
191 #[test]
192 fn test_number_enum() {
193 let int_num = Number::Integer(42);
194 let real_num = Number::Real(3.14);
195
196 assert_eq!(int_num, Number::from(42i64));
197 assert_eq!(real_num, Number::from(3.14f64));
198 assert_eq!(Number::default(), Number::Integer(0));
199 }
200
201 #[test]
202 fn test_join_type_and_join() {
203 let join = Join::new().inner().natural();
204 assert_eq!(join.join_type, JoinType::Inner);
205 assert_eq!(join.natural, true);
206 assert_eq!(join.outer, false);
207
208 let outer_join = Join::new().left().outer();
209 assert_eq!(outer_join.join_type, JoinType::Left);
210 assert_eq!(outer_join.outer, true);
211
212 let cross_join = Join::new().cross();
213 assert_eq!(cross_join.join_type, JoinType::Cross);
214 }
215
216 #[test]
217 fn test_join_to_sql() {
218 use drizzle_core::{SQL, ToSQL};
219
220 let inner_join = Join::new().inner();
221 let sql: SQL<SQLiteValue> = inner_join.to_sql();
222 assert_eq!(sql.sql(), "INNER JOIN");
223
224 let natural_left_outer = Join::new().natural().left().outer();
225 let sql: SQL<SQLiteValue> = natural_left_outer.to_sql();
226 assert_eq!(sql.sql(), "NATURAL LEFT OUTER JOIN");
227
228 let cross_join = Join::new().cross();
229 let sql: SQL<SQLiteValue> = cross_join.to_sql();
230 assert_eq!(sql.sql(), "CROSS JOIN");
231 }
232}