elif-orm 0.7.1

Production-ready ORM with migrations, database services, connection pooling, and query builder
Documentation
//! Relationship factory support for creating related models

use super::traits::{RelationshipFactory, RelationshipType};
use crate::error::OrmResult;
use crate::model::Model;

/// Factory for creating has_one relationships
#[derive(Debug)]
pub struct HasOneFactory<Parent, Related> {
    _phantom: std::marker::PhantomData<(Parent, Related)>,
}

impl<Parent, Related> Default for HasOneFactory<Parent, Related> {
    fn default() -> Self {
        Self::new()
    }
}

impl<Parent, Related> HasOneFactory<Parent, Related> {
    pub fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }
}

#[async_trait::async_trait]
impl<Parent, Related> RelationshipFactory<Parent, Related> for HasOneFactory<Parent, Related>
where
    Parent: Model + Send + Sync,
    Related: Model + Send + Sync,
{
    async fn create_for_parent(
        &self,
        _parent: &Parent,
        _pool: &sqlx::Pool<sqlx::Postgres>,
    ) -> OrmResult<Vec<Related>> {
        // TODO: Implement has_one relationship creation
        // This requires integration with the relationship system and model creation
        Ok(vec![])
    }

    async fn make_for_parent(&self, _parent: &Parent) -> OrmResult<Vec<Related>> {
        // TODO: Implement has_one relationship creation without saving
        Ok(vec![])
    }

    fn relationship_type(&self) -> RelationshipType {
        RelationshipType::HasOne
    }
}

/// Factory for creating has_many relationships
#[derive(Debug)]
pub struct HasManyFactory<Parent, Related> {
    count: usize,
    _phantom: std::marker::PhantomData<(Parent, Related)>,
}

impl<Parent, Related> HasManyFactory<Parent, Related> {
    pub fn new(count: usize) -> Self {
        Self {
            count,
            _phantom: std::marker::PhantomData,
        }
    }

    pub fn count(&self) -> usize {
        self.count
    }
}

#[async_trait::async_trait]
impl<Parent, Related> RelationshipFactory<Parent, Related> for HasManyFactory<Parent, Related>
where
    Parent: Model + Send + Sync,
    Related: Model + Send + Sync,
{
    async fn create_for_parent(
        &self,
        _parent: &Parent,
        _pool: &sqlx::Pool<sqlx::Postgres>,
    ) -> OrmResult<Vec<Related>> {
        // TODO: Implement has_many relationship creation
        // Create self.count instances of Related models linked to parent
        Ok(vec![])
    }

    async fn make_for_parent(&self, _parent: &Parent) -> OrmResult<Vec<Related>> {
        // TODO: Implement has_many relationship creation without saving
        Ok(vec![])
    }

    fn relationship_type(&self) -> RelationshipType {
        RelationshipType::HasMany
    }
}

/// Factory for creating belongs_to relationships
#[derive(Debug)]
pub struct BelongsToFactory<Child, Parent> {
    _phantom: std::marker::PhantomData<(Child, Parent)>,
}

impl<Child, Parent> Default for BelongsToFactory<Child, Parent> {
    fn default() -> Self {
        Self::new()
    }
}

impl<Child, Parent> BelongsToFactory<Child, Parent> {
    pub fn new() -> Self {
        Self {
            _phantom: std::marker::PhantomData,
        }
    }
}

#[async_trait::async_trait]
impl<Child, Parent> RelationshipFactory<Child, Parent> for BelongsToFactory<Child, Parent>
where
    Child: Model + Send + Sync,
    Parent: Model + Send + Sync,
{
    async fn create_for_parent(
        &self,
        _parent: &Child,
        _pool: &sqlx::Pool<sqlx::Postgres>,
    ) -> OrmResult<Vec<Parent>> {
        // TODO: Implement belongs_to relationship creation
        // For belongs_to, we might create a parent or use an existing one
        Ok(vec![])
    }

    async fn make_for_parent(&self, _parent: &Child) -> OrmResult<Vec<Parent>> {
        // TODO: Implement belongs_to relationship creation without saving
        Ok(vec![])
    }

    fn relationship_type(&self) -> RelationshipType {
        RelationshipType::BelongsTo
    }
}

