# avro.schema

> A module of avro's API.

Avro schema parsing and printing.

The parsed schema is an arena of `SchemaNode`s with integer child indices.
That is not just a Mojo workaround for self-referential structs: it is also
exactly what Avro's *named type references* want — a record that refers to
itself (`{"type": "record", "name": "Node", "fields": [{"name": "next",
"type": ["null", "Node"]}]}`) is one node index appearing twice.

Everything the JSON carried that Avro does not define is preserved as a raw
property (`field-id`, `element-id`, `key-id`, `value-id` — Apache Iceberg
writes all four), so `to_json()` round-trips and consumers can read them back.

## Structs

### `Props`

```mojo
struct Props
```

Ordered extra JSON attributes; values are kept as raw JSON text.

Implements: `Copyable`, `Defaultable`, `Movable`, `Sized`

Fields:

- `keys: List[String]`
- `vals: List[String]`

#### `__init__`

```mojo
def __init__(out self)
```

#### `__len__`

```mojo
def __len__(self) -> Int
```

#### `set`

```mojo
def set(mut self, var key: String, var raw_json: String)
```

#### `get`

```mojo
def get(self, key: StringSpan) -> String
```

Raw JSON text for `key`, or "" when absent.

#### `has`

```mojo
def has(self, key: StringSpan) -> Bool
```

#### `get_int`

```mojo
def get_int(self, key: StringSpan, default: Int = Int(-1)) -> Int
```

Integer property value, or `default` when absent or not a number.

### `Field`

```mojo
struct Field
```

One record field.

Implements: `Copyable`, `Movable`

Fields:

- `name: String`
- `doc: String`
- `type_index: Int`: Index of the field's type node in the owning `Schema`'s arena.
- `has_default: Bool`
- `default_json: String`: Raw JSON text of the field's default, when it has one.
- `order: String`
- `aliases: List[String]`
- `props: Props`

#### `make`

```mojo
def make(var name: String, type_index: Int) -> Self
```

#### `field_id`

```mojo
def field_id(self) -> Int
```

Iceberg's `field-id` attribute, or -1 when the field has none.

### `SchemaNode`

```mojo
struct SchemaNode
```

Implements: `Copyable`, `Movable`

Fields:

- `kind: Int`
- `name: String`: Fullname (namespace-qualified) for record/enum/fixed; "" otherwise.
- `namespace: String`
- `doc: String`
- `aliases: List[String]`
- `logical_type: String`
- `precision: Int`
- `scale: Int`
- `size: Int`: Byte width for `fixed`.
- `symbols: List[String]`
- `default_symbol: String`
- `fields: List[Field]`
- `children: List[Int]`: Array items / map values (one entry), or union branches.
- `props: Props`

#### `of`

```mojo
def of(kind: Int) -> Self
```

#### `short_name`

```mojo
def short_name(self) -> String
```

### `Schema`

```mojo
struct Schema
```

A parsed Avro schema: an arena of nodes plus the root node's index.

Implements: `Copyable`, `Movable`, `Writable`

Fields:

- `nodes: List[SchemaNode]`
- `root: Int`
- `names: Dict[String, Int]`: Fullname -> node index, for every named type the schema defines.

#### `__init__`

```mojo
def __init__(out self)
```

#### `kind`

```mojo
def kind(self, i: Int) -> Int
```

#### `root_kind`

```mojo
def root_kind(self) -> Int
```

#### `name`

```mojo
def name(self, i: Int) -> String
```

#### `logical_type`

```mojo
def logical_type(self, i: Int) -> String
```

#### `size`

```mojo
def size(self, i: Int) -> Int
```

#### `symbols`

```mojo
def symbols(self, i: Int) -> List[String]
```

#### `num_fields`

```mojo
def num_fields(self, i: Int) -> Int
```

#### `field`

```mojo
def field(self, i: Int, k: Int) -> Field
```

#### `field_index`

```mojo
def field_index(self, i: Int, name: StringSpan) -> Int
```

Position of the named field in record node `i`, or -1.

#### `field_type`

```mojo
def field_type(self, i: Int, k: Int) -> Int
```

#### `items`

```mojo
def items(self, i: Int) -> Int
```

Element node index of an `array`.

#### `values`

```mojo
def values(self, i: Int) -> Int
```

Value node index of a `map`.

#### `num_branches`

```mojo
def num_branches(self, i: Int) -> Int
```

#### `branch`

```mojo
def branch(self, i: Int, k: Int) -> Int
```

#### `props`

```mojo
def props(self, i: Int) -> Props
```

#### `is_optional`

```mojo
def is_optional(self, i: Int) -> Bool
```

True for a two-branch union with a `null` branch — Iceberg's spelling of an optional field.

#### `optional_branch`

```mojo
def optional_branch(self, i: Int) -> Int
```

For an optional union, the node index of the non-null branch; -1 otherwise.

#### `null_branch_index`

```mojo
def null_branch_index(self, i: Int) -> Int
```

Branch *position* of the `null` member of a union, or -1.

#### `is_logical_map`

```mojo
def is_logical_map(self, i: Int) -> Bool
```

An `array` of two-field records tagged `"logicalType": "map"` — how Avro (and Iceberg) spells a map with non-string keys.

#### `element_id`

```mojo
def element_id(self, i: Int) -> Int
```

#### `key_id`

```mojo
def key_id(self, i: Int) -> Int
```

#### `value_id`

```mojo
def value_id(self, i: Int) -> Int
```

#### `to_json`

```mojo
def to_json(self) -> String
```

#### `to_json_at`

```mojo
def to_json_at(self, i: Int) -> String
```

#### `write_to`

```mojo
def write_to(self, mut writer: T)
```

#### `parsing_canonical_form`

```mojo
def parsing_canonical_form(self) -> String
```

#### `fingerprint`

```mojo
def fingerprint(self) -> UInt64
```

The 64-bit Rabin fingerprint (`CRC-64-AVRO`) of the parsing canonical form — Avro's own single-object-encoding schema id.

## Functions

### `kind_name`

```mojo
def kind_name(kind: Int) -> String
```

### `primitive_kind`

```mojo
def primitive_kind(name: StringSpan) -> Int
```

Kind for a primitive type name, or -1 if `name` is not primitive.

### `is_primitive`

```mojo
def is_primitive(kind: Int) -> Bool
```

### `is_named`

```mojo
def is_named(kind: Int) -> Bool
```

### `crc64_avro`

```mojo
def crc64_avro(data: Span[UInt8]) -> UInt64
```

Avro's `CRC-64-AVRO` Rabin fingerprint.

### `parse_schema`

```mojo
def parse_schema(text: StringSpan) -> Schema
```

Parse an Avro schema from its JSON text.

## Aliases

### `NULL`

```mojo
comptime NULL = Int(0)
```

### `BOOLEAN`

```mojo
comptime BOOLEAN = Int(1)
```

### `INT`

```mojo
comptime INT = Int(2)
```

### `LONG`

```mojo
comptime LONG = Int(3)
```

### `FLOAT`

```mojo
comptime FLOAT = Int(4)
```

### `DOUBLE`

```mojo
comptime DOUBLE = Int(5)
```

### `BYTES`

```mojo
comptime BYTES = Int(6)
```

### `STRING`

```mojo
comptime STRING = Int(7)
```

### `RECORD`

```mojo
comptime RECORD = Int(8)
```

### `ENUM`

```mojo
comptime ENUM = Int(9)
```

### `ARRAY`

```mojo
comptime ARRAY = Int(10)
```

### `MAP`

```mojo
comptime MAP = Int(11)
```

### `UNION`

```mojo
comptime UNION = Int(12)
```

### `FIXED`

```mojo
comptime FIXED = Int(13)
```
