Molders Service Kind

Overview

Molders are form-specific services responsible for data transformation between form data structures and domain model entities. They provide bidirectional mapping, change detection, and field-level transformation logic for different form operations like creation and updates.

Architecture

Core Components

Form-Specific Molders (src/srv/molders/) - Each form operation has its own dedicated molder (e.g., CreateGardenFormMolder, UpdateGardenFormMolder) - Molders are organized by operation type and entity - No base library - molders implement simple, focused transformation logic

Integration Points - Forms (src/dat/forms/): Source data structures from user input - Models (src/mdl/): Target domain entities - Handlers: Consumers of molder transformation results

Naming Convention

Molders follow a consistent naming pattern: - Create{Entity}FormMolder: For entity creation forms - Update{Entity}FormMolder: For entity update forms - Additional operation-specific molders as needed

Standard Methods

Every molder implements these standard transformation methods:

Form-to-Entity Transformation

ToEntity(form, entity) (*Entity, []string)
  • Transforms form data into domain model entity
  • Returns the modified entity and a list of changed field names
  • Handles validation and type conversion during transformation

Entity-to-Form Transformation

ToForm(form, entity) *Form
  • Populates form structure with data from domain entity
  • Used for pre-filling forms during edit operations
  • Ensures form reflects current entity state

Usage Examples

Creating Entities from Forms

// Transform form data to entity
entity := &mdl.Garden{}
garden, changes := createGardenMolder.ToEntity(form, entity)

// Changes list can be used for selective updates
fmt.Printf("Modified fields: %v", changes)

Pre-filling Edit Forms

// Load existing entity data into form
form := &forms.UpdateGardenForm{}
populatedForm := updateGardenMolder.ToForm(form, existingGarden)

Update Operations with Change Detection

// Transform update form, detecting changes
entity := existingGarden  // Load existing entity
updatedEntity, changes := updateGardenMolder.ToEntity(form, entity)

// Use changes list for optimized updates
if len(changes) > 0 {
    handler.UpdateFields(ctx, updatedEntity, changes, nil)
}

Change Detection

Update molders implement change detection logic:

Simple Field Comparison

func (this *UpdateGardenFormMolder) ToEntity(form *forms.UpdateGardenForm, entity *mdl.Garden) (*mdl.Garden, []string) {
    var changes []string

    if entity.Name != form.Name {
        entity.Name = form.Name
        changes = append(changes, "Name")
    }

    if entity.Picture != form.Picture {
        entity.Picture = form.Picture
        changes = append(changes, "Picture")
    }

    return entity, changes
}

Change List Usage

The returned changes list enables: - Optimized Updates: Only update modified fields in database - Audit Logging: Track which fields were changed - Validation: Apply field-specific validation rules - Event Triggers: Fire events for specific field changes

Form Types

Create Forms

  • Contain only fields needed for entity creation
  • No ID fields (generated by system)
  • All required fields for entity initialization
  • Example: CreateGardenForm{Name, Picture}

Update Forms

  • Include entity ID for targeting specific records
  • Contain all editable fields
  • Support partial updates through change detection
  • Example: UpdateGardenForm{Id, Name, Picture}

Data Flow

Creation Flow

  1. User submits creation form
  2. Binder extracts form data from request
  3. Form Validator validates input data
  4. Molder transforms form to entity
  5. Handler persists entity to database

Update Flow

  1. User submits update form
  2. Binder extracts form data from request
  3. Form Validator validates input data
  4. Fetcher retrieves existing entity
  5. Molder transforms form to entity with change detection
  6. Handler updates only changed fields

Integration with Framework

With Handlers

// Create operation
entity := &mdl.Garden{}
garden, _ := molder.ToEntity(form, entity)
createdGarden, err := handler.Create(ctx, garden, nil)

// Update operation
updatedGarden, changes := molder.ToEntity(form, existingGarden)
result, err := handler.UpdateFields(ctx, updatedGarden, changes, nil)

With Form Presenters

// Pre-fill form for editing
form := &forms.UpdateGardenForm{}
populatedForm := molder.ToForm(form, existingEntity)
presenter.Present(populatedForm)

Field Transformation Logic

Molders handle various transformation concerns: - Type Conversion: String to appropriate field types - Format Normalization: Standardizing input formats - Default Values: Setting defaults for missing fields - Field Mapping: Handling differences between form and entity field names

Error Handling

Molders typically don’t handle errors directly but rely on: - Form Validators: Pre-validate form data before molding - Type System: Go’s type system catches conversion errors - Business Logic: Downstream validation in handlers and entities