use std::future::Future;
use super::{Db, Model};
use crate::Result;
pub trait Factory: Model {
fn definition() -> Self;
fn factory() -> FactoryBuilder<Self> {
FactoryBuilder {
count: 1,
steps: Vec::new(),
}
}
}
type Step<M> = Box<dyn FnMut(usize, &mut M) + Send>;
#[must_use = "a factory makes nothing until `make` or `create`"]
pub struct FactoryBuilder<M> {
count: usize,
steps: Vec<Step<M>>,
}
impl<M: Factory> FactoryBuilder<M> {
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn state(mut self, mut state: impl FnMut(&mut M) + Send + 'static) -> Self {
self.steps.push(Box::new(move |_, model| state(model)));
self
}
pub fn sequence(mut self, step: impl FnMut(usize, &mut M) + Send + 'static) -> Self {
self.steps.push(Box::new(step));
self
}
pub fn make(mut self) -> Vec<M> {
(0..self.count)
.map(|i| {
let mut model = M::definition();
for step in &mut self.steps {
step(i, &mut model);
}
model
})
.collect()
}
pub fn make_one(self) -> M {
self.count(1).make().pop().expect("one model")
}
pub fn create(self, db: &Db) -> impl Future<Output = Result<Vec<M>>> + Send + '_ {
let models = self.make();
async move {
let mut tx = db.begin().await?;
let mut saved = Vec::with_capacity(models.len());
for mut model in models {
model.insert(&mut tx).await?;
saved.push(model);
}
tx.commit().await?;
Ok(saved)
}
}
pub fn create_one(self, db: &Db) -> impl Future<Output = Result<M>> + Send + '_ {
let mut model = self.make_one();
async move {
model.insert(db).await?;
Ok(model)
}
}
}