serde-sqlx 0.0.1

Allows deserializing Postgres rows into Rust types using serde
Documentation
mod util;

use serde::Deserialize;
use util::{fetch_all, fetch_one};

#[derive(Debug, Deserialize, PartialEq)]
pub struct QueryStats {
    pub query: String,
    pub calls: i64,
    pub total_exec_time: f64,
    pub mean_exec_time: f64,
    pub rows: i64,
    pub total_blocks: i64,
}

#[tokio::test]
async fn test_single_query_stats() {
    // Test that a single row can be fetched and deserialized into QueryStats.
    let stats: QueryStats = fetch_one(
        r#"
            SELECT
                'dummy query' AS query,
                10 AS calls,
                123.45 AS total_exec_time,
                12.34 AS mean_exec_time,
                100 AS rows,
                256 AS total_blocks
        "#,
    )
    .await
    .unwrap();

    assert_eq!(
        stats,
        QueryStats {
            query: "dummy query".to_owned(),
            calls: 10,
            total_exec_time: 123.45,
            mean_exec_time: 12.34,
            rows: 100,
            total_blocks: 256,
        }
    );
}

#[tokio::test]
async fn test_multiple_query_stats() {
    // Test that multiple rows can be fetched and deserialized into a Vec<QueryStats>.
    let rows: Vec<QueryStats> = fetch_all(
        r#"
            SELECT * FROM (
                SELECT 'query1' AS query, 5 AS calls, 200.0 AS total_exec_time, 40.0 AS mean_exec_time, 50 AS rows, 300 AS total_blocks
                UNION ALL
                SELECT 'query2', 15, 400.0, 26.67, 80, 500
            ) T
        "#,
    )
    .await
    .unwrap();

    assert_eq!(
        rows,
        vec![
            QueryStats {
                query: "query1".to_owned(),
                calls: 5,
                total_exec_time: 200.0,
                mean_exec_time: 40.0,
                rows: 50,
                total_blocks: 300,
            },
            QueryStats {
                query: "query2".to_owned(),
                calls: 15,
                total_exec_time: 400.0,
                mean_exec_time: 26.67,
                rows: 80,
                total_blocks: 500,
            },
        ]
    );
}

#[tokio::test]
async fn test_query_stats_from_json_field() -> anyhow::Result<()> {
    // Test deserializing a JSON field into an inner QueryStats struct.
    #[derive(Debug, Deserialize, PartialEq)]
    struct Wrapper {
        query_stats: QueryStats,
    }

    let out: Vec<Wrapper> = fetch_all(
        r#"
            SELECT row_to_json(q) AS query_stats FROM (
                SELECT
                    'dummy query' AS query,
                    10 AS calls,
                    123.45 AS total_exec_time,
                    12.34 AS mean_exec_time,
                    100 AS rows,
                    256 AS total_blocks
            ) q
        "#,
    )
    .await?;

    assert_eq!(
        out,
        vec![Wrapper {
            query_stats: QueryStats {
                query: "dummy query".to_owned(),
                calls: 10,
                total_exec_time: 123.45,
                mean_exec_time: 12.34,
                rows: 100,
                total_blocks: 256,
            }
        }]
    );

    Ok(())
}