pgbatis 0.1.51

pgbaits 用于操作数据库数据的增删改查
Documentation
/*
 * @Author: BuddyCoder
 * @Date: 2026-06-05 09:02:52
 * @LastEditTime: 2026-06-05 09:02:54
 * @LastEditors: BuddyCoder
 * @Description: 
 * @FilePath: /pgbatis/examples/basic_crud.rs
 * MIT
 */
//! pgbatis 完整 CRUD 示例。
//!
//! 运行前请确保:
//! 1. PostgreSQL 服务已启动
//! 2. 修改下方 `link()` 参数中的连接信息
//! 3. 目标数据库中已创建对应用户表:
//! ```sql
//! CREATE TABLE users (
//!     id VARCHAR PRIMARY KEY,
//!     name VARCHAR,
//!     age INT,
//!     is_deleted INT DEFAULT 0
//! );
//! ```
//!
//! 运行方式:
//! ```bash
//! cargo run --example basic_crud
//! ```

use pgbatis::pgmacro::PGCRUD;
use pgbatis::Wrapper;
// PGCRUD 宏需要的 trait 和类型
use pgbatis::ColumnExt;
use pgbatis::Parameters;
use pgbatis::tokio_postgres::types::ToSql;
use pgbatis::tokio_postgres::Row;
use serde::{Deserialize, Serialize};

// ─── 1. 定义实体 ────────────────────────────────────────────
//
// #[derive(PGCRUD)] 会:
// - 自动实现 Parameters trait(含 get_table_name / gen_save / gen_update / return_one)
// - 自动生成 UserColumn 结构体(如 UserColumn::Id、UserColumn::Name)

#[derive(PGCRUD, Serialize, Deserialize, Clone, Debug, Default)]
pub struct User {
    pub id: Option<String>,
    pub name: Option<String>,
    pub age: Option<i32>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ─── 2. 初始化连接池(必须最先调用) ─────────────────────
    pgbatis::link("127.0.0.1", 5432, "postgres", "password", "mydb", 10).await?;
    println!("✅ 数据库连接成功");

    // ─── 3. 探活 ─────────────────────────────────────────────
    pgbatis::ping().await?;
    println!("✅ ping 成功");

    // ─── 4. 保存(INSERT) ────────────────────────────────────
    let user = User {
        id: Some("u1".into()),
        name: Some("Alice".into()),
        age: Some(30),
    };
    let rows = pgbatis::save(user.clone(), None, None).await?;
    println!("✅ save 成功,影响行数: {rows}");

    // 批量保存
    let users = vec![
        User { id: Some("u2".into()), name: Some("Bob".into()), age: Some(25) },
        User { id: Some("u3".into()), name: Some("Charlie".into()), age: Some(35) },
        User { id: Some("u4".into()), name: Some("Diana".into()), age: Some(28) },
        User { id: Some("u5".into()), name: Some("Eve".into()), age: Some(22) },
    ];
    for u in &users {
        pgbatis::save(u.clone(), None, None).await?;
    }
    println!("✅ 批量 save 成功");

    // ─── 5. 条件更新(UPDATE) ────────────────────────────────
    let update_data = User {
        name: Some("Alice Updated".into()),
        ..Default::default()
    };
    let rows = pgbatis::update(
        update_data,
        Wrapper::new().eq(&UserColumn::Id, &"u1"),
        None,
        None,
    )
    .await?;
    println!("✅ update 成功,影响行数: {rows}");

    // ─── 6. 查询 ─────────────────────────────────────────────

    // 6.1 单表查询列表(类型化)
    let all_users: Vec<User> = pgbatis::fetch(Wrapper::new(), None, None).await?;
    println!("✅ fetch 全部用户: {}", all_users.len());

    // 6.2 条件查询
    let adults: Vec<User> = pgbatis::fetch(
        Wrapper::new().gt(&UserColumn::Age, &18),
        None,
        None,
    )
    .await?;
    println!("✅ fetch 成年用户: {}", adults.len());

    // 6.3 单条查询
    let alice: User = pgbatis::fetch_one(
        Wrapper::new().eq(&UserColumn::Id, &"u1"),
        None,
        None,
    )
    .await?;
    println!("✅ fetch_one: {:?}", alice);

    // 6.4 指定返回字段(不返回全部字段)
    let names: Vec<std::collections::HashMap<String, serde_json::Value>> = pgbatis::fetch_with_recoder_field::<User>(
        Wrapper::new()
            .set_recoder_field(&UserColumn::Id)
            .set_recoder_field(&UserColumn::Name),
        None,
        None,
    )
    .await?;
    println!("✅ fetch_with_recoder_field(仅 id+name): {names:?}");

    // 6.5 分页查询
    let page = pgbatis::fetch_page::<User>(
        Wrapper::new()
            .set_pages(1, 2) // 第1页,每页2条
            .set_order_by_column_ext(&UserColumn::Id, false), // 按 id 升序
        None,
        None,
    )
    .await?;
    println!(
        "✅ fetch_page: 第{}/{}页,总{}",
        page.current_page, page.pages, page.total
    );
    for u in &page.records {
        println!("    - {:?}", u);
    }

    // ─── 7. 模糊查询 ─────────────────────────────────────────
    let keyword = pgbatis::format_like(&Some("li".into()));
    let matched: Vec<User> = pgbatis::fetch(
        Wrapper::new().like(&UserColumn::Name, &keyword),
        None,
        None,
    )
    .await?;
    println!("✅ LIKE 查询(含 'li'): {matched:?}");

