# Hydrators Service Kind

## Overview

Hydrators are entity-specific services responsible for populating related data into domain models. They manage the loading of relationships and nested data structures, providing different presets for various use cases like list views, detail views, and API responses.

## Architecture

### Core Components

**Base Hydrator Library** (`src/lib/hydrator/`)
- `Hydrator` struct: Core hydration coordinator
- `HydratorMod`: Configuration object containing hydration paths and options
- `HydratingPath`: Represents specific relationship paths to load

**Entity-Specific Hydrators** (`src/srv/hydrators/`)
- Each domain model has its own dedicated hydrator (e.g., `GardenHydrator`, `UserHydrator`)
- All hydrators follow the same interface pattern and method conventions
- Integrated with corresponding Relationer services for actual data loading

### Key Structures

#### HydratorMod
Configuration object that controls hydration behavior:
- **Paths**: Array of `HydratingPath` objects specifying which relationships to load
- **Contains()**: Method to check if a specific relationship path should be loaded

#### HydratingPath
Represents a relationship loading specification:
- **Path**: Array of strings defining the relationship chain to hydrate
- Supports nested relationship loading (e.g., `["garden", "plantations", "plants"]`)

## Standard Methods

Every entity hydrator implements these standard methods:

### Core Hydration Methods
```go
Many(ctx, entities, mod) error                 // Hydrate multiple entities
One(ctx, entity, mod) error                    // Hydrate single entity
```

### Preset-Based Methods
```go
OneViaPreset(ctx, entity, preset, mod) error          // Hydrate single entity with preset
MustOneViaPreset(ctx, entity, preset, mod)            // Hydrate with panic on error
ManyViaPreset(ctx, entities, preset, mod) error       // Hydrate multiple entities with preset
MustManyViaPreset(ctx, entities, preset, mod)         // Hydrate multiple with panic on error
```

### Internal Methods
```go
presetSwitch(preset, mod)                      // Apply preset configuration to mod
showPreset(mod)                                // Configure mod for detail views
listPreset(mod)                                // Configure mod for list views
oneRelations(mod)                              // Add single-entity relationships
selfRelations(mod)                             // Add self-contained relationships
```

## Usage Examples

### Basic Entity Hydration
```go
// Hydrate specific relationships
mod := &hydrator.HydratorMod{}
mod.AddHydratingPath("garden_tasks")
mod.AddHydratingPath("plantations")
err := gardenHydrator.One(ctx, garden, mod)
```

### Preset-Based Hydration
```go
// Use predefined hydration preset
err := gardenHydrator.OneViaPreset(ctx, garden, "show", nil)

// Hydrate multiple entities for list display
err := gardenHydrator.ManyViaPreset(ctx, gardens, "list", nil)
```

### Custom Hydration Paths
```go
mod := &hydrator.HydratorMod{}
mod.AddHydratingPath("plantations", "plants")  // Nested relationship
mod.AddHydratingPath("garden_tasks", "assignee")  // Deep relationship
err := gardenHydrator.One(ctx, garden, mod)
```

## Hydration Presets

Hydrators support predefined hydration presets for common use cases:

### Standard Presets
- **"show"**: Detail view hydration - loads comprehensive related data for entity display
- **"list"**: List view hydration - loads minimal related data for efficient list rendering

### Preset Configuration
Each preset configures the `HydratorMod` with appropriate relationship paths:
```go
func (this *GardenHydrator) showPreset(mod *hydrator.HydratorMod) {
    this.oneRelations(mod)  // Load detail-specific relationships
}

func (this *GardenHydrator) listPreset(mod *hydrator.HydratorMod) {
    this.selfRelations(mod)  // Load list-optimized relationships
}
```

## Integration with Relationers

Hydrators delegate actual data loading to Relationer services:
- Use `EntityRelationer.HydrateRelationshipName()` methods for loading related data
- Manage the orchestration of multiple relationship loads
- Handle conditional loading based on `HydratorMod` configuration

## Relationship Loading Logic

Hydrators use conditional loading based on the `HydratorMod` configuration:
```go
func (this *GardenHydrator) Many(ctx context.Context, entities []*mdl.Garden, mod *hydrator.HydratorMod) error {
    if mod.Contains("garden_tasks") {
        this.GardenRelationer.HydrateGardenTasks(ctx, entities, nil)
    }
    if mod.Contains("plantations") {
        this.GardenRelationer.HydratePlantations(ctx, entities, nil)
    }
    return nil
}
```

## Error Handling

- Standard methods return errors for caller handling
- Must* methods panic on errors (using `lib.Poe()`)
- Relationship loading errors bubble up from Relationists
- Failed hydrations don't modify the original entities

## Performance Considerations

- **Selective Loading**: Only loads explicitly requested relationships
- **Batch Loading**: `Many()` methods optimize for loading relationships across multiple entities
- **Preset Optimization**: Presets are tuned for specific use cases to minimize over-fetching
- **Conditional Logic**: Avoids unnecessary database queries when relationships aren't requested