# iceberg.transforms

> A module of iceberg's API.

Partition transforms and partition specs.

Every transform in the spec's transform table is here: `identity`, `bucket[N]`,
`truncate[W]`, `year`, `month`, `day`, `hour` and `void`. A transform spelling
this build does not recognise becomes `T_UNKNOWN`, which keeps its original
text, produces an `unknown` result type and reports `can_project() == False` —
the spec requires readers to ignore such a partition field when filtering
rather than fail, and requires that behaviour outright in v3.

`day` is the only time transform whose result is a `date`; `year`, `month` and
`hour` produce plain `int` counts from the epoch. Nanosecond timestamps are
truncated to microseconds before hashing (Appendix B note 3) so that a value
buckets the same however its column is typed.

## Structs

### `Transform`

```mojo
struct Transform
```

A partition transform: a kind plus the `[N]`/`[W]` parameter.

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

Fields:

- `kind: UInt8`
- `param: Int`
- `raw: String`: Original spelling — the only thing kept for `T_UNKNOWN`.

#### `identity`

```mojo
def identity() -> Self
```

#### `bucket`

```mojo
def bucket(n: Int) -> Self
```

#### `truncate`

```mojo
def truncate(w: Int) -> Self
```

#### `void`

```mojo
def void() -> Self
```

#### `name`

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

#### `write_to`

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

#### `can_project`

```mojo
def can_project(self) -> Bool
```

False when a predicate cannot be pushed through this transform.

#### `is_time`

```mojo
def is_time(self) -> Bool
```

#### `preserves_order`

```mojo
def preserves_order(self) -> Bool
```

True when `a <= b` implies `T(a) <= T(b)` — the projection rules for `<`/`>` only hold for these.

#### `result_type`

```mojo
def result_type(self, mut store: TypeStore, source: Int) -> Int
```

The type a partition value of this transform has.

#### `apply`

```mojo
def apply(self, v: Datum) -> Datum
```

Transform one value. All transforms map null to null.

### `PartitionField`

```mojo
struct PartitionField
```

One field of a partition spec.

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

Fields:

- `source_id: Int`
- `source_ids: List[Int]`: V3 multi-argument transforms. Single-source specs mirror `source_id`.
- `field_id: Int`
- `name: String`
- `transform: Transform`

#### `single`

```mojo
def single(source_id: Int, field_id: Int, var name: String, var t: Transform) -> Self
```

#### `write_to`

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

### `PartitionSpec`

```mojo
struct PartitionSpec
```

A partition spec: an id and an ordered list of partition fields.

Implements: `Copyable`, `Movable`

Fields:

- `spec_id: Int`
- `fields: List[PartitionField]`

#### `__init__`

```mojo
def __init__(out self, spec_id: Int, var fields: List[PartitionField])
```

#### `unpartitioned`

```mojo
def unpartitioned(spec_id: Int = Int(0)) -> Self
```

#### `is_unpartitioned`

```mojo
def is_unpartitioned(self) -> Bool
```

#### `field_index`

```mojo
def field_index(self, field_id: Int) -> Int
```

#### `fields_for_source`

```mojo
def fields_for_source(self, source_id: Int) -> List[Int]
```

Positions of every partition field derived from `source_id`.

#### `partition_type`

```mojo
def partition_type(self, schema: Schema) -> Schema
```

The struct type of a partition tuple under this spec.

Field ids are the *partition* field ids (1000+), matching how manifest
files type their `partition` column. Every field is optional: a
transform may legitimately produce null.

#### `from_json`

```mojo
def from_json(doc: Json, i: Int, default_spec_id: Int = Int(0)) -> Self
```

#### `from_fields_json`

```mojo
def from_fields_json(doc: Json, i: Int, spec_id: Int) -> Self
```

V1's bare `partition-spec` array (no wrapping object).

#### `to_json`

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

### `SortField`

```mojo
struct SortField
```

Implements: `Copyable`, `Movable`

Fields:

- `source_id: Int`
- `source_ids: List[Int]`
- `transform: Transform`
- `direction: UInt8`
- `null_order: UInt8`

### `SortOrder`

```mojo
struct SortOrder
```

Implements: `Copyable`, `Movable`

Fields:

- `order_id: Int`
- `fields: List[SortField]`

#### `__init__`

```mojo
def __init__(out self, order_id: Int, var fields: List[SortField])
```

#### `from_json`

```mojo
def from_json(doc: Json, i: Int) -> Self
```

#### `to_json`

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

## Functions

### `iceberg_hash`

```mojo
def iceberg_hash(v: Datum) -> Int32
```

Appendix B's 32-bit hash of a typed value.

### `bucket_of`

```mojo
def bucket_of(v: Datum, n: Int) -> Int
```

### `truncate_of`

```mojo
def truncate_of(v: Datum, w: Int) -> Datum
```

### `truncate_codepoints`

```mojo
def truncate_codepoints(s: String, w: Int) -> String
```

First `w` Unicode code points — the spec truncates strings by code point, never mid-character.

### `time_of`

```mojo
def time_of(v: Datum, kind: UInt8) -> Datum
```

### `parse_transform`

```mojo
def parse_transform(s: String) -> Transform
```

## Aliases

### `T_IDENTITY`

```mojo
comptime T_IDENTITY = UInt8(0)
```

### `T_BUCKET`

```mojo
comptime T_BUCKET = UInt8(1)
```

### `T_TRUNCATE`

```mojo
comptime T_TRUNCATE = UInt8(2)
```

### `T_YEAR`

```mojo
comptime T_YEAR = UInt8(3)
```

### `T_MONTH`

```mojo
comptime T_MONTH = UInt8(4)
```

### `T_DAY`

```mojo
comptime T_DAY = UInt8(5)
```

### `T_HOUR`

```mojo
comptime T_HOUR = UInt8(6)
```

### `T_VOID`

```mojo
comptime T_VOID = UInt8(7)
```

### `T_UNKNOWN`

```mojo
comptime T_UNKNOWN = UInt8(255)
```

### `PARTITION_DATA_ID_START`

```mojo
comptime PARTITION_DATA_ID_START = Int(1000)
```

V1 assigned partition field ids sequentially from 1000 with no record.

### `SORT_ASC`

```mojo
comptime SORT_ASC = UInt8(0)
```

### `SORT_DESC`

```mojo
comptime SORT_DESC = UInt8(1)
```

### `NULLS_FIRST`

```mojo
comptime NULLS_FIRST = UInt8(0)
```

### `NULLS_LAST`

```mojo
comptime NULLS_LAST = UInt8(1)
```
