sqlxplus/
crud.rs

1use crate::builder::query_builder::{BindValue, QueryBuilder};
2use crate::database_info::DatabaseInfo;
3use crate::error::{Result, SqlxPlusError};
4use crate::traits::Model;
5use sqlx::{Database, Row};
6
7/// 主键 ID 类型
8pub type Id = i64;
9
10/// 辅助函数:将单个绑定值应用到查询中
11/// 这是一个通用的绑定逻辑,通过宏来应用到不同的查询类型
12#[macro_export]
13macro_rules! apply_bind_value {
14    ($query:expr, $bind:expr) => {
15        match $bind {
16            $crate::builder::query_builder::BindValue::String(s) => {
17                $query = $query.bind(s);
18            }
19            $crate::builder::query_builder::BindValue::Int64(i) => {
20                $query = $query.bind(i);
21            }
22            $crate::builder::query_builder::BindValue::Int32(i) => {
23                $query = $query.bind(i);
24            }
25            $crate::builder::query_builder::BindValue::Int16(i) => {
26                $query = $query.bind(i);
27            }
28            // i8, u64, u32, u16, u8 在 PostgreSQL 中不支持,但保留在 BindValue 中用于 QueryBuilder
29            // 这些类型在 CRUD 操作中会通过类型转换处理
30            // 注意:当 $bind 是引用时,需要使用 ref 模式或解引用
31            $crate::builder::query_builder::BindValue::Int8(ref i) => {
32                // 转换为 i16(三种数据库都支持的最小整数类型)
33                $query = $query.bind(*i as i16);
34            }
35            $crate::builder::query_builder::BindValue::UInt64(ref i) => {
36                // 转换为 i64(注意:可能溢出,但这是跨数据库兼容的折中方案)
37                $query = $query.bind(*i as i64);
38            }
39            $crate::builder::query_builder::BindValue::UInt32(ref i) => {
40                // 转换为 i64
41                $query = $query.bind(*i as i64);
42            }
43            $crate::builder::query_builder::BindValue::UInt16(ref i) => {
44                // 转换为 i32
45                $query = $query.bind(*i as i32);
46            }
47            $crate::builder::query_builder::BindValue::UInt8(ref i) => {
48                // 转换为 i16
49                $query = $query.bind(*i as i16);
50            }
51            $crate::builder::query_builder::BindValue::Float64(f) => {
52                $query = $query.bind(f);
53            }
54            $crate::builder::query_builder::BindValue::Float32(f) => {
55                $query = $query.bind(f);
56            }
57            $crate::builder::query_builder::BindValue::Bool(b) => {
58                $query = $query.bind(b);
59            }
60            $crate::builder::query_builder::BindValue::Bytes(b) => {
61                $query = $query.bind(b);
62            }
63            $crate::builder::query_builder::BindValue::Null => {
64                $query = $query.bind(Option::<String>::None);
65            }
66        }
67    };
68}
69
70/// 泛型版本的绑定辅助函数:将绑定值应用到查询中(用于 query)
71///
72/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
73/// 用于处理 `sqlx::query` 类型的查询对象。
74///
75/// # 类型参数
76///
77/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
78///
79/// # 参数
80///
81/// * `query` - sqlx 的 `Query` 查询对象
82/// * `binds` - 绑定值数组
83///
84/// # 返回值
85///
86/// 应用了绑定值的查询对象
87fn apply_binds_to_query_generic<'q, DB>(
88    mut query: sqlx::query::Query<'q, DB, DB::Arguments<'q>>,
89    binds: &'q [BindValue],
90) -> sqlx::query::Query<'q, DB, DB::Arguments<'q>>
91where
92    DB: Database + DatabaseInfo,
93    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
94    // 基本类型必须实现 Type<DB> 和 Encode<DB>(这些对于 sqlx 支持的所有数据库都自动满足)
95    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
96    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
97    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
98    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
99    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
100    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
101    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
102    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
103    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
104    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
105{
106    for bind in binds {
107        crate::apply_bind_value!(query, bind);
108    }
109    query
110}
111
112/// 泛型版本的绑定辅助函数:将绑定值应用到查询中(用于 query_as)
113///
114/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
115/// 使用此函数可以避免为每个数据库类型创建单独的绑定函数。
116///
117/// # 类型参数
118///
119/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
120/// * `M` - 模型类型,必须实现对应数据库的 `FromRow`
121///
122/// # 参数
123///
124/// * `query` - sqlx 的 `QueryAs` 查询对象
125/// * `binds` - 绑定值数组
126///
127/// # 返回值
128///
129/// 应用了绑定值的查询对象
130fn apply_binds_to_query_as_generic<'q, DB, M>(
131    mut query: sqlx::query::QueryAs<'q, DB, M, DB::Arguments<'q>>,
132    binds: &'q [BindValue],
133) -> sqlx::query::QueryAs<'q, DB, M, DB::Arguments<'q>>
134where
135    DB: Database + DatabaseInfo,
136    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
137    M: for<'r> sqlx::FromRow<'r, DB::Row>,
138    // 基本类型必须实现 Type<DB> 和 Encode<DB>(这些对于 sqlx 支持的所有数据库都自动满足)
139    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
140    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
141    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
142    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
143    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
144    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
145    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
146    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
147    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
148    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
149{
150    for bind in binds {
151        crate::apply_bind_value!(query, bind);
152    }
153    query
154}
155
156/// 分页结果
157#[derive(Debug, Clone)]
158pub struct Page<T> {
159    pub items: Vec<T>,
160    pub total: i64,
161    pub page: u32,
162    pub size: u32,
163    pub pages: u32,
164}
165
166impl<T> Page<T> {
167    pub fn new(items: Vec<T>, total: i64, page: u32, size: u32) -> Self {
168        let pages = if size > 0 {
169            ((total as u64 + size as u64 - 1) / size as u64) as u32
170        } else {
171            0
172        };
173        Self {
174            items,
175            total,
176            page,
177            size,
178            pages,
179        }
180    }
181}
182
183/// 根据 ID 查找单条记录(泛型版本)
184///
185/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
186///
187/// # 类型参数
188///
189/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
190/// * `M` - 模型类型,必须实现 `Model` trait 和对应数据库的 `FromRow`
191/// * `E` - 执行器类型,可以是连接池或事务
192///
193/// # 参数
194///
195/// * `executor` - 数据库执行器(连接池或事务)
196/// * `id` - 主键 ID 值
197///
198/// # 返回值
199///
200/// 如果找到记录,返回 `Ok(Some(M))`;如果未找到,返回 `Ok(None)`
201///
202/// # 示例
203///
204/// ```rust,ignore
205/// use sqlxplus::{DatabaseInfo, crud};
206///
207/// // MySQL
208/// let user = crud::find_by_id::<sqlx::MySql, User, _>(pool, 1).await?;
209///
210/// // PostgreSQL
211/// let user = crud::find_by_id::<sqlx::Postgres, User, _>(pool, 1).await?;
212///
213/// // SQLite
214/// let user = crud::find_by_id::<sqlx::Sqlite, User, _>(pool, 1).await?;
215/// ```
216pub async fn find_by_id<'e, 'c: 'e, DB, M, E>(
217    executor: E,
218    id: impl for<'q> sqlx::Encode<'q, DB> + sqlx::Type<DB> + Send + Sync,
219) -> Result<Option<M>>
220where
221    DB: Database + DatabaseInfo,
222    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
223    M: Model + for<'r> sqlx::FromRow<'r, DB::Row> + Send + Unpin,
224    E: sqlx::Executor<'c, Database = DB> + Send,
225{
226    // 使用 DatabaseInfo trait 获取数据库特定信息
227    let escaped_table = DB::escape_identifier(M::TABLE);
228    let escaped_pk = DB::escape_identifier(M::PK);
229    let placeholder = DB::placeholder(0);
230
231    let sql_str = if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
232        let escaped_field = DB::escape_identifier(soft_delete_field);
233        format!(
234            "SELECT * FROM {} WHERE {} = {} AND {} = 0",
235            escaped_table, escaped_pk, placeholder, escaped_field
236        )
237    } else {
238        format!(
239            "SELECT * FROM {} WHERE {} = {}",
240            escaped_table, escaped_pk, placeholder
241        )
242    };
243
244    // 执行查询 - sqlx::query 可以从 executor 推断数据库类型
245    match sqlx::query(&sql_str)
246        .bind(id)
247        .fetch_optional(executor)
248        .await?
249    {
250        Some(row) => Ok(Some(sqlx::FromRow::from_row(&row).map_err(|e| {
251            SqlxPlusError::DatabaseError(sqlx::Error::Decode(
252                Box::new(e) as Box<dyn std::error::Error + Send + Sync + 'static>
253            ))
254        })?)),
255        None => Ok(None),
256    }
257}
258
259// 注意:find_by_id_mysql, find_by_id_postgres, find_by_id_sqlite 等兼容层函数已移除
260// 现在直接使用泛型版本的 find_by_id<DB, M, E>
261// trait 中的方法直接调用泛型版本,不再需要这些中间函数
262
263/// 根据多个 ID 查找记录(泛型版本)
264///
265/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
266///
267/// # 类型参数
268///
269/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
270/// * `M` - 模型类型,必须实现 `Model` trait 和对应数据库的 `FromRow`
271/// * `I` - ID 集合类型,可以是 `Vec<T>` 或其他实现了 `IntoIterator` 的类型
272/// * `E` - 执行器类型,可以是连接池或事务
273///
274/// # 参数
275///
276/// * `executor` - 数据库执行器(连接池或事务)
277/// * `ids` - 主键 ID 集合
278///
279/// # 返回值
280///
281/// 返回找到的所有记录,如果没有找到任何记录,返回空向量
282///
283/// # 示例
284///
285/// ```rust,ignore
286/// use sqlxplus::{DatabaseInfo, crud};
287///
288/// // MySQL
289/// let users = crud::find_by_ids::<sqlx::MySql, User, _, _>(pool, vec![1, 2, 3]).await?;
290///
291/// // PostgreSQL
292/// let users = crud::find_by_ids::<sqlx::Postgres, User, _, _>(pool, vec![1, 2, 3]).await?;
293///
294/// // SQLite
295/// let users = crud::find_by_ids::<sqlx::Sqlite, User, _, _>(pool, vec![1, 2, 3]).await?;
296/// ```
297pub async fn find_by_ids<'e, 'c: 'e, DB, M, I, E>(executor: E, ids: I) -> Result<Vec<M>>
298where
299    DB: Database + DatabaseInfo,
300    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
301    M: Model + for<'r> sqlx::FromRow<'r, DB::Row> + Send + Unpin,
302    I: IntoIterator + Send,
303    I::Item: for<'q> sqlx::Encode<'q, DB> + sqlx::Type<DB> + Send + Sync + Clone,
304    E: sqlx::Executor<'c, Database = DB> + Send,
305{
306    let ids_vec: Vec<_> = ids.into_iter().collect();
307    if ids_vec.is_empty() {
308        return Ok(Vec::new());
309    }
310
311    // 使用 DatabaseInfo trait 获取数据库特定信息
312    let escaped_table = DB::escape_identifier(M::TABLE);
313    let escaped_pk = DB::escape_identifier(M::PK);
314
315    // 为每个 ID 生成占位符
316    let placeholders: Vec<String> = (0..ids_vec.len()).map(|i| DB::placeholder(i)).collect();
317    let placeholders_str = placeholders.join(", ");
318
319    let mut sql_str = format!(
320        "SELECT * FROM {} WHERE {} IN ({})",
321        escaped_table, escaped_pk, placeholders_str
322    );
323
324    if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
325        let escaped_field = DB::escape_identifier(soft_delete_field);
326        sql_str.push_str(&format!(" AND {} = 0", escaped_field));
327    }
328
329    // 执行查询
330    let mut query = sqlx::query_as::<DB, M>(&sql_str);
331    for id in &ids_vec {
332        query = query.bind(id.clone());
333    }
334    query
335        .fetch_all(executor)
336        .await
337        .map_err(|e| SqlxPlusError::DatabaseError(e))
338}
339
340// 注意:find_by_ids_mysql, find_by_ids_postgres, find_by_ids_sqlite 等兼容层函数已移除
341// 现在直接使用泛型版本的 find_by_ids<DB, M, I, E>
342// trait 中的方法直接调用泛型版本,不再需要这些中间函数
343
344/// 根据查询构建器查找单条记录(泛型版本)
345///
346/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
347///
348/// # 类型参数
349///
350/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
351/// * `M` - 模型类型,必须实现 `Model` trait 和对应数据库的 `FromRow`
352/// * `E` - 执行器类型,可以是连接池或事务
353///
354/// # 参数
355///
356/// * `executor` - 数据库执行器(连接池或事务)
357/// * `builder` - 查询构建器
358///
359/// # 返回值
360///
361/// 如果找到记录,返回 `Ok(Some(M))`;如果未找到,返回 `Ok(None)`
362///
363/// # 示例
364///
365/// ```rust,ignore
366/// use sqlxplus::{DatabaseInfo, crud, QueryBuilder};
367///
368/// // MySQL
369/// let builder = QueryBuilder::new("SELECT * FROM user").and_eq("id", 1);
370/// let user = crud::find_one::<sqlx::MySql, User, _>(pool, builder).await?;
371///
372/// // PostgreSQL
373/// let builder = QueryBuilder::new("SELECT * FROM \"user\"").and_eq("id", 1);
374/// let user = crud::find_one::<sqlx::Postgres, User, _>(pool, builder).await?;
375///
376/// // SQLite
377/// let builder = QueryBuilder::new("SELECT * FROM user").and_eq("id", 1);
378/// let user = crud::find_one::<sqlx::Sqlite, User, _>(pool, builder).await?;
379/// ```
380pub async fn find_one<'e, 'c: 'e, DB, M, E>(executor: E, builder: QueryBuilder) -> Result<Option<M>>
381where
382    DB: Database + DatabaseInfo,
383    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
384    M: Model + for<'r> sqlx::FromRow<'r, DB::Row> + Send + Unpin,
385    E: sqlx::Executor<'c, Database = DB> + Send,
386    // 基本类型必须实现 Type<DB> 和 Encode<DB>(用于绑定值)
387    // 虽然 sqlx 已经为这些类型实现了这些 trait,但在泛型上下文中需要显式声明
388    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
389    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
390    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
391    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
392    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
393    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
394    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
395    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
396    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
397    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
398{
399    // 使用 DatabaseInfo trait 获取数据库特定信息
400    let driver = DB::get_driver();
401    let escaped_table = DB::escape_identifier(M::TABLE);
402
403    // 构建查询构建器
404    let mut query_builder = builder;
405    query_builder = query_builder.with_base_sql(format!("SELECT * FROM {}", escaped_table));
406
407    // 如果指定了逻辑删除字段,自动添加过滤条件(只查询未删除的记录)
408    if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
409        query_builder = query_builder.and_eq(soft_delete_field, 0);
410    }
411
412    // 自动添加 LIMIT 1
413    let mut sql = query_builder.into_sql(driver);
414    sql.push_str(" LIMIT 1");
415
416    let binds = query_builder.binds().to_vec();
417    let query = sqlx::query_as::<DB, M>(&sql);
418    let query = apply_binds_to_query_as_generic(query, &binds);
419
420    query
421        .fetch_optional(executor)
422        .await
423        .map_err(|e| SqlxPlusError::DatabaseError(e))
424}
425
426// 注意:find_one_mysql, find_one_postgres, find_one_sqlite 等兼容层函数已移除
427// 现在直接使用泛型版本的 find_one<DB, M, E>
428// trait 中的方法直接调用泛型版本,不再需要这些中间函数
429
430/// 根据查询构建器查找所有记录(泛型版本)
431///
432/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
433///
434/// # 类型参数
435///
436/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
437/// * `M` - 模型类型,必须实现 `Model` trait 和对应数据库的 `FromRow`
438/// * `E` - 执行器类型,可以是连接池或事务
439///
440/// # 参数
441///
442/// * `executor` - 数据库执行器(连接池或事务)
443/// * `builder` - 查询构建器(可选),如果为 `None`,则查询所有记录
444///
445/// # 返回值
446///
447/// 返回找到的所有记录,最多 1000 条
448///
449/// # 示例
450///
451/// ```rust,ignore
452/// use sqlxplus::{DatabaseInfo, crud, QueryBuilder};
453///
454/// // MySQL - 查询所有记录
455/// let users = crud::find_all::<sqlx::MySql, User, _>(pool, None).await?;
456///
457/// // PostgreSQL - 使用查询构建器
458/// let builder = QueryBuilder::new("SELECT * FROM \"user\"").and_eq("status", 1);
459/// let users = crud::find_all::<sqlx::Postgres, User, _>(pool, Some(builder)).await?;
460///
461/// // SQLite
462/// let users = crud::find_all::<sqlx::Sqlite, User, _>(pool, None).await?;
463/// ```
464pub async fn find_all<'e, 'c: 'e, DB, M, E>(
465    executor: E,
466    builder: Option<QueryBuilder>,
467) -> Result<Vec<M>>
468where
469    DB: Database + DatabaseInfo,
470    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
471    M: Model + for<'r> sqlx::FromRow<'r, DB::Row> + Send + Unpin,
472    E: sqlx::Executor<'c, Database = DB> + Send,
473    // 基本类型必须实现 Type<DB> 和 Encode<DB>(用于绑定值)
474    // 虽然 sqlx 已经为这些类型实现了这些 trait,但在泛型上下文中需要显式声明
475    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
476    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
477    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
478    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
479    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
480    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
481    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
482    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
483    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
484    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
485{
486    // 使用 DatabaseInfo trait 获取数据库特定信息
487    let driver = DB::get_driver();
488    let escaped_table = DB::escape_identifier(M::TABLE);
489
490    // 构建查询构建器
491    let mut query_builder =
492        builder.unwrap_or_else(|| QueryBuilder::new(format!("SELECT * FROM {}", escaped_table)));
493    query_builder = query_builder.with_base_sql(format!("SELECT * FROM {}", escaped_table));
494
495    // 如果指定了逻辑删除字段,自动添加过滤条件(只查询未删除的记录)
496    if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
497        query_builder = query_builder.and_eq(soft_delete_field, 0);
498    }
499
500    // 限制最多 1000 条
501    let mut sql = query_builder.into_sql(driver);
502    sql.push_str(" LIMIT 1000");
503
504    let binds = query_builder.binds().to_vec();
505    let query = sqlx::query_as::<DB, M>(&sql);
506    let query = apply_binds_to_query_as_generic(query, &binds);
507
508    query
509        .fetch_all(executor)
510        .await
511        .map_err(|e| SqlxPlusError::DatabaseError(e))
512}
513
514// 注意:find_all_mysql, find_all_postgres, find_all_sqlite 等兼容层函数已移除
515// 现在直接使用泛型版本的 find_all<DB, M, E>
516// trait 中的方法直接调用泛型版本,不再需要这些中间函数
517
518/// 统计记录数量(泛型版本)
519///
520/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
521///
522/// # 类型参数
523///
524/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
525/// * `M` - 模型类型,必须实现 `Model` trait
526/// * `E` - 执行器类型,可以是连接池或事务
527///
528/// # 参数
529///
530/// * `executor` - 数据库执行器(连接池或事务)
531/// * `builder` - 查询构建器
532///
533/// # 返回值
534///
535/// 返回符合条件的记录数量
536///
537/// # 示例
538///
539/// ```rust,ignore
540/// use sqlxplus::{DatabaseInfo, crud, QueryBuilder};
541///
542/// // MySQL
543/// let builder = QueryBuilder::new("SELECT * FROM user");
544/// let count = crud::count::<sqlx::MySql, User, _>(pool, builder).await?;
545///
546/// // PostgreSQL
547/// let builder = QueryBuilder::new("SELECT * FROM \"user\"");
548/// let count = crud::count::<sqlx::Postgres, User, _>(pool, builder).await?;
549///
550/// // SQLite
551/// let builder = QueryBuilder::new("SELECT * FROM user");
552/// let count = crud::count::<sqlx::Sqlite, User, _>(pool, builder).await?;
553/// ```
554pub async fn count<'e, 'c: 'e, DB, M, E>(executor: E, builder: QueryBuilder) -> Result<u64>
555where
556    DB: Database + DatabaseInfo,
557    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
558    M: Model,
559    E: sqlx::Executor<'c, Database = DB> + Send,
560    // 基本类型必须实现 Type<DB> 和 Encode<DB>(用于绑定值)
561    // i64 还需要实现 Decode<DB>(用于从查询结果中读取)
562    // usize 需要实现 ColumnIndex<DB::Row>(用于通过索引访问列)
563    // 虽然 sqlx 已经为这些类型实现了这些 trait,但在泛型上下文中需要显式声明
564    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
565    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
566    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB> + for<'r> sqlx::Decode<'r, DB>,
567    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
568    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
569    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
570    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
571    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
572    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
573    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
574    usize: sqlx::ColumnIndex<DB::Row>,
575{
576    // 使用 DatabaseInfo trait 获取数据库特定信息
577    let driver = DB::get_driver();
578    let escaped_table = DB::escape_identifier(M::TABLE);
579
580    let mut query_builder = builder;
581    query_builder = query_builder.with_base_sql(format!("SELECT * FROM {}", escaped_table));
582
583    if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
584        query_builder = query_builder.and_eq(soft_delete_field, 0);
585    }
586
587    let binds = query_builder.binds().to_vec();
588    let count_sql = query_builder.into_count_sql(driver);
589    let query = sqlx::query::<DB>(&count_sql);
590    let query = apply_binds_to_query_generic(query, &binds);
591
592    let row = query.fetch_one(executor).await?;
593    // 使用 get 方法,明确指定索引类型为 usize
594    let count_value: i64 = row.get(0usize);
595    Ok(count_value as u64)
596}
597
598// 注意:count_mysql, count_postgres, count_sqlite 等兼容层函数已移除
599// 现在直接使用泛型版本的 count<DB, M, E>
600// trait 中的方法直接调用泛型版本,不再需要这些中间函数
601
602/// 分页查询(泛型版本)
603///
604/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
605///
606/// # 类型参数
607///
608/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
609/// * `M` - 模型类型,必须实现 `Model` trait 和对应数据库的 `FromRow`
610/// * `E` - 执行器类型,可以是连接池或事务(需要实现 `Clone`)
611///
612/// # 参数
613///
614/// * `executor` - 数据库执行器(连接池或事务)
615/// * `builder` - 查询构建器
616/// * `page` - 页码(从 1 开始)
617/// * `size` - 每页大小
618///
619/// # 返回值
620///
621/// 返回分页结果,包含数据列表、总数、页码等信息
622///
623/// # 示例
624///
625/// ```rust,ignore
626/// use sqlxplus::{DatabaseInfo, crud, QueryBuilder};
627///
628/// // MySQL
629/// let builder = QueryBuilder::new("SELECT * FROM user");
630/// let page = crud::paginate::<sqlx::MySql, User, _>(pool, builder, 1, 10).await?;
631///
632/// // PostgreSQL
633/// let builder = QueryBuilder::new("SELECT * FROM \"user\"");
634/// let page = crud::paginate::<sqlx::Postgres, User, _>(pool, builder, 1, 10).await?;
635///
636/// // SQLite
637/// let builder = QueryBuilder::new("SELECT * FROM user");
638/// let page = crud::paginate::<sqlx::Sqlite, User, _>(pool, builder, 1, 10).await?;
639/// ```
640pub async fn paginate<'e, 'c: 'e, DB, M, E>(
641    executor: E,
642    mut builder: QueryBuilder,
643    page: u32,
644    size: u32,
645) -> Result<Page<M>>
646where
647    DB: Database + DatabaseInfo,
648    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
649    M: Model + for<'r> sqlx::FromRow<'r, DB::Row> + Send + Unpin,
650    E: sqlx::Executor<'c, Database = DB> + Send + Clone,
651    // 基本类型必须实现 Type<DB> 和 Encode<DB>(用于绑定值)
652    // i64 还需要实现 Decode<DB>(用于从查询结果中读取)
653    // usize 需要实现 ColumnIndex<DB::Row>(用于通过索引访问列)
654    // 虽然 sqlx 已经为这些类型实现了这些 trait,但在泛型上下文中需要显式声明
655    // 注意:只包含三种数据库(MySQL、PostgreSQL、SQLite)都支持的类型
656    String: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
657    i64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB> + for<'r> sqlx::Decode<'r, DB>,
658    i32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
659    i16: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
660    f64: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
661    f32: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
662    bool: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
663    Vec<u8>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
664    Option<String>: sqlx::Type<DB> + for<'b> sqlx::Encode<'b, DB>,
665    usize: sqlx::ColumnIndex<DB::Row>,
666{
667    let offset = ((page as u64).saturating_sub(1) * size as u64) as u32;
668    let driver = DB::get_driver();
669    let escaped_table = DB::escape_identifier(M::TABLE);
670
671    builder = builder.with_base_sql(format!("SELECT * FROM {}", escaped_table));
672
673    if let Some(soft_delete_field) = M::SOFT_DELETE_FIELD {
674        builder = builder.and_eq(soft_delete_field, 0);
675    }
676
677    let binds = builder.binds().to_vec();
678
679    // 执行 count 查询获取总数
680    let count_sql = builder.clone().into_count_sql(driver);
681    let count_query = sqlx::query::<DB>(&count_sql);
682    let count_query = apply_binds_to_query_generic(count_query, &binds);
683    let executor_clone = executor.clone();
684    let row = count_query.fetch_one(executor_clone).await?;
685    let total: i64 = row.get(0usize);
686
687    // 执行分页查询获取数据
688    let data_sql = builder.clone().into_paginated_sql(driver, size, offset);
689    let query = sqlx::query_as::<DB, M>(&data_sql);
690    let query = apply_binds_to_query_as_generic(query, &binds);
691    let items = query
692        .fetch_all(executor)
693        .await
694        .map_err(|e| SqlxPlusError::DatabaseError(e))?;
695
696    Ok(Page::new(items, total, page, size))
697}
698
699// 注意:paginate_mysql, paginate_postgres, paginate_sqlite 等兼容层函数已移除
700// 现在直接使用泛型版本的 paginate<DB, M, E>
701// trait 中的方法直接调用泛型版本,不再需要这些中间函数
702
703/// 根据 ID 物理删除记录(泛型版本)
704///
705/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
706///
707/// # 类型参数
708///
709/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
710/// * `M` - 模型类型,必须实现 `Model` trait
711/// * `E` - 执行器类型,可以是连接池或事务
712///
713/// # 参数
714///
715/// * `executor` - 数据库执行器(连接池或事务)
716/// * `id` - 主键 ID 值
717///
718/// # 返回值
719///
720/// 删除成功返回 `Ok(())`
721///
722/// # 示例
723///
724/// ```rust,ignore
725/// use sqlxplus::{DatabaseInfo, crud};
726///
727/// // MySQL
728/// crud::hard_delete_by_id::<sqlx::MySql, User, _>(pool, 1).await?;
729///
730/// // PostgreSQL
731/// crud::hard_delete_by_id::<sqlx::Postgres, User, _>(pool, 1).await?;
732///
733/// // SQLite
734/// crud::hard_delete_by_id::<sqlx::Sqlite, User, _>(pool, 1).await?;
735/// ```
736pub async fn hard_delete_by_id<'e, 'c: 'e, DB, M, E>(
737    executor: E,
738    id: impl for<'q> sqlx::Encode<'q, DB> + sqlx::Type<DB> + Send + Sync,
739) -> Result<()>
740where
741    DB: Database + DatabaseInfo,
742    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
743    M: Model,
744    E: sqlx::Executor<'c, Database = DB> + Send,
745{
746    let escaped_table = DB::escape_identifier(M::TABLE);
747    let escaped_pk = DB::escape_identifier(M::PK);
748    let placeholder = DB::placeholder(0);
749    let sql = format!(
750        "DELETE FROM {} WHERE {} = {}",
751        escaped_table, escaped_pk, placeholder
752    );
753    sqlx::query(&sql).bind(id).execute(executor).await?;
754    Ok(())
755}
756
757/// 根据 ID 逻辑删除记录(泛型版本)
758///
759/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
760/// 逻辑删除会将 `SOFT_DELETE_FIELD` 字段设置为 1。
761///
762/// # 类型参数
763///
764/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
765/// * `M` - 模型类型,必须实现 `Model` trait 且定义了 `SOFT_DELETE_FIELD`
766/// * `E` - 执行器类型,可以是连接池或事务
767///
768/// # 参数
769///
770/// * `executor` - 数据库执行器(连接池或事务)
771/// * `id` - 主键 ID 值
772///
773/// # 返回值
774///
775/// 删除成功返回 `Ok(())`;如果模型未定义 `SOFT_DELETE_FIELD`,返回错误
776///
777/// # 示例
778///
779/// ```rust,ignore
780/// use sqlxplus::{DatabaseInfo, crud};
781///
782/// // MySQL
783/// crud::soft_delete_by_id::<sqlx::MySql, User, _>(pool, 1).await?;
784///
785/// // PostgreSQL
786/// crud::soft_delete_by_id::<sqlx::Postgres, User, _>(pool, 1).await?;
787///
788/// // SQLite
789/// crud::soft_delete_by_id::<sqlx::Sqlite, User, _>(pool, 1).await?;
790/// ```
791pub async fn soft_delete_by_id<'e, 'c: 'e, DB, M, E>(
792    executor: E,
793    id: impl for<'q> sqlx::Encode<'q, DB> + sqlx::Type<DB> + Send + Sync,
794) -> Result<()>
795where
796    DB: Database + DatabaseInfo,
797    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
798    M: Model,
799    E: sqlx::Executor<'c, Database = DB> + Send,
800{
801    let soft_delete_field = M::SOFT_DELETE_FIELD.ok_or_else(|| {
802        SqlxPlusError::DatabaseError(sqlx::Error::Configuration(
803            format!(
804                "Model {} does not have SOFT_DELETE_FIELD defined",
805                std::any::type_name::<M>()
806            )
807            .into(),
808        ))
809    })?;
810
811    let escaped_table = DB::escape_identifier(M::TABLE);
812    let escaped_pk = DB::escape_identifier(M::PK);
813    let escaped_field = DB::escape_identifier(soft_delete_field);
814    let placeholder = DB::placeholder(0);
815    let sql = format!(
816        "UPDATE {} SET {} = 1 WHERE {} = {}",
817        escaped_table, escaped_field, escaped_pk, placeholder
818    );
819    sqlx::query(&sql).bind(id).execute(executor).await?;
820    Ok(())
821}
822
823/// 根据 ID 删除记录(泛型版本)
824///
825/// 这是统一的泛型实现,支持所有实现了 `DatabaseInfo` 的数据库类型。
826/// 如果模型定义了 `SOFT_DELETE_FIELD`,则使用逻辑删除;否则使用物理删除。
827///
828/// # 类型参数
829///
830/// * `DB` - 数据库类型(如 `sqlx::MySql`, `sqlx::Postgres`, `sqlx::Sqlite`)
831/// * `M` - 模型类型,必须实现 `Model` trait
832/// * `E` - 执行器类型,可以是连接池或事务
833///
834/// # 参数
835///
836/// * `executor` - 数据库执行器(连接池或事务)
837/// * `id` - 主键 ID 值
838///
839/// # 返回值
840///
841/// 删除成功返回 `Ok(())`
842///
843/// # 示例
844///
845/// ```rust,ignore
846/// use sqlxplus::{DatabaseInfo, crud};
847///
848/// // MySQL
849/// crud::delete_by_id::<sqlx::MySql, User, _>(pool, 1).await?;
850///
851/// // PostgreSQL
852/// crud::delete_by_id::<sqlx::Postgres, User, _>(pool, 1).await?;
853///
854/// // SQLite
855/// crud::delete_by_id::<sqlx::Sqlite, User, _>(pool, 1).await?;
856/// ```
857pub async fn delete_by_id<'e, 'c: 'e, DB, M, E>(
858    executor: E,
859    id: impl for<'q> sqlx::Encode<'q, DB> + sqlx::Type<DB> + Send + Sync,
860) -> Result<()>
861where
862    DB: Database + DatabaseInfo,
863    for<'a> DB::Arguments<'a>: sqlx::IntoArguments<'a, DB>,
864    M: Model,
865    E: sqlx::Executor<'c, Database = DB> + Send,
866{
867    if M::SOFT_DELETE_FIELD.is_some() {
868        soft_delete_by_id::<DB, M, E>(executor, id).await
869    } else {
870        hard_delete_by_id::<DB, M, E>(executor, id).await
871    }
872}