# `Milvex.Schema.Field`

Builder for Milvus collection field schemas.

Provides a fluent API for constructing field definitions with validation.
Supports all Milvus data types including scalars, vectors, and complex types.

## Examples

    # Primary key field (using builder)
    field = Field.new("id", :int64) |> Field.set_primary_key() |> Field.auto_id()

    # Vector field with dimension
    field = Field.new("embedding", :float_vector) |> Field.dimension(128)

    # VarChar with max length
    field = Field.new("title", :varchar) |> Field.max_length(512)

    # Using smart constructors
    Field.primary_key("id", :int64, auto_id: true)
    Field.vector("embedding", 128)
    Field.varchar("title", 512, nullable: true)

# `data_type`

```elixir
@type data_type() ::
  :bool
  | :int8
  | :int16
  | :int32
  | :int64
  | :float
  | :double
  | :varchar
  | :json
  | :text
  | :timestamp
  | :array
  | :struct
  | :array_of_struct
  | :binary_vector
  | :float_vector
  | :float16_vector
  | :bfloat16_vector
  | :sparse_float_vector
  | :int8_vector
```

# `t`

```elixir
@type t() :: %Milvex.Schema.Field{
  auto_id: boolean(),
  data_type: data_type(),
  default_value: term() | nil,
  description: String.t() | nil,
  dimension: pos_integer() | nil,
  element_type: data_type() | nil,
  enable_analyzer: boolean(),
  is_clustering_key: boolean(),
  is_dynamic: boolean(),
  is_partition_key: boolean(),
  is_primary_key: boolean(),
  max_capacity: pos_integer() | nil,
  max_length: pos_integer() | nil,
  name: String.t(),
  nullable: boolean(),
  struct_schema: [t()] | nil
}
```

# `array`

```elixir
@spec array(String.t(), data_type(), keyword()) :: t()
```

Creates an array field with the specified element type.

## Options
  - `:max_capacity` - Maximum number of elements (required)
  - `:nullable` - Allow null values (default: false)
  - `:description` - Field description
  - `:struct_schema` - Required when element_type is :struct, list of Field.t()
  - `:max_length` - For varchar element types

## Examples

    # Array of scalars
    Field.array("tags", :varchar, max_capacity: 100, max_length: 64)

    # Array of structs
    struct_fields = [
      Field.varchar("text", 4096),
      Field.vector("embedding", 1024)
    ]
    Field.array("sentences", :struct, max_capacity: 50, struct_schema: struct_fields)

# `array_of_struct?`

```elixir
@spec array_of_struct?(t()) :: boolean()
```

Checks if the field is an array of struct type.

# `auto_id`

```elixir
@spec auto_id(t(), boolean()) :: t()
```

Enables auto-generation of IDs for this field.
Only valid for primary key fields with int64 or varchar type.

# `clustering_key`

```elixir
@spec clustering_key(t(), boolean()) :: t()
```

Marks the field as a clustering key.

# `data_types`

```elixir
@spec data_types() :: [data_type()]
```

Returns list of all supported data types.

# `default`

```elixir
@spec default(t(), term()) :: t()
```

Sets a default value for the field.

# `description`

```elixir
@spec description(t(), String.t()) :: t()
```

Sets the field description.

# `dimension`

```elixir
@spec dimension(t(), pos_integer()) :: t()
```

Sets the dimension for vector fields.
Required for all vector types except sparse vectors.

# `dynamic`

```elixir
@spec dynamic(t(), boolean()) :: t()
```

Marks the field as a dynamic field.

Only valid for scalar types: bool, int8, int16, int32, int64, float, double, text, varchar, json.
Dynamic fields allow storing data that may not be strictly typed at the schema level.

## Examples

    Field.new("metadata", :json) |> Field.dynamic()
    Field.varchar("extra", 256, dynamic: true)

# `element_type`

```elixir
@spec element_type(t(), data_type()) :: t()
```

Sets the element type for array fields.

# `enable_analyzer`

```elixir
@spec enable_analyzer(t(), boolean()) :: t()
```

Enables text analyzer for varchar fields.
Used for BM25 full-text search.

# `from_proto`

```elixir
@spec from_proto(Milvex.Milvus.Proto.Schema.FieldSchema.t()) :: t()
```

Creates a Field from a protobuf FieldSchema struct.

# `from_struct_array_field_schema`

```elixir
@spec from_struct_array_field_schema(
  Milvex.Milvus.Proto.Schema.StructArrayFieldSchema.t()
) :: t()
```

Creates a Field from a StructArrayFieldSchema proto.

# `max_capacity`

```elixir
@spec max_capacity(t(), pos_integer()) :: t()
```

Sets the maximum capacity for array fields.

# `max_length`

```elixir
@spec max_length(t(), pos_integer()) :: t()
```

Sets the maximum length for varchar fields.
Required for varchar type, must be between 1 and 65535.

# `new`

```elixir
@spec new(String.t(), data_type()) :: t()
```

Creates a new field with the given name and data type.

## Parameters
  - `name` - Field name (1-255 characters, alphanumeric and underscores)
  - `data_type` - One of the supported Milvus data types

