puerto 0.10.0

Puerto — Rust full-stack DDD framework CLI. Scaffolds Clean Architecture projects with auto-wired DI, SQLx support, and zero manual wiring. Formerly puerto-framework.
use std::sync::Arc;

use async_trait::async_trait;
{% for imp in extra_imports %}{{ imp }}
{% endfor %}
use crate::domain::{{ snake }}::{
    errors::{{ pascal }}Error,
    model::{{ model_import }},
    repository::{{ pascal }}RepositoryTrait,
    use_cases::create_{{ snake }}::{Create{{ pascal }}Params, Create{{ pascal }}UseCaseTrait},
};

pub struct Create{{ pascal }}UseCaseImpl {
    pub repository: Arc<dyn {{ pascal }}RepositoryTrait>,
}

#[async_trait]
impl Create{{ pascal }}UseCaseTrait for Create{{ pascal }}UseCaseImpl {
    async fn execute(&self, params: Create{{ pascal }}Params) -> Result<{{ pascal }}, {{ pascal }}Error> {
        tracing::info!("create_{{ snake }}: start");
{% if vo_constructions %}{{ vo_constructions }}{% endif %}        let entity = {{ pascal }}::new({{ pascal }}Props {
{{ props_fields }}
        }).inspect_err(|e| tracing::warn!(error = %e, "create_{{ snake }}: rejected"))?;
        self.repository.save(&entity).await.inspect_err(|e| tracing::error!(error = %e, "create_{{ snake }}: repository failed"))?;
        tracing::info!(id = %entity.id, "create_{{ snake }}: done");
        Ok(entity)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::domain::{{ snake }}::repository::mocks::Mock{{ pascal }}Repository;
{{ test_imports }}

    #[tokio::test]
    async fn {{ valid_test_name }}() {
        // Arrange
        let mut mock_repo = Mock{{ pascal }}Repository::new();
        mock_repo.expect_save().returning(|_| Ok(()));
        let use_case = Create{{ pascal }}UseCaseImpl {
            repository: Arc::new(mock_repo),
        };

        // Act
        let result = use_case
            .execute(Create{{ pascal }}Params {
{{ valid_params }}
            })
            .await;

        // Assert
        assert!(result.is_ok());{{ valid_assertion }}
    }
{% for tc in validation_test_cases %}
    #[tokio::test]
    async fn {{ tc.test_name }}() {
        // Arrange
        let mock_repo = Mock{{ pascal }}Repository::new();
        let use_case = Create{{ pascal }}UseCaseImpl {
            repository: Arc::new(mock_repo),
        };

        // Act
        let result = use_case
            .execute(Create{{ pascal }}Params {
{{ tc.empty_params }}
            })
            .await;

        // Assert
        assert!(result.is_err());
        assert_eq!(
            result.unwrap_err().to_string(),
            "{{ tc.error_str }}"
        );
    }
{% endfor %}}