switchy_database 0.5.0

Switchy database package
#![cfg(all(feature = "sqlite-rusqlite", feature = "schema"))]

use std::sync::Arc;
use switchy_database::{
    Database,
    query::{JoinCondition, qualified_column},
    rusqlite::RusqliteDatabase,
    schema::{Column, DataType},
};

#[tokio::test]
async fn typed_join_preserves_equality_and_left_join_semantics() {
    let connection = rusqlite::Connection::open_in_memory().unwrap();
    let db = RusqliteDatabase::new(vec![Arc::new(switchy_async::sync::Mutex::new(connection))]);
    for table in ["parents", "children"] {
        db.create_table(table)
            .column(Column {
                name: "id".into(),
                data_type: DataType::BigInt,
                nullable: false,
                auto_increment: false,
                default: None,
            })
            .execute(&db)
            .await
            .unwrap();
    }
    for id in [1, 2] {
        db.insert("parents")
            .value("id", id)
            .execute(&db)
            .await
            .unwrap();
    }
    db.insert("children")
        .value("id", 1)
        .execute(&db)
        .await
        .unwrap();
    for (left, expected) in [(false, 1), (true, 2)] {
        let condition = (
            qualified_column("parents", "id"),
            qualified_column("children", "id"),
        );
        let query = db.select("parents");
        let query = if left {
            query.left_join("children", condition)
        } else {
            query.join("children", condition)
        };
        let rows = query.execute(&db).await.unwrap();
        assert_eq!(rows.len(), expected);
    }
    // A second ON condition must not filter unmatched parents out of a LEFT JOIN.
    let rows = db
        .select("parents")
        .left_join(
            "children",
            JoinCondition::And(vec![
                (
                    qualified_column("parents", "id"),
                    qualified_column("children", "id"),
                )
                    .into(),
                (
                    qualified_column("parents", "id"),
                    qualified_column("children", "rowid"),
                )
                    .into(),
            ]),
        )
        .execute(&db)
        .await
        .unwrap();
    assert_eq!(rows.len(), 2);
    for name in ["id OR 1=1 --", "id\" = 1 OR 1=1 --", "children.id"] {
        assert!(
            db.select("parents")
                .join(
                    "children",
                    (
                        qualified_column("parents", "id"),
                        qualified_column("children", name),
                    ),
                )
                .execute(&db)
                .await
                .is_err()
        );
    }
    for table in ["children ON 1=1 --", "children\" ON 1=1 --"] {
        assert!(
            db.select("parents")
                .left_join(
                    table,
                    (
                        qualified_column("parents", "id"),
                        qualified_column("children", "id"),
                    ),
                )
                .execute(&db)
                .await
                .is_err()
        );
    }
    db.close().await.unwrap();
}