Crate sql_middleware

Crate sql_middleware 

Source
Expand description

This crate provides a lightweight async wrapper for SQLite, PostgreSQL, LibSQL, Turso (experimental), and SQL Server (tiberius). The goal is a similar, async-compatible API consistent across databases.

§Features

  • Similar API regardless of backend (as much as possible)
  • Asynchronous (where available)
  • deadpool connection pooling (where available)
  • Transaction support
  • Not an ORM

§Feature Flags

Default features are sqlite and postgres. Enable others as needed:

# Only SQLite and LibSQL
sql-middleware = { version = "0", features = ["sqlite", "libsql"] }

# All backends
sql-middleware = { version = "0", features = ["sqlite", "postgres", "mssql", "libsql", "turso"] }

Additional flags:

  • libsql: LibSQL (local has been tested, remote is present)
  • turso: Turso (in-process, SQLite-compatible). Experimental; no remote support.
  • test-utils: Test helpers for internal testing
  • mssql: SQL Server via tiberius (untested, but present)
  • benchmarks: Criterion helpers for benches

§Example

use chrono::NaiveDateTime;
use sql_middleware::prelude::*;

pub struct ScoreChange {
    pub espn_id: i64,
    pub score: i32,
    pub updated_at: NaiveDateTime,
}

/// Update scores across any supported backend without copy/pasting per-database functions.
pub async fn set_scores_in_db(
    config_and_pool: &ConfigAndPool,
    updates: &[ScoreChange],
) -> Result<ResultSet, SqlMiddlewareDbError> {
    // Acquire a pooled connection (Postgres, SQLite, LibSQL, or Turso).
    let pool = config_and_pool.pool.get().await?;
    let mut conn = MiddlewarePool::get_connection(pool).await?;

    // Pick the appropriate placeholder syntax based on the backend.
    let (insert_sql, fetch_sql) = match &conn {
        MiddlewarePoolConnection::Postgres(_) => (
            "INSERT INTO scores (espn_id, score, updated_at) VALUES ($1, $2, $3)",
            "SELECT espn_id, score, updated_at FROM scores ORDER BY updated_at DESC LIMIT $1",
        ),
        MiddlewarePoolConnection::Sqlite(_)
        | MiddlewarePoolConnection::Libsql(_)
        | MiddlewarePoolConnection::Turso(_) => (
            "INSERT INTO scores (espn_id, score, updated_at) VALUES (?1, ?2, ?3)",
            "SELECT espn_id, score, updated_at FROM scores ORDER BY updated_at DESC LIMIT ?1",
        ),
        #[allow(unreachable_patterns)]
        _ => {
            return Err(SqlMiddlewareDbError::Unimplemented(
                "Backend not enabled in this build".to_string(),
            ))
        }
    };

    // Reuse the same binding logic for every backend.
    for change in updates {
        let params = vec![
            RowValues::Int(change.espn_id),
            RowValues::Int(i64::from(change.score)),
            RowValues::Timestamp(change.updated_at),
        ];
        let statement = QueryAndParams::new(insert_sql, params);
        conn.execute_dml(&statement.query, &statement.params).await?;
    }

    // Fetch the latest rows to confirm the write path succeeded.
    let limit = updates.len().max(1) as i64;
    let latest = QueryAndParams::new(fetch_sql, vec![RowValues::Int(limit)]);
    conn.execute_select(&latest.query, &latest.params).await
}

// For more in-depth examples (batch queries, AsyncDatabaseExecutor usage, benchmarks),
// see the project README: https://github.com/derekfrye/sql-middleware/blob/main/docs/README.md

Re-exports§

pub use middleware::AnyConnWrapper;
pub use middleware::AsyncDatabaseExecutor;
pub use middleware::ConfigAndPool;
pub use middleware::ConversionMode;
pub use middleware::CustomDbRow;
pub use middleware::DatabaseType;
pub use middleware::MiddlewarePool;
pub use middleware::MiddlewarePoolConnection;
pub use middleware::ParamConverter;
pub use middleware::QueryAndParams;
pub use middleware::ResultSet;
pub use middleware::RowValues;
pub use middleware::SqlMiddlewareDbError;
pub use conversion::convert_sql_params;
pub use exports::*;

Modules§

conversion
Parameter conversion utilities.
error
executor
exports
Database-specific type exports.
helpers
Helper utilities for testing and development.
middleware
pool
postgres
prelude
Convenient imports for common functionality.
query
results
test_helpers
types