# `Macaw.Data.Transform`
[🔗](https://github.com/dcoai/macaw_data/blob/v0.5.3/lib/macaw/data/transform.ex#L1)

The transform behavior (spec/04 §1.1): one step of a data pipeline, a table in and a
table out, declared once so the validator, a drawer's forms and vocabulary, the JSON
forms and the sandbox all read the same declaration (visualize#886).

    defmodule MyApp.Ops.Clip do
      @behaviour Macaw.Data.Transform
      alias Macaw.Data.Operations.Option

      @impl true
      def name, do: "clip"
      @impl true
      def options, do: [{"field", %Option{type: :field, required: true}}]
      @impl true
      def needs, do: []
      @impl true
      def outputs(_node, columns), do: columns
      @impl true
      def run(node, table, _context), do: ...
    end

A member is pure and deterministic: no processes, ETS, NIFs, `Regex`, clock or
randomness. `run/3` and `outputs/2` are given the node checked
(`Macaw.Data.Operations.validate/3`): its keys strings, every option present with its
default filled in, an enum value its atom, a frame-bound `"plot"` already a number.

# `columns`

```elixir
@type columns() :: [{Macaw.Data.Table.name(), Macaw.Data.Table.type()}]
```

Columns in order, each with its `Macaw.Data.Table` type.

# `need`

```elixir
@type need() :: :frame | :projection | :text
```

Context a transform may need beyond the data: a drawer's frame, projection, text.

# `node_map`

```elixir
@type node_map() :: %{required(String.t()) =&gt; term()}
```

A checked node: the op's options by their strings, each holding its value.

# `name`

```elixir
@callback name() :: String.t()
```

The op a node names, unique in a registry.

# `needs`

```elixir
@callback needs() :: [need()]
```

The context the op requires beyond the data: `[]` for a table operation.

# `options`

```elixir
@callback options() :: [{String.t(), Macaw.Data.Operations.Option.t()}]
```

Every key the op reads, in order, each declared.

# `outputs`

```elixir
@callback outputs(node_map(), columns()) :: columns()
```

The columns `run/3` answers for the node over input `columns`.

# `prepare`
*optional* 

```elixir
@callback prepare([node_map()], Macaw.Data.Table.t(), map()) :: term()
```

Computed once per design and shared by its marks, under the context's `prepared`.

# `reduces`
*optional* 

```elixir
@callback reduces() :: {String.t(), pos_integer()}
```

A reducer's count option and the rows each unit of it keeps at most (spec/04 §7).

# `run`

```elixir
@callback run(node_map(), Macaw.Data.Table.t(), map()) :: Macaw.Data.Table.t()
```

The step: the table after it.

---

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