# Relationers Service Kind

## Overview

Relationers are entity-specific services responsible for loading and distributing related data into domain model collections. They handle the actual data fetching for relationships and provide efficient batch loading with proper data distribution across entity collections.

## Architecture

### Core Components

**Base Relationer Library** (`src/lib/relationer/`)
- `Relationer` struct: Core relationship loading coordinator
- `RelationerMod`: Configuration object with fetcher modifications
- `Entity` interface: Common interface for entities with ID access

**Entity-Specific Relationers** (`src/srv/relationers/`)
- Each domain model has its own dedicated relationer (e.g., `GardenRelationer`, `UserRelationer`)
- All relationers follow the same interface pattern and method conventions
- Integrated with corresponding Fetcher services for data retrieval

### Key Structures

#### RelationerMod
Configuration object that controls relationship loading:
- **FetcherMod**: Embedded fetcher modification for query customization
- Passed through to underlying fetchers for filtering, ordering, etc.

#### Entity Interface
Common interface that all domain models implement:
```go
type Entity interface {
    GetId() string
}
```

## Standard Methods

Every entity relationer implements relationship-specific methods following these patterns:

### Hydrate Methods
```go
Hydrate{RelationshipName}(ctx, entities, mod) error
```
- Load related data and distribute it to entity collections
- Batch-optimized for loading relationships across multiple entities
- Handle empty collections and missing relationships gracefully

### Distribute Methods
```go
Distribute{RelationshipName}(ctx, entities, relatedData)
```
- Internal methods for distributing fetched data to appropriate entities
- Match related entities by foreign key relationships
- Append related data to entity relationship slices

### Conversion Methods
```go
convert{EntityName}ToEntities(entities) []relationer.Entity
```
- Convert typed entity collections to generic Entity interface
- Enable use of generic relationship loading utilities
- Support polymorphic relationship handling

## Usage Examples

### Loading Single Relationship
```go
// Load garden tasks for a collection of gardens
err := gardenRelationer.HydrateGardenTasks(ctx, gardens, nil)
// gardens[0].GardenTasks now contains related garden tasks
```

### Loading with Fetcher Modifications
```go
// Load plantations with specific filtering
mod := &relationer.RelationerMod{
    FetcherMod: plantationFetcher.Mod(),
}
mod.FetcherMod.ExactBooleanValueFilter("active", true)
err := gardenRelationer.HydratePlantations(ctx, gardens, mod)
```

### Multiple Relationship Loading
```go
// Load multiple relationships (typically done via Hydrators)
err = gardenRelationer.HydrateGardenTasks(ctx, gardens, nil)
if err != nil { return err }
err = gardenRelationer.HydratePlantations(ctx, gardens, nil)
if err != nil { return err }
```

## Relationship Loading Process

### 1. ID Extraction
```go
ids := this.Relationer.GetUniqueEntitiesIds(ctx, this.convertGardensToEntities(set))
if len(ids) == 0 {
    return nil  // No entities to process
}
```

### 2. Batch Data Fetching
```go
setToMerge, err := this.GardenTaskFetcher.FindSetInGardenIds(ctx, ids, this.Relationer.GetFetcherMod(mod))
if err != nil {
    return err
}
```

### 3. Data Distribution
```go
this.DistributeGardenTasks(ctx, set, setToMerge)
```

## Data Distribution Logic

Relationers implement efficient N+1 query prevention through batch loading:

### Foreign Key Matching
```go
func (this *GardenRelationer) DistributeGardenTasks(ctx context.Context, set []*mdl.Garden, setToMerge []*mdl.GardenTask) {
    for _, item := range set {
        for _, itemToMerge := range setToMerge {
            if item.Id == itemToMerge.GardenId {
                item.GardenTasks = append(item.GardenTasks, itemToMerge)
            }
        }
    }
}
```

### Unique ID Collection
The base `Relationer` provides utilities for collecting unique IDs:
- Eliminates duplicate IDs to prevent redundant fetching
- Handles empty/nil IDs gracefully
- Returns deduplicated ID collections for batch queries

## Integration with Framework

### With Fetchers
Relationers delegate data retrieval to appropriate Fetchers:
```go
setToMerge, err := this.PlantationFetcher.FindSetInGardenIds(ctx, ids, fetcherMod)
```

### With Hydrators
Hydrators orchestrate multiple Relationers for complete entity hydration:
```go
// In GardenHydrator.Many()
if mod.Contains("garden_tasks") {
    this.GardenRelationer.HydrateGardenTasks(ctx, entities, nil)
}
```

## Performance Optimization

### Batch Loading
- Single query per relationship type regardless of entity count
- Prevents N+1 query problems common in ORM systems
- Efficiently handles large entity collections

### Early Exit Conditions
- Skip processing when no entities are provided
- Return early when entity collections are empty
- Avoid unnecessary database queries

### Memory Efficiency
- Stream processing of relationship data
- In-place entity modification rather than copying
- Efficient ID deduplication using maps

## Error Handling

- Propagate fetcher errors to calling code
- Handle missing relationships gracefully (empty slices)
- Maintain entity integrity when relationship loading fails
- Support partial success scenarios

## Relationship Types

Relationers handle various relationship patterns:
- **One-to-Many**: Parent entity with multiple child entities
- **Many-to-One**: Child entities referencing parent entity
- **Many-to-Many**: Junction table relationships (through intermediate fetchers)
- **Nested Relationships**: Multi-level relationship chains