use crate::error::{OrmError, OrmResult};
use crate::model::{CrudOperations, Model};
use once_cell::sync::Lazy;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::RwLock;
pub mod fake_data;
pub mod relationships;
pub mod seeder;
pub mod states;
pub mod traits;
pub use seeder::Seeder;
pub use traits::{FactoryState, RelationshipFactory};
#[async_trait::async_trait]
pub trait Factory<T: Model>: Send + Sync {
fn new() -> Self
where
Self: Sized;
async fn definition(&self) -> OrmResult<HashMap<String, Value>>;
async fn make(&self) -> OrmResult<T>;
async fn create(&self, pool: &sqlx::Pool<sqlx::Postgres>) -> OrmResult<T>;
async fn make_many(&self, count: usize) -> OrmResult<Vec<T>>;
async fn create_many(
&self,
pool: &sqlx::Pool<sqlx::Postgres>,
count: usize,
) -> OrmResult<Vec<T>>;
fn with_attributes(self, attributes: HashMap<String, Value>) -> FactoryBuilder<T, Self>
where
Self: Sized,
{
FactoryBuilder::new(self, attributes)
}
fn state<S: FactoryState<T>>(self, state: S) -> StateBuilder<T, Self, S>
where
Self: Sized,
{
StateBuilder::new(self, state)
}
}
pub struct FactoryBuilder<T: Model, F: Factory<T>> {
factory: F,
attributes: HashMap<String, Value>,
_phantom: std::marker::PhantomData<T>,
}
impl<T: Model, F: Factory<T>> FactoryBuilder<T, F> {
pub fn new(factory: F, attributes: HashMap<String, Value>) -> Self {
Self {
factory,
attributes,
_phantom: std::marker::PhantomData,
}
}
pub fn with(mut self, key: &str, value: Value) -> Self {
self.attributes.insert(key.to_string(), value);
self
}
pub async fn make(&self) -> OrmResult<T> {
let mut base_attributes = self.factory.definition().await?;
for (key, value) in &self.attributes {
base_attributes.insert(key.clone(), value.clone());
}
Err(OrmError::Validation(
"Factory make not yet implemented".to_string(),
))
}
pub async fn create(&self, pool: &sqlx::Pool<sqlx::Postgres>) -> OrmResult<T> {
let model = self.make().await?;
T::create(pool, model).await
}
}
pub struct StateBuilder<T: Model, F: Factory<T>, S: FactoryState<T>> {
factory: F,
state: S,
_phantom: std::marker::PhantomData<T>,
}
impl<T: Model, F: Factory<T>, S: FactoryState<T>> StateBuilder<T, F, S> {
pub fn new(factory: F, state: S) -> Self {
Self {
factory,
state,
_phantom: std::marker::PhantomData,
}
}
pub async fn make(&self) -> OrmResult<T> {
let mut attributes = self.factory.definition().await?;
self.state.apply(&mut attributes).await?;
Err(OrmError::Validation(
"State make not yet implemented".to_string(),
))
}
pub async fn create(&self, pool: &sqlx::Pool<sqlx::Postgres>) -> OrmResult<T> {
let model = self.make().await?;
T::create(pool, model).await
}
}
#[derive(Default)]
pub struct FactoryRegistry {
factories: HashMap<String, Box<dyn std::any::Any + Send + Sync>>,
}
impl FactoryRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register<T: Model, F: Factory<T> + 'static>(&mut self, factory: F) {
self.factories
.insert(T::table_name().to_string(), Box::new(factory));
}
pub fn get<T: Model, F: Factory<T> + 'static>(&self) -> Option<&F> {
self.factories
.get(T::table_name())
.and_then(|f| f.downcast_ref::<F>())
}
pub async fn create<T: Model>(&self, _pool: &sqlx::Pool<sqlx::Postgres>) -> OrmResult<T>
where
T: 'static,
{
Err(OrmError::Validation(
"Registry create not yet implemented".to_string(),
))
}
pub fn factory_count(&self) -> usize {
self.factories.len()
}
}
static FACTORY_REGISTRY: Lazy<RwLock<FactoryRegistry>> =
Lazy::new(|| RwLock::new(FactoryRegistry::new()));
pub fn factory_registry() -> std::sync::RwLockReadGuard<'static, FactoryRegistry> {
FACTORY_REGISTRY.read().unwrap()
}
pub fn factory_registry_mut() -> std::sync::RwLockWriteGuard<'static, FactoryRegistry> {
FACTORY_REGISTRY.write().unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factory_registry_creation() {
let registry = FactoryRegistry::new();
assert_eq!(registry.factories.len(), 0);
}
#[test]
fn test_factory_builder_creation() {
assert!(true);
}
}