## Examples

    Field.new("id", :int64)
    Field.new("embedding", :float_vector)

# `nullable`

```elixir
@spec nullable(t(), boolean()) :: t()
```

Marks the field as nullable.

# `partition_key`

```elixir
@spec partition_key(t(), boolean()) :: t()
```

Marks the field as a partition key.

# `primary_key`

```elixir
@spec primary_key(String.t(), data_type(), keyword()) :: t()
```

Creates a primary key field with common defaults.

## Options
  - `:auto_id` - Enable auto ID generation (default: false)
  - `:description` - Field description

## Examples

    Field.primary_key("id", :int64)
    Field.primary_key("id", :int64, auto_id: true)
    Field.primary_key("pk", :varchar, max_length: 64)

# `scalar`

```elixir
@spec scalar(String.t(), data_type(), keyword()) :: t()
```

Creates a scalar field of the specified type.

## Options
  - `:nullable` - Allow null values (default: false)
  - `:description` - Field description
  - `:default` - Default value

## Examples

    Field.scalar("age", :int32)
    Field.scalar("score", :float, nullable: true)

# `scalar_type?`

```elixir
@spec scalar_type?(data_type()) :: boolean()
```

Checks if the given type is a scalar type.

# `scalar_types`

```elixir
@spec scalar_types() :: [data_type()]
```

Returns list of scalar data types.

# `set_primary_key`

```elixir
@spec set_primary_key(t()) :: t()
```

Marks the field as the primary key (sets to true).

# `set_primary_key`

```elixir
@spec set_primary_key(t(), boolean()) :: t()
```

Marks the field as the primary key.

When called with a single Field argument, sets `is_primary_key` to `true`.
When called with a boolean, sets `is_primary_key` to that value.

# `sparse_vector`

```elixir
@spec sparse_vector(
  String.t(),
  keyword()
) :: t()
```

Creates a sparse vector field.

Sparse vectors don't require a dimension parameter.

## Examples

    Field.sparse_vector("sparse_embedding")

# `struct`

```elixir
@spec struct(
  String.t(),
  keyword()
) :: t()
```

Creates a struct field with nested fields.

Struct fields are typically used as the element type for array_of_struct fields.

## Options
  - `:fields` - List of Field.t() defining the struct schema (required)
  - `:description` - Field description

## Examples

    struct_fields = [
      Field.varchar("text", 4096),
      Field.vector("embedding", 1024),
      Field.varchar("speaker_id", 36)
    ]
    Field.struct("sentence", fields: struct_fields)

# `struct?`

```elixir
@spec struct?(t()) :: boolean()
```

Checks if the field is a struct type.

# `timestamp`

```elixir
@spec timestamp(
  String.t(),
  keyword()
) :: t()
```

Creates a timestamp field (with timezone).

Milvus stores timestamps as `Timestamptz` - timestamp with timezone information.

## Options
  - `:nullable` - Allow null values (default: false)
  - `:description` - Field description
  - `:default` - Default value

## Examples

    Field.timestamp("created_at")
    Field.timestamp("updated_at", nullable: true)

# `to_proto`

```elixir
@spec to_proto(t()) :: Milvex.Milvus.Proto.Schema.FieldSchema.t()
```

Converts the field to a protobuf FieldSchema struct.

# `to_struct_array_field_schema`

```elixir
@spec to_struct_array_field_schema(t()) ::
  Milvex.Milvus.Proto.Schema.StructArrayFieldSchema.t()
```

Converts an array_of_struct field to a StructArrayFieldSchema proto.

Used for the `struct_array_fields` in CollectionSchema.

Nested fields are wrapped as Array (for scalars) or ArrayOfVector (for vectors)
as required by Milvus's StructArrayFieldSchema format.

# `validate`

```elixir
@spec validate(t()) :: {:ok, t()} | {:error, Milvex.Error.t()}
```

Validates the field configuration.

Returns `{:ok, field}` if valid, `{:error, error}` otherwise.

# `validate!`

```elixir
@spec validate!(t()) :: t()
```

Validates the field and raises on error.

# `varchar`

```elixir
@spec varchar(String.t(), pos_integer(), keyword()) :: t()
```

Creates a varchar field with the specified max length.

## Options
  - `:nullable` - Allow null values (default: false)
  - `:description` - Field description
  - `:default` - Default value
  - `:enable_analyzer` - Enable text analyzer for BM25 search (default: false)

## Examples

    Field.varchar("title", 256)
    Field.varchar("description", 1024, nullable: true)
    Field.varchar("content", 4096, enable_analyzer: true)

# `vector`

```elixir
@spec vector(String.t(), pos_integer(), keyword()) :: t()
```

Creates a vector field with the specified dimension.

## Options
  - `:type` - Vector type (default: :float_vector)
  - `:description` - Field description

## Examples

    Field.vector("embedding", 128)
    Field.vector("embedding", 768, type: :float16_vector)

# `vector_type?`

```elixir
@spec vector_type?(data_type()) :: boolean()
```

Checks if the given type is a vector type.

# `vector_types`

```elixir
@spec vector_types() :: [data_type()]
```

Returns list of vector data types.

---

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