Skip to main content

wae_database/orm/
condition.rs

1//! 查询条件模块
2//!
3//! 提供查询条件构建和排序方式定义
4
5use 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#[cfg(feature = "postgres")]
18use crate::connection::postgres::{PostgresParam, value_to_postgres_param};
19
20/// 查询条件
21#[derive(Debug, Clone)]
22pub enum Condition {
23    /// 相等条件
24    Eq {
25        /// 列名
26        column: String,
27        /// 值
28        value: Value,
29    },
30    /// 不相等条件
31    Ne {
32        /// 列名
33        column: String,
34        /// 值
35        value: Value,
36    },
37    /// 大于条件
38    Gt {
39        /// 列名
40        column: String,
41        /// 值
42        value: Value,
43    },
44    /// 大于等于条件
45    Gte {
46        /// 列名
47        column: String,
48        /// 值
49        value: Value,
50    },
51    /// 小于条件
52    Lt {
53        /// 列名
54        column: String,
55        /// 值
56        value: Value,
57    },
58    /// 小于等于条件
59    Lte {
60        /// 列名
61        column: String,
62        /// 值
63        value: Value,
64    },
65    /// LIKE 条件
66    Like {
67        /// 列名
68        column: String,
69        /// 模式
70        pattern: String,
71    },
72    /// IN 条件
73    In {
74        /// 列名
75        column: String,
76        /// 值列表
77        values: Vec<Value>,
78    },
79    /// IS NULL 条件
80    IsNull {
81        /// 列名
82        column: String,
83    },
84    /// IS NOT NULL 条件
85    IsNotNull {
86        /// 列名
87        column: String,
88    },
89    /// AND 组合
90    And(Vec<Condition>),
91    /// OR 组合
92    Or(Vec<Condition>),
93    /// NOT 条件
94    Not(Box<Condition>),
95    /// 原始 SQL 条件
96    Raw {
97        /// SQL 片段
98        sql: String,
99        /// 参数
100        params: Vec<Value>,
101    },
102}
103
104impl Condition {
105    /// 创建相等条件
106    pub fn eq<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
107        Condition::Eq { column: column.into(), value: value.into() }
108    }
109
110    /// 创建不相等条件
111    pub fn ne<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
112        Condition::Ne { column: column.into(), value: value.into() }
113    }
114
115    /// 创建大于条件
116    pub fn gt<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
117        Condition::Gt { column: column.into(), value: value.into() }
118    }
119
120    /// 创建大于等于条件
121    pub fn gte<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
122        Condition::Gte { column: column.into(), value: value.into() }
123    }
124
125    /// 创建小于条件
126    pub fn lt<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
127        Condition::Lt { column: column.into(), value: value.into() }
128    }
129
130    /// 创建小于等于条件
131    pub fn lte<C: Into<String>, V: Into<Value>>(column: C, value: V) -> Self {
132        Condition::Lte { column: column.into(), value: value.into() }
133    }
134
135    /// 创建 LIKE 条件
136    pub fn like<C: Into<String>, P: Into<String>>(column: C, pattern: P) -> Self {
137        Condition::Like { column: column.into(), pattern: pattern.into() }
138    }
139
140    /// 创建 IN 条件
141    pub fn in_<C: Into<String>, V: Into<Value>>(column: C, values: Vec<V>) -> Self {
142        Condition::In { column: column.into(), values: values.into_iter().map(|v| v.into()).collect() }
143    }
144
145    /// 创建 IS NULL 条件
146    pub fn is_null<C: Into<String>>(column: C) -> Self {
147        Condition::IsNull { column: column.into() }
148    }
149
150    /// 创建 IS NOT NULL 条件
151    pub fn is_not_null<C: Into<String>>(column: C) -> Self {
152        Condition::IsNotNull { column: column.into() }
153    }
154
155    /// 创建 AND 组合
156    pub fn and(conditions: Vec<Condition>) -> Self {
157        Condition::And(conditions)
158    }
159
160    /// 创建 OR 组合
161    pub fn or(conditions: Vec<Condition>) -> Self {
162        Condition::Or(conditions)
163    }
164
165    /// 创建 NOT 条件
166    pub fn negate(condition: Condition) -> Self {
167        Condition::Not(Box::new(condition))
168    }
169
170    /// 创建原始 SQL 条件
171    pub fn raw<S: Into<String>>(sql: S, params: Vec<Value>) -> Self {
172        Condition::Raw { sql: sql.into(), params }
173    }
174
175    #[cfg(feature = "turso")]
176    /// 构建 SQL 和参数 (内部使用 turso::Value)
177    pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
178        match self {
179            Condition::Eq { column, value } => (format!("{} = ?", column), vec![from_wae_value(value.clone())]),
180            Condition::Ne { column, value } => (format!("{} != ?", column), vec![from_wae_value(value.clone())]),
181            Condition::Gt { column, value } => (format!("{} > ?", column), vec![from_wae_value(value.clone())]),
182            Condition::Gte { column, value } => (format!("{} >= ?", column), vec![from_wae_value(value.clone())]),
183            Condition::Lt { column, value } => (format!("{} < ?", column), vec![from_wae_value(value.clone())]),
184            Condition::Lte { column, value } => (format!("{} <= ?", column), vec![from_wae_value(value.clone())]),
185            Condition::Like { column, pattern } => (format!("{} LIKE ?", column), vec![TursoValue::Text(pattern.clone())]),
186            Condition::In { column, values } => {
187                let placeholders: Vec<&str> = values.iter().map(|_| "?").collect();
188                let turso_values: Vec<TursoValue> = values.iter().map(|v| from_wae_value(v.clone())).collect();
189                (format!("{} IN ({})", column, placeholders.join(", ")), turso_values)
190            }
191            Condition::IsNull { column } => (format!("{} IS NULL", column), vec![]),
192            Condition::IsNotNull { column } => (format!("{} IS NOT NULL", column), vec![]),
193            Condition::And(conditions) => {
194                let mut sql_parts = Vec::new();
195                let mut all_params = Vec::new();
196                for cond in conditions {
197                    let (sql, params) = cond.build_turso();
198                    sql_parts.push(format!("({})", sql));
199                    all_params.extend(params);
200                }
201                (sql_parts.join(" AND "), all_params)
202            }
203            Condition::Or(conditions) => {
204                let mut sql_parts = Vec::new();
205                let mut all_params = Vec::new();
206                for cond in conditions {
207                    let (sql, params) = cond.build_turso();
208                    sql_parts.push(format!("({})", sql));
209                    all_params.extend(params);
210                }
211                (sql_parts.join(" OR "), all_params)
212            }
213            Condition::Not(cond) => {
214                let (sql, params) = cond.build_turso();
215                (format!("NOT ({})", sql), params)
216            }
217            Condition::Raw { sql, params } => {
218                let turso_params: Vec<TursoValue> = params.iter().map(|v| from_wae_value(v.clone())).collect();
219                (sql.clone(), turso_params)
220            }
221        }
222    }
223
224    #[cfg(feature = "mysql")]
225    /// 构建 SQL 和参数 (内部使用 MySQL Value)
226    pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
227        match self {
228            Condition::Eq { column, value } => (format!("{} = ?", column), vec![from_wae_to_mysql(value.clone())]),
229            Condition::Ne { column, value } => (format!("{} != ?", column), vec![from_wae_to_mysql(value.clone())]),
230            Condition::Gt { column, value } => (format!("{} > ?", column), vec![from_wae_to_mysql(value.clone())]),
231            Condition::Gte { column, value } => (format!("{} >= ?", column), vec![from_wae_to_mysql(value.clone())]),
232            Condition::Lt { column, value } => (format!("{} < ?", column), vec![from_wae_to_mysql(value.clone())]),
233            Condition::Lte { column, value } => (format!("{} <= ?", column), vec![from_wae_to_mysql(value.clone())]),
234            Condition::Like { column, pattern } => {
235                (format!("{} LIKE ?", column), vec![MySqlValue::Bytes(pattern.clone().into_bytes())])
236            }
237            Condition::In { column, values } => {
238                let placeholders: Vec<&str> = values.iter().map(|_| "?").collect();
239                let mysql_values: Vec<MySqlValue> = values.iter().map(|v| from_wae_to_mysql(v.clone())).collect();
240                (format!("{} IN ({})", column, placeholders.join(", ")), mysql_values)
241            }
242            Condition::IsNull { column } => (format!("{} IS NULL", column), vec![]),
243            Condition::IsNotNull { column } => (format!("{} IS NOT NULL", column), vec![]),
244            Condition::And(conditions) => {
245                let mut sql_parts = Vec::new();
246                let mut all_params = Vec::new();
247                for cond in conditions {
248                    let (sql, params) = cond.build_mysql();
249                    sql_parts.push(format!("({})", sql));
250                    all_params.extend(params);
251                }
252                (sql_parts.join(" AND "), all_params)
253            }
254            Condition::Or(conditions) => {
255                let mut sql_parts = Vec::new();
256                let mut all_params = Vec::new();
257                for cond in conditions {
258                    let (sql, params) = cond.build_mysql();
259                    sql_parts.push(format!("({})", sql));
260                    all_params.extend(params);
261                }
262                (sql_parts.join(" OR "), all_params)
263            }
264            Condition::Not(cond) => {
265                let (sql, params) = cond.build_mysql();
266                (format!("NOT ({})", sql), params)
267            }
268            Condition::Raw { sql, params } => {
269                let mysql_params: Vec<MySqlValue> = params.iter().map(|v| from_wae_to_mysql(v.clone())).collect();
270                (sql.clone(), mysql_params)
271            }
272        }
273    }
274
275    #[cfg(feature = "postgres")]
276    /// 构建 SQL 和参数 (内部使用 PostgresParam)
277    pub(crate) fn build_postgres(&self) -> (String, Vec<PostgresParam>) {
278        let param_index = 1;
279        match self {
280            Condition::Eq { column, value } => {
281                let sql = format!("{} = ${}", column, param_index);
282                let params = vec![value_to_postgres_param(value.clone())];
283                (sql, params)
284            }
285            Condition::Ne { column, value } => {
286                let sql = format!("{} != ${}", column, param_index);
287                let params = vec![value_to_postgres_param(value.clone())];
288                (sql, params)
289            }
290            Condition::Gt { column, value } => {
291                let sql = format!("{} > ${}", column, param_index);
292                let params = vec![value_to_postgres_param(value.clone())];
293                (sql, params)
294            }
295            Condition::Gte { column, value } => {
296                let sql = format!("{} >= ${}", column, param_index);
297                let params = vec![value_to_postgres_param(value.clone())];
298                (sql, params)
299            }
300            Condition::Lt { column, value } => {
301                let sql = format!("{} < ${}", column, param_index);
302                let params = vec![value_to_postgres_param(value.clone())];
303                (sql, params)
304            }
305            Condition::Lte { column, value } => {
306                let sql = format!("{} <= ${}", column, param_index);
307                let params = vec![value_to_postgres_param(value.clone())];
308                (sql, params)
309            }
310            Condition::Like { column, pattern } => {
311                let sql = format!("{} LIKE ${}", column, param_index);
312                let params = vec![value_to_postgres_param(Value::String(pattern.clone()))];
313                (sql, params)
314            }
315            Condition::In { column, values } => {
316                let placeholders: Vec<String> = (0..values.len()).map(|i| format!("${}", param_index + i)).collect();
317                let postgres_params: Vec<PostgresParam> = values.iter().map(|v| value_to_postgres_param(v.clone())).collect();
318                (format!("{} IN ({})", column, placeholders.join(", ")), postgres_params)
319            }
320            Condition::IsNull { column } => (format!("{} IS NULL", column), vec![]),
321            Condition::IsNotNull { column } => (format!("{} IS NOT NULL", column), vec![]),
322            Condition::And(conditions) => {
323                let mut sql_parts = Vec::new();
324                let mut all_params = Vec::new();
325                let mut current_index = 1;
326                for cond in conditions {
327                    let (sql, params) = cond.build_postgres();
328                    let sql = replace_placeholders(&sql, current_index);
329                    sql_parts.push(format!("({})", sql));
330                    let params_len = params.len();
331                    all_params.extend(params);
332                    current_index += params_len;
333                }
334                (sql_parts.join(" AND "), all_params)
335            }
336            Condition::Or(conditions) => {
337                let mut sql_parts = Vec::new();
338                let mut all_params = Vec::new();
339                let mut current_index = 1;
340                for cond in conditions {
341                    let (sql, params) = cond.build_postgres();
342                    let sql = replace_placeholders(&sql, current_index);
343                    sql_parts.push(format!("({})", sql));
344                    let params_len = params.len();
345                    all_params.extend(params);
346                    current_index += params_len;
347                }
348                (sql_parts.join(" OR "), all_params)
349            }
350            Condition::Not(cond) => {
351                let (sql, params) = cond.build_postgres();
352                (format!("NOT ({})", sql), params)
353            }
354            Condition::Raw { sql, params } => {
355                let postgres_params: Vec<PostgresParam> = params.iter().map(|v| value_to_postgres_param(v.clone())).collect();
356                (sql.clone(), postgres_params)
357            }
358        }
359    }
360}
361
362#[cfg(feature = "postgres")]
363fn replace_placeholders(sql: &str, start_index: usize) -> String {
364    let mut result = String::new();
365    let mut chars = sql.chars().peekable();
366    while let Some(c) = chars.next() {
367        if c == '$' {
368            let mut num_str = String::new();
369            while let Some(&next_c) = chars.peek() {
370                if next_c.is_ascii_digit() {
371                    num_str.push(next_c);
372                    chars.next();
373                }
374                else {
375                    break;
376                }
377            }
378            if !num_str.is_empty() {
379                if let Ok(num) = num_str.parse::<usize>() {
380                    result.push_str(&format!("${}", num + start_index - 1));
381                }
382            }
383            else {
384                result.push(c);
385            }
386        }
387        else {
388            result.push(c);
389        }
390    }
391    result
392}
393
394/// 排序方式
395#[derive(Debug, Clone, Copy)]
396pub enum Order {
397    /// 升序
398    Asc,
399    /// 降序
400    Desc,
401}