1use wae_types::Value;
6
7#[cfg(feature = "turso")]
8use crate::types::from_wae_value;
9#[cfg(feature = "turso")]
10use turso::Value as TursoValue;
11
12#[cfg(feature = "mysql")]
13use crate::types::from_wae_to_mysql;
14#[cfg(feature = "mysql")]
15use mysql_async::Value as MySqlValue;
16
17#[derive(Debug, Clone)]
19pub enum Condition {
20 Eq {
22 column: String,
24 value: Value,
26 },
27 Ne {
29 column: String,
31 value: Value,
33 },
34 Gt {
36 column: String,
38 value: Value,
40 },
41 Gte {
43 column: String,
45 value: Value,
47 },
48 Lt {
50 column: String,
52 value: Value,
54 },
55 Lte {
57 column: String,
59 value: Value,
61 },
62 Like {
64 column: String,
66 pattern: String,
68 },
69 In {
71 column: String,
73 values: Vec<Value>,
75 },
76 IsNull {
78 column: String,
80 },
81 IsNotNull {
83 column: String,
85 },
86 And(Vec<Condition>),
88 Or(Vec<Condition>),
90 Not(Box<Condition>),
92 Raw {
94 sql: String,
96 params: Vec<Value>,
98 },
99}
100
101impl Condition {
102 pub fn eq<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
104 Condition::Eq { column: column.into(), value: value.into() }
105 }
106
107 pub fn ne<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
109 Condition::Ne { column: column.into(), value: value.into() }
110 }
111
112 pub fn gt<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
114 Condition::Gt { column: column.into(), value: value.into() }
115 }
116
117 pub fn gte<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
119 Condition::Gte { column: column.into(), value: value.into() }
120 }
121
122 pub fn lt<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
124 Condition::Lt { column: column.into(), value: value.into() }
125 }
126
127 pub fn lte<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
129 Condition::Lte { column: column.into(), value: value.into() }
130 }
131
132 pub fn like<C: Into<String>, P: Into<String>>(column: C, pattern: P) -> Self {
134 Condition::Like { column: column.into(), pattern: pattern.into() }
135 }
136
137 pub fn in_<C: Into<String>, V: Into<Value>>(column: C, values: Vec<V>) -> Self {
139 Condition::In { column: column.into(), values: values.into_iter().map(|v| v.into()).collect() }
140 }
141
142 pub fn is_null<C: Into<String>>(column: C) -> Self {
144 Condition::IsNull { column: column.into() }
145 }
146
147 pub fn is_not_null<C: Into<String>>(column: C) -> Self {
149 Condition::IsNotNull { column: column.into() }
150 }
151
152 pub fn and(conditions: Vec<Condition>) -> Self {
154 Condition::And(conditions)
155 }
156
157 pub fn or(conditions: Vec<Condition>) -> Self {
159 Condition::Or(conditions)
160 }
161
162 pub fn negate(condition: Condition) -> Self {
164 Condition::Not(Box::new(condition))
165 }
166
167 pub fn raw<S: Into<String>>(sql: S, params: Vec<Value>) -> Self {
169 Condition::Raw { sql: sql.into(), params }
170 }
171
172 #[cfg(feature = "turso")]
173 pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
175 match self {
176 Condition::Eq { column, value } => (format!("{} = ?", column), vec![from_wae_value(value.clone())]),
177 Condition::Ne { column, value } => (format!("{} != ?", column), vec![from_wae_value(value.clone())]),
178 Condition::Gt { column, value } => (format!("{} > ?", column), vec![from_wae_value(value.clone())]),
179 Condition::Gte { column, value } => (format!("{} >= ?", column), vec![from_wae_value(value.clone())]),
180 Condition::Lt { column, value } => (format!("{} < ?", column), vec![from_wae_value(value.clone())]),
181 Condition::Lte { column, value } => (format!("{} <= ?", column), vec![from_wae_value(value.clone())]),
182 Condition::Like { column, pattern } => (format!("{} LIKE ?", column), vec![TursoValue::Text(pattern.clone())]),
183 Condition::In { column, values } => {
184 let placeholders: Vec<&str> = values.iter().map(|_| "?").collect();
185 let turso_values: Vec<TursoValue> = values.iter().map(|v| from_wae_value(v.clone())).collect();
186 (format!("{} IN ({})", column, placeholders.join(", ")), turso_values)
187 }
188 Condition::IsNull { column } => (format!("{} IS NULL", column), vec![]),
189 Condition::IsNotNull { column } => (format!("{} IS NOT NULL", column), vec![]),
190 Condition::And(conditions) => {
191 let mut sql_parts = Vec::new();
192 let mut all_params = Vec::new();
193 for cond in conditions {
194 let (sql, params) = cond.build_turso();
195 sql_parts.push(format!("({})", sql));
196 all_params.extend(params);
197 }
198 (sql_parts.join(" AND "), all_params)
199 }
200 Condition::Or(conditions) => {
201 let mut sql_parts = Vec::new();
202 let mut all_params = Vec::new();
203 for cond in conditions {
204 let (sql, params) = cond.build_turso();
205 sql_parts.push(format!("({})", sql));
206 all_params.extend(params);
207 }
208 (sql_parts.join(" OR "), all_params)
209 }
210 Condition::Not(cond) => {
211 let (sql, params) = cond.build_turso();
212 (format!("NOT ({})", sql), params)
213 }
214 Condition::Raw { sql, params } => {
215 let turso_params: Vec<TursoValue> = params.iter().map(|v| from_wae_value(v.clone())).collect();
216 (sql.clone(), turso_params)
217 }
218 }
219 }
220
221 #[cfg(feature = "mysql")]
222 pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
224 match self {
225 Condition::Eq { column, value } => (format!("{} = ?", column), vec![from_wae_to_mysql(value.clone())]),
226 Condition::Ne { column, value } => (format!("{} != ?", column), vec![from_wae_to_mysql(value.clone())]),
227 Condition::Gt { column, value } => (format!("{} > ?", column), vec![from_wae_to_mysql(value.clone())]),
228 Condition::Gte { column, value } => (format!("{} >= ?", column), vec![from_wae_to_mysql(value.clone())]),
229 Condition::Lt { column, value } => (format!("{} < ?", column), vec![from_wae_to_mysql(value.clone())]),
230 Condition::Lte { column, value } => (format!("{} <= ?", column), vec![from_wae_to_mysql(value.clone())]),
231 Condition::Like { column, pattern } => {
232 (format!("{} LIKE ?", column), vec![MySqlValue::Bytes(pattern.clone().into_bytes())])
233 }
234 Condition::In { column, values } => {
235 let placeholders: Vec<&str> = values.iter().map(|_| "?").collect();
236 let mysql_values: Vec<MySqlValue> = values.iter().map(|v| from_wae_to_mysql(v.clone())).collect();
237 (format!("{} IN ({})", column, placeholders.join(", ")), mysql_values)
238 }
239 Condition::IsNull { column } => (format!("{} IS NULL", column), vec![]),
240 Condition::IsNotNull { column } => (format!("{} IS NOT NULL", column), vec![]),
241 Condition::And(conditions) => {
242 let mut sql_parts = Vec::new();
243 let mut all_params = Vec::new();
244 for cond in conditions {
245 let (sql, params) = cond.build_mysql();
246 sql_parts.push(format!("({})", sql));
247 all_params.extend(params);
248 }
249 (sql_parts.join(" AND "), all_params)
250 }
251 Condition::Or(conditions) => {
252 let mut sql_parts = Vec::new();
253 let mut all_params = Vec::new();
254 for cond in conditions {
255 let (sql, params) = cond.build_mysql();
256 sql_parts.push(format!("({})", sql));
257 all_params.extend(params);
258 }
259 (sql_parts.join(" OR "), all_params)
260 }
261 Condition::Not(cond) => {
262 let (sql, params) = cond.build_mysql();
263 (format!("NOT ({})", sql), params)
264 }
265 Condition::Raw { sql, params } => {
266 let mysql_params: Vec<MySqlValue> = params.iter().map(|v| from_wae_to_mysql(v.clone())).collect();
267 (sql.clone(), mysql_params)
268 }
269 }
270 }
271}
272
273#[derive(Debug, Clone, Copy)]
275pub enum Order {
276 Asc,
278 Desc,
280}