ormer 0.2.4

A minimalist ORM framework that supports SQLite, PostgreSQL, MySQL, and SqlServer
Documentation
#![cfg(any(feature = "sqlite", feature = "postgresql", feature = "mysql"))]

pub mod _test_common;

// 使用宏定义测试专用模型(每个测试使用唯一表名)
define_test_user_simple!(ValidateTestUserSuccess, "validate_table_success_users_1");
define_test_user_simple!(
    ValidateTestUserNotExists,
    "validate_table_notexists_users_1"
);
define_test_user_simple!(
    ValidateTestUserNoValidation,
    "validate_table_novalidation_users_1"
);

#[cfg(feature = "postgresql")]
#[derive(Debug, ormer::Model, Clone)]
#[table = "validate_table_hypertable_mismatch_1"]
struct ValidateTestHypertable {
    #[primary]
    id: i32,
    #[hypertable(std::time::Duration::from_secs(3600))]
    created_at: chrono::NaiveDateTime,
    name: String,
}

#[cfg(any(feature = "sqlite", feature = "postgresql", feature = "mysql"))]
mod validate_table_tests {
    use super::*;
    use _test_common::{DbConfig, create_db_connection};

    async fn test_validate_table_success_impl(
        config: &DbConfig,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let db = create_db_connection(config).await?;

        // 先删除表(如果存在)
        db.drop_table::<ValidateTestUserSuccess>()
            .execute()
            .await
            .ok();

        // 创建表
        db.create_table::<ValidateTestUserSuccess>()
            .execute()
            .await?;

        // 验证表结构应该成功
        db.validate_table::<ValidateTestUserSuccess>().await?;

        println!("validate_table succeeded for existing table");

        // 清理
        db.drop_table::<ValidateTestUserSuccess>().execute().await?;

        Ok(())
    }

    async fn test_validate_table_not_exists_impl(
        config: &DbConfig,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let db = create_db_connection(config).await?;

        // 确保表不存在
        db.drop_table::<ValidateTestUserNotExists>()
            .execute()
            .await
            .ok();

        // 验证不存在的表应该失败
        // 验证表不存在时的错误处理
        let result = db.validate_table::<ValidateTestUserNotExists>().await;
        assert!(
            result.is_err(),
            "validate_table should fail for non-existent table"
        );

        // 错误已被包装为 ormer::OrmerError,只需验证它确实是错误
        println!("Correctly detected non-existent table: {:?}", result.err());

        Ok(())
    }

    async fn test_create_table_without_validation_impl(
        config: &DbConfig,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let db = create_db_connection(config).await?;

        // 先删除表(如果存在)
        db.drop_table::<ValidateTestUserNoValidation>()
            .execute()
            .await?;

        // 创建表(不应该进行验证)
        db.create_table::<ValidateTestUserNoValidation>()
            .execute()
            .await?;

        println!("create_table succeeded without validation");

        // 清理
        db.drop_table::<ValidateTestUserNoValidation>()
            .execute()
            .await?;

        Ok(())
    }

    #[cfg(feature = "postgresql")]
    async fn test_validate_table_hypertable_mismatch_impl(
        config: &DbConfig,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let db = create_db_connection(config).await?;

        db.drop_table::<ValidateTestHypertable>()
            .execute()
            .await
            .ok();
        db.execute_sql(
            r#"
            CREATE TABLE validate_table_hypertable_mismatch_1 (
                id INTEGER PRIMARY KEY,
                created_at TIMESTAMP NOT NULL,
                name VARCHAR(255) NOT NULL
            )
            "#,
        )
        .await?;

        let result = db.validate_table::<ValidateTestHypertable>().await;
        db.drop_table::<ValidateTestHypertable>().execute().await?;

        let error = result
            .expect_err("validate_table should reject a regular table for a hypertable model");
        assert!(
            format!("{error:?}").contains("Hypertable mismatch"),
            "unexpected error: {error:?}"
        );

        Ok(())
    }

    test_on_all_dbs_result!(test_validate_table_success_impl);
    test_on_all_dbs_result!(test_validate_table_not_exists_impl);
    test_on_all_dbs_result!(test_create_table_without_validation_impl);

    #[cfg(feature = "postgresql")]
    #[tokio::test]
    async fn test_postgresql_validate_table_hypertable_mismatch()
    -> Result<(), Box<dyn std::error::Error>> {
        let config = _test_common::postgresql_config();
        test_validate_table_hypertable_mismatch_impl(&config).await
    }
}