Skip to main content

Crate factory_m8_derive

Crate factory_m8_derive 

Source
Expand description

Factory Derive Macros

Generates factory boilerplate for test entities with automatic FK resolution.

§Example Usage

use factory_m8::FactoryCreate;
use factory_derive::Factory;

#[derive(Debug, Default, Factory)]
#[factory(entity = Patient)]
pub struct PatientFactory {
    #[pk]
    pub id: PatientId,

    // Option<T> FK - auto-creates if None/sentinel, result is Some(id)
    // Factory field type should match entity field type
    #[fk(Practice, "id", PracticeFactory)]
    pub practice_id: Option<PracticeId>,

    // Non-Option FK - auto-creates if is_sentinel() returns true
    // Default impl typically sets to sentinel value (e.g., Id(0))
    #[fk(Tenant, "id", TenantFactory)]
    pub tenant_id: TenantId,

    // Option<T> FK with no_default - won't auto-create, None stays None
    // Use for truly optional FKs where entity field is also Option
    #[fk(Provider, "id", ProviderFactory, no_default)]
    pub provider_id: Option<ProviderId>,

    // Non-Option field - used directly (provide in Default impl)
    pub name: String,

    // Option field - cloned as-is (truly optional)
    pub nickname: Option<String>,
}

// User implements just the INSERT
impl FactoryCreate for PatientFactory {
    type Entity = Patient;

    async fn create(self, pool: &PgPool) -> Result<Patient, Box<dyn Error + Send + Sync>> {
        let entity = self.build_with_fks(pool).await?;
        sqlx::query_as!(Patient, "INSERT INTO patient ...")
            .fetch_one(pool).await
    }
}

§Attributes

  • #[factory(entity = EntityType)] - Specifies the entity type this factory creates
  • #[pk] - Primary key field, uses Default::default()
  • #[fk(Entity, "field", Factory)] - FK field, optionality based on field type:
    • Option<T>: auto-creates if None/unset, returns Some(id)
    • T (non-Option): auto-creates if is_unset(), returns id
  • #[fk(Entity, "field", Factory, no_default)] - Don’t auto-create, None stays None

§FK Field Types

FK field type determines behavior in build_with_fks():

  • Option<IdType>: Auto-creates if None or sentinel, returns Some(created_id). Use no_default flag to disable auto-creation (None stays None).

  • IdType (non-Option): Auto-creates if is_sentinel() returns true. Default impl should set to sentinel value (e.g., Id(0)).

Important: Factory field type should match entity field type.

§Generated Methods

  • new() - Creates factory with default values
  • with_<entity>(&Entity) - Sets FK from entity reference
  • with_<field>_id(Id) - Sets FK ID directly
  • with_<field>(value) - Sets field value (for Option and non-Option fields)
  • build() - Creates entity in-memory (clones Option FK fields as-is)
  • build_with_fks(pool) - Creates entity, auto-creating FK dependencies if needed

Derive Macros§

Factory