use dbnexus::MigrationHistory;
use dbnexus::foundation::DatabaseType;
#[path = "../../common/mod.rs"]
mod common;
fn table_exists_check_sql(db_type: DatabaseType, table_name: &str) -> String {
match db_type {
DatabaseType::Sqlite => format!(
"SELECT name FROM sqlite_master WHERE type='table' AND name='{}'",
table_name
),
DatabaseType::Postgres => format!(
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_name='{}'",
table_name
),
DatabaseType::MySql => format!(
"SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name='{}'",
table_name
),
DatabaseType::DuckDb => format!(
"SELECT table_name FROM information_schema.tables WHERE table_name='{}'",
table_name
),
}
}
#[tokio::test]
async fn test_migration_executor_creation() {
let (pool, _temp_dir) = common::create_test_pool().await.expect("Failed to create test pool");
let session = pool.get_session("admin").await.expect("Failed to get session");
let _conn = session.connection().expect("Connection should be available");
let table_name = format!(
"migration_test_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
);
session
.execute_raw_ddl(&format!(
"CREATE TABLE IF NOT EXISTS {} (id INTEGER PRIMARY KEY, name TEXT)",
table_name
))
.await
.expect("Should be able to create table");
let _ = session
.execute_raw_ddl(&format!("DROP TABLE IF EXISTS {}", table_name))
.await;
}
#[tokio::test]
async fn test_migration_apply() {
let (pool, _temp_dir) = common::create_test_pool().await.expect("Failed to create test pool");
let session = pool.get_session("admin").await.expect("Failed to get session");
let table_name = format!(
"migration_apply_test_{}",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
);
session
.execute_raw_ddl(&format!(
"CREATE TABLE IF NOT EXISTS {} (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)",
table_name
))
.await
.expect("Migration should apply successfully");
let check_sql = table_exists_check_sql(pool.config().database_type().unwrap(), &table_name);
let result = session.execute_raw(&check_sql).await;
assert!(result.is_ok(), "Migration should be applied");
let _ = session
.execute_raw_ddl(&format!("DROP TABLE IF EXISTS {}", table_name))
.await;
}
#[test]
fn test_migration_history_creation() {
let history = MigrationHistory::new();
assert!(history.applied_migrations.is_empty());
assert_eq!(history.get_latest_version(), None);
}
#[test]
fn test_migration_history_add() {
let mut history = MigrationHistory::new();
let migration = dbnexus::MigrationVersion {
version: 1,
description: "Initial migration".to_string(),
applied_at: time::OffsetDateTime::now_utc(),
file_path: "migrations/001_initial.sql".to_string(),
};
history.add_migration(migration);
assert_eq!(history.applied_migrations.len(), 1);
assert_eq!(history.get_latest_version(), Some(1));
}
#[tokio::test]
async fn test_migration_executor_first_run() {
use dbnexus::MigrationExecutor;
use std::io::Write;
use tempfile::TempDir;
let (pool, _temp_dir) = common::create_test_pool().await.expect("Failed to create test pool");
let session = pool.get_session("admin").await.expect("Failed to get session");
let conn = session.connection().expect("Connection should be available");
let migration_dir = TempDir::new().expect("Failed to create temp dir");
let migration_file_path = migration_dir.path().join("001_create_test_table.sql");
let mut file = std::fs::File::create(&migration_file_path).expect("Failed to create migration file");
let table_suffix = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis();
writeln!(
file,
"-- UP\nCREATE TABLE test_first_run_{} (id INTEGER PRIMARY KEY);",
table_suffix
)
.expect("Failed to write migration file");
drop(file);
let db_type = pool.config().database_type().unwrap();
let mut executor = MigrationExecutor::new(conn.clone(), db_type);
assert!(executor.history().applied_migrations.is_empty());
let result = executor.run_migrations(migration_dir.path()).await;
assert!(result.is_ok(), "Migration should succeed on first run");
assert_eq!(result.unwrap(), 1, "One migration should be applied");
assert_eq!(executor.history().applied_migrations.len(), 1);
assert_eq!(executor.get_latest_migration().map(|m| m.version), Some(1));
let result = executor.run_migrations(migration_dir.path()).await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 0, "No migration should be applied on second run");
let _ = session
.execute_raw_ddl(&format!("DROP TABLE IF EXISTS test_first_run_{}", table_suffix))
.await;
}