# `LeXtract.Schema`
[🔗](https://github.com/YgorCastor/lextract.git/blob/main/lib/lextract/schema.ex#L1)

Generate and manage NimbleOptions schemas from extraction examples.

Provides schema generation for structured output with ReqLLM's generate_object/4.

## Example

    iex> examples = [
    ...>   %LeXtract.ExampleData{
    ...>     input: "Patient takes aspirin",
    ...>     output: %{
    ...>       "extractions" => [
    ...>         %{"class" => "Medication", "medication_attributes" => %{"name" => "aspirin"}}
    ...>       ]
    ...>     }
    ...>   }
    ...> ]
    iex> schema = LeXtract.Schema.from_examples(examples)
    iex> is_list(schema)
    true
    iex> Keyword.has_key?(schema, :extractions)
    true

# `from_examples`

```elixir
@spec from_examples(
  [LeXtract.ExampleData.t()],
  keyword()
) :: keyword()
```

Generates NimbleOptions schema from example extractions.

Analyzes the provided examples to automatically infer a schema suitable for
use with ReqLLM's generate_object/4. The schema will include all extraction
classes and their attributes found in the examples.

## Parameters

  * `examples` - List of LeXtract.ExampleData structs
  * `opts` - Options (see below)

## Options

  * `:attribute_suffix` - Suffix for attribute fields (default: "_attributes")
  * `:required` - List of required field names (default: [])
  * `:manual_schema` - User-provided schema to merge with generated (default: nil)

## Examples

    iex> examples = [
    ...>   %LeXtract.ExampleData{
    ...>     input: "Dr. Smith prescribed aspirin to John Doe",
    ...>     output: %{
    ...>       "extractions" => [
    ...>         %{
    ...>           "class" => "Person",
    ...>           "person_attributes" => %{"name" => "Dr. Smith", "role" => "doctor"}
    ...>         },
    ...>         %{
    ...>           "class" => "Medication",
    ...>           "medication_attributes" => %{"name" => "aspirin"}
    ...>         }
    ...>       ]
    ...>     }
    ...>   }
    ...> ]
    iex> schema = LeXtract.Schema.from_examples(examples)
    iex> Keyword.has_key?(schema, :extractions)
    true

# `merge`

```elixir
@spec merge(keyword(), keyword()) :: keyword()
```

Merges user-provided schema with generated schema.

User schema takes precedence for conflicts. This allows users to override
specific parts of the automatically generated schema while keeping the rest.

## Parameters

  * `generated_schema` - Schema generated from examples
  * `user_schema` - User-provided schema overrides

## Returns

Merged schema as keyword list.

## Examples

    iex> generated = [
    ...>   extractions: [type: {:list, [type: :map]}, default: []]
    ...> ]
    iex> user = [
    ...>   extractions: [type: {:list, [type: :map]}, default: [], required: true]
    ...> ]
    iex> merged = LeXtract.Schema.merge(generated, user)
    iex> merged[:extractions][:required]
    true

    iex> generated = [
    ...>   name: [type: :string],
    ...>   age: [type: :integer]
    ...> ]
    iex> user = [
    ...>   age: [type: :integer, required: true]
    ...> ]
    iex> merged = LeXtract.Schema.merge(generated, user)
    iex> Keyword.has_key?(merged, :name)
    true
    iex> merged[:age][:required]
    true

# `validate`

```elixir
@spec validate(
  term(),
  keyword()
) :: {:ok, term()} | {:error, term()}
```

Validates extraction data against a schema.

Uses NimbleOptions.validate/2 internally to validate the provided data
against the schema.

## Parameters

  * `data` - Data to validate (typically a keyword list or map)
  * `schema` - NimbleOptions schema (keyword list)

## Returns

`:ok` if valid, `{:error, reason}` otherwise.

## Examples

    iex> schema = [
    ...>   extractions: [
    ...>     type: {:list, :map},
    ...>     default: []
    ...>   ]
    ...> ]
    iex> data = [extractions: []]
    iex> LeXtract.Schema.validate(data, schema)
    {:ok, [extractions: []]}

    iex> schema = [
    ...>   extractions: [
    ...>     type: {:list, :map},
    ...>     required: true
    ...>   ]
    ...> ]
    iex> data = []
    iex> {:error, %NimbleOptions.ValidationError{}} = LeXtract.Schema.validate(data, schema)

---

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