# `Sinter.Validator`
[🔗](https://github.com/nshkrdotcom/sinter/blob/v0.2.0/lib/sinter/validator.ex#L1)

The unified validation engine for Sinter.

This module provides the single validation pipeline that handles all types
of validation in Sinter. It processes schemas created by `Sinter.Schema.define/2`
and runs a clean, predictable validation process.

## Validation Pipeline

1. **Input Validation** - Ensure input is valid format
2. **Required Field Check** - Verify all required fields are present
3. **Field Validation** - Validate each field against its type and constraints
4. **Strict Mode Check** - Reject unknown fields if strict mode enabled
5. **Post Validation** - Run custom cross-field validation if configured

## Design Philosophy

The validator focuses purely on validation - it does NOT perform data transformation.
Any data transformation should be explicit in your application code, keeping
your validation logic pure and your transformations visible.

## Usage

    schema = Sinter.Schema.define([
      {:name, :string, [required: true, min_length: 2]},
      {:age, :integer, [optional: true, gt: 0]}
    ])

    # Basic validation
    {:ok, validated} = Sinter.Validator.validate(schema, %{name: "Alice", age: 30})

    # With coercion
    {:ok, validated} = Sinter.Validator.validate(schema, %{name: "Alice", age: "30"}, coerce: true)

    # Batch validation
    data_list = [%{name: "Alice", age: 30}, %{name: "Bob", age: 25}]
    {:ok, validated_list} = Sinter.Validator.validate_many(schema, data_list)

# `validation_opts`

```elixir
@type validation_opts() :: [
  coerce: boolean(),
  strict: boolean(),
  path: [atom() | String.t() | integer()]
]
```

# `validation_result`

```elixir
@type validation_result() :: {:ok, map()} | {:error, [Sinter.Error.t()]}
```

# `validate`

```elixir
@spec validate(Sinter.Schema.t(), map(), validation_opts()) :: validation_result()
```

Validates data against a Sinter schema.

This is the core validation function that all other validation in Sinter
ultimately uses. It implements a clean, predictable pipeline.

## Parameters

  * `schema` - A schema created by `Sinter.Schema.define/2`
  * `data` - The data to validate (must be a map)
  * `opts` - Validation options

## Options

  * `:coerce` - Enable type coercion (default: false)
  * `:strict` - Override schema's strict setting
  * `:path` - Base path for error reporting (default: [])

## Returns

  * `{:ok, validated_data}` - Validation succeeded
  * `{:error, errors}` - List of validation errors

## Examples

    iex> schema = Sinter.Schema.define([
    ...>   {:name, :string, [required: true]},
    ...>   {:age, :integer, [optional: true, gt: 0]}
    ...> ])
    iex> Sinter.Validator.validate(schema, %{name: "Alice", age: 30})
    {:ok, %{name: "Alice", age: 30}}

    iex> Sinter.Validator.validate(schema, %{age: 30})
    {:error, [%Sinter.Error{path: [:name], code: :required, ...}]}

# `validate!`

```elixir
@spec validate!(Sinter.Schema.t(), map(), validation_opts()) :: map() | no_return()
```

Validates data against a schema, raising an exception on failure.

## Examples

    iex> validated = Sinter.Validator.validate!(schema, data)
    %{name: "Alice", age: 30}

    # Raises Sinter.ValidationError on failure

# `validate_many`

```elixir
@spec validate_many(Sinter.Schema.t(), [map()], validation_opts()) ::
  {:ok, [map()]} | {:error, %{required(integer()) =&gt; [Sinter.Error.t()]}}
```

Validates multiple data items against the same schema efficiently.

## Parameters

  * `schema` - Schema to validate against
  * `data_list` - List of data maps to validate
  * `opts` - Validation options

## Returns

  * `{:ok, validated_list}` if all validations succeed
  * `{:error, errors_by_index}` if any validation fails

## Examples

    iex> data_list = [
    ...>   %{name: "Alice", age: 30},
    ...>   %{name: "Bob", age: 25}
    ...> ]
    iex> Sinter.Validator.validate_many(schema, data_list)
    {:ok, [%{name: "Alice", age: 30}, %{name: "Bob", age: 25}]}

# `validate_stream`

```elixir
@spec validate_stream(Sinter.Schema.t(), Enumerable.t(), validation_opts()) ::
  Enumerable.t()
```

Validates a stream of data maps against a schema with memory efficiency.

This function is designed for processing large datasets without loading
everything into memory at once. Perfect for DSPEx teleprompter optimization
on large training sets.

## Parameters

  * `schema` - A schema created by `Sinter.Schema.define/2`
  * `data_stream` - An Enumerable of data maps to validate
  * `opts` - Validation options

## Returns

  * A stream of `{:ok, validated_data}` or `{:error, [Error.t()]}` tuples

## Examples

    iex> schema = Sinter.Schema.define([{:id, :integer, [required: true]}])
    iex> data_stream = Stream.map(1..1000, &%{"id" => &1})
    iex> results = Sinter.Validator.validate_stream(schema, data_stream)
    iex> Enum.take(results, 3)
    [
      {:ok, %{id: 1}},
      {:ok, %{id: 2}},
      {:ok, %{id: 3}}
    ]

## Memory Efficiency

This function processes items one at a time and does not accumulate results,
making it suitable for very large datasets that would not fit in memory.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
