# `Masu.Sheet`
[🔗](https://github.com/hattoriai/masu/blob/v0.7.0/lib/masu/sheet.ex#L1)

A grid outside the LiveView: its rows, and its writes, for a job, a
test, or an agent (`Masu.Issho`). The writes go the grid's way: its
changeset or its `on_update`, its read-only rules, the compare of a
cell someone changed meanwhile, its history, and its `live` topic, so
the people who have the grid open see each change as it lands.

Define a grid once, as the attributes of `Masu.Components.data_grid/1`,
and use it in both places:

    defmodule MyApp.Grids do
      def tasks(scope) do
        [
          id: "tasks",
          source: MyApp.Tasks.query(scope),
          repo: MyApp.Repo,
          changeset: &MyApp.Tasks.Task.changeset/2,
          struct: %MyApp.Tasks.Task{},
          create_with: %{account_id: scope.account.id},
          deletable: true,
          history: MyApp.GridHistory,
          live: {MyApp.PubSub, "tasks:#{scope.account.id}"},
          columns: [
            [field: :title],
            [field: :status, type: :enum],
            [field: :due, type: :date]
          ]
        ]
      end
    end

```heex
<.data_grid {MyApp.Grids.tasks(@current_scope)} scope={@current_scope} user={@user} />
```

    sheet = Masu.Sheet.new(MyApp.Grids.tasks(scope))
    Masu.Sheet.rows(sheet, filters: [{"status", :eq, "open"}], limit: 20)
    Masu.Sheet.update(sheet, [%{"id" => 7, "key" => "status", "value" => "done"}],
      scope: scope, user: %{id: "agent:1", name: "Assistant"})

The columns of a sheet are those of `columns`, or its source's: a
`:col` slot is of the HEEx that renders the grid, and a sheet has
none. A grid given `rows` (a list) is a sheet of that list, which its
writes do not change.

# `error`

```elixir
@type error() :: [term()]
```

# `t`

```elixir
@type t() :: %Masu.Sheet{
  attrs: map(),
  columns: [Masu.Column.t()],
  id: String.t(),
  source: Masu.Source.t()
}
```

# `can`

```elixir
@spec can(t()) :: %{edit: boolean(), create: boolean(), delete: boolean()}
```

Whether the sheet edits cells, adds rows, deletes rows.

# `columns`

```elixir
@spec columns(t()) :: [Masu.Column.t()]
```

The columns of the sheet.

# `create`

```elixir
@spec create(t(), [map()], keyword()) :: [ok: term(), error: [list()]]
```

New rows, each the values of its cells by key: for each, `{:ok, row}`
or `{:error, errors}` (`[key, message]`, a key of nil for the row).
Options as `update/3`.

# `delete`

```elixir
@spec delete(t(), [term()], keyword()) :: %{deleted: [term()], errors: [list()]}
```

Deletes rows, by their ids: the rows deleted, and the errors, each
`[id, message]`. Options as `update/3`.

# `fetch`

```elixir
@spec fetch(t(), [term()]) :: [term()]
```

The rows of these ids that the sheet has (its source may show).

# `id`

```elixir
@spec id(t(), term()) :: term()
```

A row's id, as `update/3` and `delete/3` take it.

# `new`

```elixir
@spec new(keyword() | map()) :: t()
```

A sheet of a grid's attributes (a keyword list or a map, as
`data_grid/1` takes them). The attributes of the LiveView alone
(`issho`, `views`, `url`...) are left out.

# `rows`

```elixir
@spec rows(t(), keyword()) ::
  {:ok, %{rows: [term()], total: term()}} | {:error, String.t()}
```

Rows of the sheet, in an order, filtered and searched as a person
would (`Masu.Query.new/2`: `sort`, `filters`, `search`), from `offset`,
at most `limit` (50 unless given, 500 at most): `{:ok, %{rows:, total:}}`,
or what is wrong with the query. `total` is how many rows the query
has, or `{:at_least, n}` for a count the source caps.

# `to_map`

```elixir
@spec to_map(t(), term()) :: map()
```

A row as a person reads it in the grid: each column's key and value,
with the row's `"id"`.

# `update`

```elixir
@spec update(t(), [map()], keyword()) :: %{
  saved: [term()],
  errors: [error()],
  saving: [list()]
}
```

Edits cells, as a person types in them: each `%{"id" => id, "key" =>
key, "value" => value}`, with `"before"`, the value seen, to refuse an
edit of a cell someone changed since. Options: `scope` (in the
`Masu.Write`), `user` (who, for the history and the people who see the
rows change: `%{id:, name:}`), `by` (who, as the write's `by` says
them; `user` unless given), and `origin` (`:edit`, `:paste`...).

Gives the rows saved, and the errors, each `[id, key, message]` or,
for a cell changed meanwhile, `[id, key, message, value]`.

---

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