#![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 = "sqlite")]
#[derive(Debug, ormer::Model, Clone)]
#[table = "validate_table_primary_key_mismatch_1"]
struct ValidateTestPrimaryKeyMismatch {
#[primary]
id: i32,
name: String,
}
#[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(feature = "postgresql")]
#[derive(Debug, ormer::Model, Clone)]
#[table = "validate_table_hypertable_interval_mismatch_1"]
struct ValidateTestHypertableInterval {
#[primary]
id: i32,
#[primary]
#[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"
);
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 = "sqlite")]
#[tokio::test]
async fn test_sqlite_validate_table_detects_primary_key_mismatch()
-> Result<(), Box<dyn std::error::Error>> {
let db = create_db_connection(&_test_common::sqlite_config()).await?;
db.drop_table::<ValidateTestPrimaryKeyMismatch>()
.execute()
.await
.ok();
db.execute_sql(
"CREATE TABLE validate_table_primary_key_mismatch_1 \
(id INTEGER NOT NULL, name TEXT NOT NULL)",
)
.await?;
let result = db.validate_table::<ValidateTestPrimaryKeyMismatch>().await;
db.drop_table::<ValidateTestPrimaryKeyMismatch>()
.execute()
.await?;
let error = result.expect_err("primary-key mismatch must be detected");
assert!(error.to_string().contains("Primary key mismatch"));
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(())
}
#[cfg(feature = "postgresql")]
async fn test_validate_table_hypertable_interval_mismatch_impl(
config: &DbConfig,
) -> Result<(), Box<dyn std::error::Error>> {
let db = create_db_connection(config).await?;
db.drop_table::<ValidateTestHypertableInterval>()
.execute()
.await
.ok();
db.execute_sql(
r#"
CREATE TABLE validate_table_hypertable_interval_mismatch_1 (
id INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id, created_at)
)
"#,
)
.await?;
let create_result = db
.execute_sql(
"SELECT create_hypertable('validate_table_hypertable_interval_mismatch_1', 'created_at', chunk_time_interval => INTERVAL '2 hours', if_not_exists => TRUE, migrate_data => TRUE)",
)
.await;
if let Err(error) = create_result {
db.drop_table::<ValidateTestHypertableInterval>()
.execute()
.await
.ok();
let message = format!("{error:?}").to_lowercase();
if message.contains("create_hypertable")
&& (message.contains("function") || message.contains("函数"))
{
return Ok(());
}
return Err(Box::new(error));
}
let result = db.validate_table::<ValidateTestHypertableInterval>().await;
db.drop_table::<ValidateTestHypertableInterval>()
.execute()
.await?;
let error = result.expect_err(
"validate_table should reject a hypertable with a different chunk interval",
);
assert!(
format!("{error:?}").contains("Hypertable dimension 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
}
#[cfg(feature = "postgresql")]
#[tokio::test]
async fn test_postgresql_validate_table_hypertable_interval_mismatch()
-> Result<(), Box<dyn std::error::Error>> {
let config = _test_common::postgresql_config();
test_validate_table_hypertable_interval_mismatch_impl(&config).await
}
}