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

Joined fields (spec/02 §1.4): a reader of an input reads each per-identity source's
answer for its own identity. Its rows carry, beside their own fields, every output
field but the identity, named `"<id>.<field>"`, a string, never an atom, `nil` where the
output holds nothing for the row's entity; its schema describes them as the outputs do.

Which sources a reader sees is its owner's to decide; on a Macaw page, `macaw_compose`'s.
Ported from visualize's `Visualize.VirtualSource.Join`, whose names were atoms.

    iex> alias Macaw.Data.Schema
    iex> hosts = Schema.new!(%{"host" => %{type: :category, identity: true}, "cpu" => %{type: :number}})
    iex> health = Schema.new!(%{"host" => %{type: :category, identity: true}, "state" => %{type: :category}})
    iex> outputs = [{"health", health, [%{"host" => "a", "state" => "ok"}]}]
    iex> Macaw.Data.Derived.Join.join([%{"host" => "a", "cpu" => 3}, %{"host" => "b", "cpu" => 9}], hosts, outputs)
    [%{"host" => "a", "cpu" => 3, "health.state" => "ok"}, %{"host" => "b", "cpu" => 9, "health.state" => nil}]

# `output`

```elixir
@type output() :: {String.t(), Macaw.Data.Schema.t(), [map()]}
```

A per-identity source's id, its output schema and its last good output rows.

# `join`

```elixir
@spec join([map()], Macaw.Data.Schema.t(), [output()]) :: [map()]
```

The rows with every output's fields for their identity (spec/02 §1.4).

# `schema`

```elixir
@spec schema(Macaw.Data.Schema.t(), [{String.t(), Macaw.Data.Schema.t()} | output()]) ::
  Macaw.Data.Schema.t()
```

The input's schema with each joined field described as its output does, without
`identity` or `window` (spec/02 §1.4); as it is with no output.

---

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