/// Builder for relationship factories with method chaining
pub struct RelationshipBuilder<Parent, Related> {
    factories: Vec<Box<dyn RelationshipFactory<Parent, Related>>>,
    _phantom: std::marker::PhantomData<(Parent, Related)>,
}

impl<Parent, Related> Default for RelationshipBuilder<Parent, Related>
where
    Parent: crate::model::Model + 'static,
    Related: crate::model::Model + 'static,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<Parent, Related> RelationshipBuilder<Parent, Related>
where
    Parent: crate::model::Model + 'static,
    Related: crate::model::Model + 'static,
{
    pub fn new() -> Self {
        Self {
            factories: Vec::new(),
            _phantom: std::marker::PhantomData,
        }
    }

    pub fn has_one(mut self) -> Self {
        self.factories.push(Box::new(HasOneFactory::new()));
        self
    }

    pub fn has_many(mut self, count: usize) -> Self {
        self.factories.push(Box::new(HasManyFactory::new(count)));
        self
    }

    pub fn belongs_to(self) -> Self {
        // Type conversion needed for belongs_to
        // self.factories.push(Box::new(BelongsToFactory::new()));
        self
    }

    pub async fn create_all_for_parent(
        &self,
        parent: &Parent,
        pool: &sqlx::Pool<sqlx::Postgres>,
    ) -> OrmResult<Vec<Vec<Related>>>
    where
        Parent: Model + Send + Sync,
        Related: Model + Send + Sync,
    {
        let mut all_related = Vec::new();

        for factory in &self.factories {
            let related = factory.create_for_parent(parent, pool).await?;
            all_related.push(related);
        }

        Ok(all_related)
    }
}

/// Trait for models that support relationship factories
pub trait WithRelationships<Related: crate::model::Model> {
    /// Create relationships for this model
    fn with_relationships() -> RelationshipBuilder<Self, Related>
    where
        Self: crate::model::Model + Sized + 'static,
        Related: 'static,
    {
        RelationshipBuilder::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    // Mock model for testing
    #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
    struct MockModel;

    impl crate::model::Model for MockModel {
        type PrimaryKey = i32;

        fn table_name() -> &'static str {
            "mock_models"
        }

        fn primary_key(&self) -> Option<Self::PrimaryKey> {
            Some(1)
        }

        fn set_primary_key(&mut self, _key: Self::PrimaryKey) {
            // Mock implementation
        }

        fn to_fields(&self) -> std::collections::HashMap<String, serde_json::Value> {
            std::collections::HashMap::new()
        }

        fn from_row(_row: &sqlx::postgres::PgRow) -> crate::error::ModelResult<Self> {
            Ok(MockModel)
        }
    }

    #[test]
    fn test_relationship_factory_creation() {
        let has_one_factory: HasOneFactory<MockModel, MockModel> = HasOneFactory::new();
        assert_eq!(
            has_one_factory.relationship_type(),
            RelationshipType::HasOne
        );

        let has_many_factory: HasManyFactory<MockModel, MockModel> = HasManyFactory::new(5);
        assert_eq!(
            has_many_factory.relationship_type(),
            RelationshipType::HasMany
        );

        let belongs_to_factory: BelongsToFactory<MockModel, MockModel> = BelongsToFactory::new();
        assert_eq!(
            belongs_to_factory.relationship_type(),
            RelationshipType::BelongsTo
        );
    }

    #[test]
    fn test_relationship_builder() {
        let builder: RelationshipBuilder<MockModel, MockModel> =
            RelationshipBuilder::new().has_one().has_many(3);

        assert_eq!(builder.factories.len(), 2);
    }
}