# `Narabe.Move`
[🔗](https://github.com/hattoriai/narabe/blob/v0.1.0/lib/narabe/move.ex#L1)

A move, as a drop sends it: these items (one, or several selected), into
this parent (a tree's item, a board's column, or `nil` for the top level
or a plain list), right after one item, or right before another.

    %Narabe.Move{ids: [42], parent: 7, after: 12, before: 13, index: 3}

The move says where by ids, not by an index: a screen a moment out of
date still means what the person saw ("after Roadmap"), whoever moved
what meanwhile. `after` wins over `before`; `index` is a last resort, for
a neighbour that is gone.

The browser sends it to the list's `on_move` event:

    def handle_event("moved", params, socket) do
      {:ok, move} = Narabe.Move.parse(params, Card)
      ...
    end

# `id`

```elixir
@type id() :: term()
```

# `t`

```elixir
@type t() :: %Narabe.Move{
  after: id() | nil,
  before: id() | nil,
  ids: [id()],
  index: non_neg_integer() | nil,
  parent: id() | nil
}
```

# `apply`

```elixir
@spec apply([term()], t(), keyword()) ::
  {:ok, [term()]} | {:error, :not_found | :into_itself}
```

Applies a move to items in memory, in their order: a list, a board's
cards (each with its column in `:group`), or a tree's items, flat (each
with its parent in `:group`, and `tree: true`). For apps that keep the
order themselves, without `Narabe.Ecto`, and for tests.

Returns `{:ok, items}`, the items in their new order with the moved ones'
group set, or `{:error, reason}`: `:not_found` (an id that is not among
the items), or `:into_itself` (a tree item into itself or under itself).

Options:

  * `:id` - an item's id: a key or a function (`:id`).
  * `:group` - the key of its column or parent (none: one list).
  * `:tree` - whether `:group` is a parent among the items.

## Examples

    iex> items = [%{id: 1}, %{id: 2}, %{id: 3}]
    iex> {:ok, moved} = Narabe.Move.apply(items, %Narabe.Move{ids: [1], after: 3})
    iex> Enum.map(moved, & &1.id)
    [2, 3, 1]

    iex> cards = [%{id: 1, col: :todo}, %{id: 2, col: :done}]
    iex> {:ok, moved} = Narabe.Move.apply(cards, %Narabe.Move{ids: [1], parent: :done, before: 2}, group: :col)
    iex> moved
    [%{id: 1, col: :done}, %{id: 2, col: :done}]

# `parse`

```elixir
@spec parse(map(), module() | atom()) :: {:ok, t()} | {:error, :invalid_move}
```

A move from the params of an `on_move` event, its ids cast to the type of
a schema's primary key (or to an Ecto type, `:id`, `:binary_id`,
`:string`); the browser sends ids as text.

    iex> Narabe.Move.parse(%{"v" => 1, "ids" => ["42"], "parent" => "7", "after" => "12", "before" => nil, "index" => 3}, :id)
    {:ok, %Narabe.Move{ids: [42], parent: 7, after: 12, before: nil, index: 3}}

    iex> Narabe.Move.parse(%{"v" => 1, "ids" => []}, :id)
    {:error, :invalid_move}

# `parse!`

```elixir
@spec parse!(map(), module() | atom()) :: t()
```

As `parse/2`, raising `ArgumentError` for params that are no move.

# `to_params`

```elixir
@spec to_params(t()) :: map()
```

The params of a move, as the browser sends them: for `Narabe.Test` and
an agent's tool that moves items as a person would.

    iex> Narabe.Move.to_params(%Narabe.Move{ids: [42], after: 12})
    %{"v" => 1, "ids" => ["42"], "parent" => nil, "after" => "12", "before" => nil, "index" => nil}

---

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