Skip to content

lifeRobot/ssw

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SSW (Simple Smart Wrapper)

Rust Version License Crates.io

A lightweight, type-safe Rust ORM library built on top of rbatis


🚀 Features

  • Type-safe SQL generation - Compile-time query validation
  • Wrapper pattern - Fluent API for building complex queries
  • DaoTrait - Standard CRUD operations out of the box
  • Macro support - Minimal boilerplate with impl_model_trait! and impl_dao_trait!
  • Async/await - Native async support with tokio
  • Multi-database support - PostgreSQL, SQLite, MySQL via rbatis
  • Pagination - Built-in PageResult with metadata
  • Aggregate functions - count, max, min, sum, avg, exists

📦 Installation

Add to your Cargo.toml:

[dependencies]
ssw = "0.1.1"

# For PostgreSQL
rbdc-pg = "4.9"

# For SQLite
rbdc-sqlite = "4.8"

# For MySQL
rbdc-mysql = "4.8"

# Common dependencies
serde = { version = "1.0", features = ["derive"] }
lazy_static = "1.5"

🔥 Quick Start

1. Define Your Model

use serde::{Deserialize, Serialize};
use ssw::{ModelTrait, DaoTrait, impl_model_trait, impl_dao_trait};
use ssw::QueryWrapper;

#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    id: Option<i64>,       // SERIAL PRIMARY KEY → Option<i64>
    username: Option<String>,
    email: Option<String>,
    status: Option<i32>,
    created_at: Option<i64>, // TIMESTAMP → Option<i64> (Unix ms)
}

// Implement ModelTrait (required)
impl_model_trait!(User, "users");

2. Initialize RBatis

use rbatis::RBatis;
use rbdc_pg::PgDriver;
use lazy_static::lazy_static;

lazy_static! {
    static ref RB: RBatis = RBatis::new();
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize with PostgreSQL connection string
    RB.init(PgDriver {}, "postgres://postgres:123456@127.0.0.1:5432/tt").unwrap();
    
    println!("✅ Database connected!");
    Ok(())
}

3. Implement DaoTrait

// Use macro (recommended)
impl_dao_trait!(User, User, &RB);

// Or implement manually
impl DaoTrait for User {
    type T = User;
    
    fn rb_ref() -> &'static RBatis {
        &RB
    }
}

4. Use CRUD Operations

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ===== INSERT =====
    let user = User {
        id: None,
        username: Some("alice".to_string()),
        email: Some("alice@example.com".to_string()),
        status: Some(1),
        created_at: None,
    };
    
    let result = User::try_save(&user).await?;
    println!("Inserted {} rows", result.rows_affected);
    
    // ===== SELECT =====
    let users = User::select_by_column("status", 1).await;
    println!("Found {} active users", users.len());
    
    // ===== UPDATE =====
    let user = User {
        id: None,
        username: None,
        email: Some("alice_new@example.com".to_string()),
        status: Some(2),
        created_at: None,
    };
    
    let result = User::try_update_by_column(&user, "username", "alice").await?;
    println!("Updated {} rows", result.rows_affected);
    
    // ===== DELETE =====
    let result = User::try_delete_by_column("username", "alice").await?;
    println!("Deleted {} rows", result.rows_affected);
    
    Ok(())
}

5. Pagination (Optional)

use ssw::Page;

// Create a Page (recommended: use ::new())
let page = Page::new(1, 10);  // Page 1, 10 records per page

let wrapper = QueryWrapper::new()
    .table("users")
    .order_by(Order::Desc("id"));

let page_result = User::select_page(wrapper, page).await;

println!("Total: {}", page_result.total);
println!("Total pages: {}", page_result.total_pages);
println!("Data: {:?}", page_result.list);

📚 Documentation

📖 Full documentation: See skills/SKILL.md for:

  • Complete API reference
  • Advanced usage examples
  • Best practices
  • Troubleshooting guide
  • Migration guide

🧪 Examples: See integration tests for complete working examples:


🧪 Testing

# Run unit tests
cargo test --lib --tests

# Run integration tests (requires database)
# PostgreSQL
cd examples/rbatis_test/pgsql_test
cargo run

# SQLite
cd examples/rbatis_test/sqlite_test
cargo run

# MySQL
cd examples/rbatis_test/mysql_test
cargo run

# Check code coverage (optional)
cargo tarpaulin --out html

⚠️ Safety Warnings

try_delete_all() - EXTREME DANGER!

// ⚠️ WARNING: This will DELETE ALL RECORDS in the table!
let result = User::try_delete_all().await?;

Never use try_delete_all() in production! Always add WHERE conditions:

// ✅ Safe: Delete with condition
User::try_delete_by_column("id", user_id).await?;

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the repo
git clone https://github.com/yourusername/ssw.git
cd ssw

# Run tests
cargo test --lib --tests

# Run integration tests (requires database)
# PostgreSQL
cd examples/rbatis_test/pgsql_test
cargo run

# SQLite
cd examples/rbatis_test/sqlite_test
cargo run

# MySQL
cd examples/rbatis_test/mysql_test
cargo run

📄 License

Licensed under either of:

at your option.


🙏 Acknowledgments

  • rbatis - The underlying Rust ORM framework
  • serde - Serialization framework
  • tokio - Async runtime

📧 Contact


Made with ❤️ in Rust

About

ssw is sql simple wrapper

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages