use std::future::Future;
use std::pin::Pin;
use crate::orm::Connection;
pub type SeederResult<'a> =
Pin<Box<dyn Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>> + Send + 'a>>;
pub trait Seeder: Send + Sync {
fn name(&self) -> &str;
fn run<'a>(&'a self, conn: &'a mut Box<dyn Connection>) -> SeederResult<'a>;
}
pub struct SeedRunner {
seeders: Vec<Box<dyn Seeder>>,
}
impl SeedRunner {
pub fn new() -> Self {
Self {
seeders: Vec::new(),
}
}
pub fn register(&mut self, seeder: Box<dyn Seeder>) -> &mut Self {
self.seeders.push(seeder);
self
}
pub async fn execute(
&self,
conn: &mut Box<dyn Connection>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
for seeder in &self.seeders {
println!("[Seed] Running {}...", seeder.name());
seeder.run(conn).await?;
println!("[Seed] {} completed.", seeder.name());
}
Ok(())
}
pub fn len(&self) -> usize {
self.seeders.len()
}
pub fn is_empty(&self) -> bool {
self.seeders.is_empty()
}
}
impl Default for SeedRunner {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
struct CounterSeeder {
name: String,
counter: Arc<AtomicUsize>,
}
impl Seeder for CounterSeeder {
fn name(&self) -> &str {
&self.name
}
fn run<'a>(&'a self, _conn: &'a mut Box<dyn Connection>) -> SeederResult<'a> {
Box::pin(async move {
self.counter.fetch_add(1, Ordering::SeqCst);
Ok(())
})
}
}
#[test]
fn test_seed_runner_register_and_len() {
let counter = Arc::new(AtomicUsize::new(0));
let mut runner = SeedRunner::new();
assert_eq!(runner.len(), 0);
assert!(runner.is_empty());
runner.register(Box::new(CounterSeeder {
name: "A".to_string(),
counter: counter.clone(),
}));
runner.register(Box::new(CounterSeeder {
name: "B".to_string(),
counter: counter.clone(),
}));
assert_eq!(runner.len(), 2);
assert!(!runner.is_empty());
}
#[test]
fn test_seed_runner_default() {
let runner = SeedRunner::default();
assert!(runner.is_empty());
}
}