# `Masu.Source`
[🔗](https://github.com/hattoriai/masu/blob/v0.1.0/lib/masu/source.ex#L1)

Where a grid's rows come from.

A grid never holds all its rows. It asks its source for the rows of
its query (`prepare/3`), how many there are (`count/1`), and the rows
the browser shows (`rows/3`): a block at a time, as the person scrolls.

Masu has two sources:

  * `Masu.Source.List`, for rows the LiveView already has (`rows={@users}`);
  * `Masu.Source.Ecto`, for an Ecto query or schema
    (`source={User} repo={Repo}`): it sorts, filters, searches and
    counts in the database, and reads only the rows on the screen.

A source of your own is a module with these callbacks, given as
`source={{MySource, opts}}`; the grid calls `init/2` with the opts.

# `state`

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

The state of a source; a source keeps what it needs between calls.

# `t`

```elixir
@type t() :: %Masu.Source{module: module(), state: state()}
```

# `change`
*optional* 

```elixir
@callback change(state(), [Masu.Live.change()], (term() -&gt; term())) :: state()
```

Takes changes into the source's rows (see `Masu.Live`): `{:upsert, row}`
and `{:delete, row_or_id}`, oldest first, with the grid's function that
gives a row's id. The grid calls `prepare/3` after it.

A source that reads its rows anew for each query (as a database does)
does not need it: without it, the grid asks the query again.

# `columns`
*optional* 

```elixir
@callback columns(state()) :: [String.t() | keyword() | map()]
```

The source's columns, for a grid with no `:col` slots: a query tool's,
whose columns are known when its query runs. Each is a key (a string),
or a keyword list or map of a `:col`'s attributes (`key`, `label`,
`type`, `field`, `width`...). A column without a `field` reads the row
at its place: its rows are lists of values in the columns' order. A
column without a `type` is `:auto`: the grid learns it from the values
(see `Masu.Column`).

# `count`

```elixir
@callback count(state()) :: non_neg_integer() | {:at_least, non_neg_integer()} | :unknown
```

How many rows the query has: a number, `{:at_least, n}` when the
source knows only that there are at least `n` (a search engine's
"10,000+"), or `:unknown`. A grid whose source does not know scrolls
over the rows it read, and a block that comes back short says where
they end (see the [Export, selection and large tables](export.md) guide).

# `fetch`
*optional* 

```elixir
@callback fetch(state(), ids :: [term()], (term() -&gt; term())) :: [term()]
```

The rows with the given ids, among the rows the source may show (its
query without the person's filters): the rows a person edits. A row
that is not there is not given, so that no one edits a row the grid
would not show them.

# `filters`
*optional* 

```elixir
@callback filters(state(), Masu.Column.t()) :: [Masu.Filter.op()]
```

The operators of `Masu.Filter` the source filters a column by. Without
it, every operator of the column's type. A source that is not a
database Masu translates itself (an API, a search engine, another
query tool) gives those it runs: the filter menu, the chips, the menu
of a cell, a view's params (a link, a saved view) and `Masu.Test`
offer only them, and the server refuses the others.

Masu runs `:between` as `:gte` and `:lte` for a source that has those
and not it. `[]` is a column the source does not filter by. See the
[Sources](sources.md) guide for what each operator means.

# `init`

```elixir
@callback init(input :: term(), opts :: keyword()) :: state()
```

Starts the source from what the grid was given.

# `locate`
*optional* 

```elixir
@callback locate(state(), id :: term(), (term() -&gt; term())) :: non_neg_integer() | nil
```

The place (from 0) of the row with an id in the rows of the query, in
their order, or `nil` when the query does not have it: where another
person's cell is in this person's order (`Masu.Presence`).

# `nodes`
*optional* 

```elixir
@callback nodes(state(), offset :: non_neg_integer(), limit :: pos_integer()) ::
  [{term(), Masu.Tree.node_info()}] | nil
```

For a tree (`Masu.Tree`): the rows from `offset`, as `rows/3` gives
them, each with where it is in the tree (`t:Masu.Tree.node_info/0`), or
`nil` when the source is not a tree. The rows of a tree are the roots
and the children of the rows that are open (`Masu.Query`'s `expanded`),
in order.

# `prepare`

```elixir
@callback prepare(state(), Masu.Query.t(), [Masu.Column.t()]) :: state()
```

Applies a query: the rows that `count/1` counts and `rows/3` reads are
from now on those of the query, in its order. The query is checked
against the columns (`Masu.Query`).

# `rows`

```elixir
@callback rows(state(), offset :: non_neg_integer(), limit :: pos_integer()) ::
  [term()] | {[term()], non_neg_integer()} | {:error, term()}
```

The rows from `offset` (from 0), at most `limit` of them; or
`{rows, count}`, when the source learned the count of the query with
them (a `total_count` of the same request), which the grid takes; or
`{:error, reason}`, which a grid with `load={:async}` shows (see
`Masu.Source.Error`).

# `select_all`
*optional* 

```elixir
@callback select_all(
  state(),
  Masu.Query.t(),
  [Masu.Column.t()],
  except :: [term()],
  (term() -&gt; term())
) ::
  {:ids, [term()]} | {:query, term()}
```

Every row of a query but those of `except` (ids, as the browser has
them): the person selected every row (`Masu.Live.selected/1`). Gives
their ids, or, for a database, a query of them.

# `siblings`
*optional* 

```elixir
@callback siblings(state(), id :: term()) :: [term()]
```

For a tree: the ids of the siblings of a row (it among them) that have
children: the rows that open with the row's level (`*`).

# `supports?`
*optional* 

```elixir
@callback supports?(state(), Masu.Column.t()) :: boolean()
```

Whether the source can sort and filter by a column. A database can sort
only by a field it stores, not by a function of the row; the grid makes
such a column one that does not sort or filter.

# `totals`
*optional* 

```elixir
@callback totals(state()) :: %{required(String.t()) =&gt; term()}
```

The totals of the rows of the query (`Masu.Group`): the value of each
column with an `aggregate`, by its key.

# `values`
*optional* 

```elixir
@callback values(state(), Masu.Column.t(), Masu.Query.t(), [Masu.Column.t()], keyword()) ::
  [
    {term(), non_neg_integer()}
  ]
```

The values of a column among the rows of a query, with how many rows
have each, the most frequent first: what a column's filter menu offers.
`search` narrows them to the values that contain it, without case.
`nil` counts as a value: the rows with no value.

A source without it offers no values: the menu then filters by what the
person types.

# `new`

```elixir
@spec new(term(), keyword()) :: t()
```

The source for what a grid was given: a list, an Ecto query or schema
(with the `:repo` option), or `{module, opts}`.

---

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