    // ─── 8. 原生 SQL 查询 ─────────────────────────────────────

    // 8.1 查询列表(返回 HashMap)
    let rows = pgbatis::query(
        "SELECT name, age FROM users WHERE age > $1 ORDER BY age DESC",
        &[&20],
    )
    .await?;
    println!("✅ query: {rows:?}");

    // 8.2 查询单条
    let stat = pgbatis::query_one("SELECT count(*) as cnt, avg(age) as avg_age FROM users", &[])
        .await?;
    println!("✅ query_one: {stat:?}");

    // 8.3 联表分页(此处以单表为例)
    let page = pgbatis::query_page(
        "SELECT id, name, age FROM users",
        &[],
        "age",
        true, // 按年龄降序
        1,
        3,
    )
    .await?;
    println!("✅ query_page: 总{}条,当前页{}", page.total, page.records.len());

    // 8.4 类型化原生查询
    let typed_users: Vec<User> = pgbatis::query_t::<User>(
        "SELECT id, name, age FROM users WHERE age < $1",
        &[&30],
    )
    .await?;
    println!("✅ query_t: {}", typed_users.len());

    // 8.5 执行非查询 SQL
    let rows = pgbatis::execute(
        &"UPDATE users SET age = $1 WHERE id = $2".to_string(),
        &[&99, &"u1"],
    )
    .await?;
    println!("✅ execute: {rows}");

    // ─── 9. 存在性检查 ───────────────────────────────────────

    // 9.1 按列值检查
    let exists = pgbatis::check_row_by_column("users", &UserColumn::Name, "Alice Updated").await?;
    println!("✅ check_row_by_column: Alice 存在? {exists}");

    // 9.2 按 Wrapper 条件检查
    let exists = pgbatis::check_row_wrap::<User>(
        Wrapper::new().eq(&UserColumn::Id, &"u99"),
        None,
        None,
    )
    .await?;
    println!("✅ check_row_wrap: u99 存在? {exists}");

    // ─── 10. 范围查询 ────────────────────────────────────────
    let mid_age: Vec<User> = pgbatis::fetch(
        Wrapper::new()
            .between(&UserColumn::Age, &25, &35)
            .set_order_by_column_ext(&UserColumn::Age, false),
        None,
        None,
    )
    .await?;
    println!("✅ between 25~35: {mid_age:?}");

    // ─── 11. 集合查询 ────────────────────────────────────────
    let targets: Vec<User> = pgbatis::fetch(
        Wrapper::new().in_array_string(
            &UserColumn::Id,
            &vec!["u2".into(), "u3".into(), "u4".into()],
        ),
        None,
        None,
    )
    .await?;
    println!("✅ in_array_string: {targets:?}");

    // ─── 12. 软删除 ──────────────────────────────────────────
    let rows = pgbatis::remove::<User>(
        Wrapper::new().eq(&UserColumn::Id, &"u5"),
        None,
        None,
    )
    .await?;
    println!("✅ remove(软删除)u5,影响: {rows}");

    // 被软删除的记录不会出现在查询结果中
    let after_delete: Vec<User> = pgbatis::fetch(Wrapper::new(), None, None).await?;
    println!("   删除后剩余: {} 条(u5 已被过滤)", after_delete.len());

    // ─── 13. 强制物理删除 ─────────────────────────────────────
    let rows = pgbatis::permanent_deletion::<User>(
        Wrapper::new().eq(&UserColumn::Id, &"u4"),
        None,
        None,
    )
    .await?;
    println!("✅ permanent_deletion u4,影响: {rows}");

    // ─── 14. 逻辑删除排除表 ───────────────────────────────────
    // 对 sys_log 之类不需要逻辑删除的表,加入排除名单
    pgbatis::set_unlogic_delete_table("sys_log");

    // ─── 15. 事务操作 ────────────────────────────────────────

    // 15.1 先删后批量插
    let new_users = vec![
        User { id: Some("t1".into()), name: Some("Tx1".into()), age: Some(10) },
        User { id: Some("t2".into()), name: Some("Tx2".into()), age: Some(20) },
    ];
    pgbatis::transaction_delete_and_save(
        &UserColumn::Id,
        &"u1",
        new_users,
        None,
        None,
    )
    .await?;
    println!("✅ transaction_delete_and_save 成功");

    // 15.2 批量事务(可跨表)
    use pgbatis::TransactionBatchParam;
    let params = vec![
        TransactionBatchParam {
            statement_sql: "UPDATE users SET age = $1 WHERE id = $2",
            params: vec![&50, &"t1"],
        },
        TransactionBatchParam {
            statement_sql: "UPDATE users SET age = $1 WHERE id = $2",
            params: vec![&60, &"t2"],
        },
    ];
    pgbatis::transaction_batch(params).await?;
    println!("✅ transaction_batch 成功");

    // ─── 16. 最终结果 ────────────────────────────────────────
    let final_users: Vec<User> = pgbatis::fetch(
        Wrapper::new().set_order_by_column_ext(&UserColumn::Id, false),
        None,
        None,
    )
    .await?;
    println!("\n🎉 最终用户列表:");
    for u in &final_users {
        println!("    {:?}", u);
    }

    Ok(())
}