Crate typed_sqlx_client

Source
Expand description

Β§typed_sqlx_client

A type-safe, extensible Rust library for managing multiple SQL databases and tables with sqlx, providing automatic CRUD operations and flexible query capabilities.

§🎯 Core Design Philosophy

This library is specifically designed for multi-database, multi-table scenarios where:

  • Different tables require different operation sets and business logic
  • Each table can implement custom traits independently
  • No monolithic β€œSQL client” that tries to handle all table operations
  • Type safety prevents accidental cross-database/cross-table operations

Key Principle: Each table type gets its own trait implementations, allowing for:

  • πŸŽ›οΈ Granular control: Only implement the operations each table actually needs
  • πŸ”’ Type safety: Compile-time prevention of mixing databases/tables
  • πŸš€ Performance: No runtime overhead for unused operations
  • 🧩 Modularity: Easy to add/remove/modify table-specific behaviors

Β§Overview

This library evolved from v0.1.1 with significant improvements:

  • Removed the old CrudOps trait
  • Added the #[derive(CrudOpsRef)] macro for automatic CRUD implementation
  • Enhanced SELECT queries with type-safe execute_select_as_only<T>() method
  • Direct implementation of SelectOnlyQuery on SqlTable (no macro required)

Β§Key Features

  • πŸ”’ Type-safe wrappers: Generic SqlPool<P, DB> and SqlTable<P, DB, Table> for compile-time safety
  • πŸ—„οΈ Multi-database support: MySQL, PostgreSQL, and SQLite with unified API
  • ⚑ Auto-generated CRUD: #[derive(CrudOpsRef)] macro creates all CRUD operations instantly
  • πŸ” Dual query modes:
    • execute_select_only(): Dynamic JSON results for unknown schemas
    • execute_select_as_only<T>(): Type-safe deserialization to structs/tuples
  • 🌐 Framework ready: Perfect for actix-web, warp, and other async web frameworks
  • 🏷️ Multiple database support: Handle multiple databases with compile-time distinction

Β§Migration from v0.1.1

Breaking Changes:

  • CrudOps trait has been removed
  • Replace with #[derive(CrudOpsRef)] macro on your struct
  • SelectOnlyQuery is now implemented directly on SqlTable

New Features:

  • Type-safe SELECT with execute_select_as_only<T>()
  • Enhanced field mapping with #[crud(rename = "...")]
  • Improved primary key detection and handling

Β§Quick Start Example

use typed_sqlx_client::{CrudOpsRef, SqlPool, SelectOnlyQuery};
use sqlx::{PgPool, FromRow};
use uuid::Uuid;

// Define your database entity with automatic CRUD
#[derive(FromRow, CrudOpsRef, Debug)]
#[crud(table = "users", db = "postgres")]
struct User {
    #[crud(primary_key)]
    id: Option<Uuid>,
    #[crud(rename = "user_name")]  // Maps to database column 'user_name'
    name: String,
    email: String,
}

// Create a database marker for type safety
struct MainDatabase;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Setup typed connection pool
    let pool = PgPool::connect("postgres://...").await?;
    let sql_pool = SqlPool::from_pool::<MainDatabase>(pool);
    let user_table = sql_pool.get_table::<User>();
     
    // CRUD operations (auto-generated by derive macro)
    let user = User {
        id: Some(Uuid::new_v4()),
        name: "Alice".to_string(),
        email: "alice@example.com".to_string()
    };
    user_table.insert(&user).await?;
     
    let found_user = user_table.get_by_id(&user.id.unwrap()).await?;
     
    // Type-safe SELECT queries
    let users: Vec<User> = user_table
        .execute_select_as_only::<User>("SELECT * FROM users WHERE email LIKE '%@example.com'")
        .await?;
     
    // For aggregations or custom queries
    let counts: Vec<(i64,)> = user_table
        .execute_select_as_only::<(i64,)>("SELECT COUNT(*) FROM users")
        .await?;
     
    // Dynamic JSON queries for unknown schemas
    let json_rows = user_table
        .execute_select_only("SELECT name, email FROM users")
        .await?;
     
    Ok(())
}

Β§Multi-Database Usage

Handle multiple databases with type safety:

struct MainDB;
struct AnalyticsDB;

let main_pool = SqlPool::from_pool::<MainDB>(main_pg_pool);
let analytics_pool = SqlPool::from_pool::<AnalyticsDB>(analytics_pg_pool);

let users = main_pool.get_table::<User>();
let events = analytics_pool.get_table::<Event>();
// Compile-time prevents mixing up databases!

Β§Supported Databases

DatabaseDerive SupportQuery SupportStatus
MySQLβœ… db = "mysql"βœ… Both modesStable
PostgreSQLβœ… db = "postgres"βœ… Both modesStable
SQLiteβœ… db = "sqlite"βœ… Both modesStable

Re-exportsΒ§

pub use tables::*;
pub use traits::*;

ModulesΒ§

tables
traits

Derive MacrosΒ§

CrudOpsRef
Derive macro for automatically implementing the CrudOpsRef trait.