# `Masu.Source.Ecto`
[🔗](https://github.com/hattoriai/masu/blob/v0.7.0/lib/masu/source/ecto.ex#L2)

The source of a grid given an Ecto query or schema and a repo:
`<.data_grid source={from(o in Order, where: o.shop_id == ^shop.id)} repo={Repo}>`.

The database does the work. A sort is an `ORDER BY`, a filter and the
search a `WHERE`, the count a `count(*)` of the query, and each block
the browser asks for one `LIMIT`: the block after a block it read by
the sort values of that block's last row, not by `OFFSET` (see
[Export, selection and large tables](export.md)). The LiveView never
holds more rows than the screen shows.

The query may already have its own `where`, `join` and `preload`: the
grid's filters are added to them. The grid's order replaces the
query's while the person sorts, and the query's order is used when
they do not. After the grid's order comes the schema's primary key, so
that rows of equal values do not move from one block to the next.

A column sorts and filters in the database when it names a field of
the query's first source (`field={:total}`), or a field of a related
row through the schema's associations (`field={[:customer, :name]}`).
A column with a `value` function is shown, but does not sort or
filter.

## Related rows

A path of `belongs_to` and `has_one` associations is one value. The
source joins each step (`LEFT JOIN`, a named binding: `:customer`,
then `:customer_company`) when a sort, a filter, the search or a group
needs it, and uses a binding of that name that the query already has.
A row with no related row has `NULL` there. The source preloads the
associations of the paths, so that each row shows its values and the
blocks are read by key.

A path through a `has_many` or `many_to_many` is of many values. It
filters and searches with a subquery of the related rows (`id IN
(SELECT ...)`), never a join, so that the rows are not repeated and
the count stays right; it does not sort or group. The schema needs one
primary key.

The text filters and the search compare without case with
`lower(field) LIKE ...`, which PostgreSQL, MySQL and SQLite all run.
An index on `lower(field)` makes them fast on a large table.

## A tree

With the grid's `tree` (a field that holds the parent's id), the rows
are a tree (`Masu.Tree`). The source keeps the ids of the rows that
show, not the rows: the roots, in the grid's order, and the children
of each row the person opens, read when it opens; each block of rows
is then read by its ids. A filter or a search reads the ids of the
rows that match and climbs to their ancestors, a level per query. The
schema needs one primary key.

## Options

  * `:repo` (required) - the repo that runs the queries.
  * `:repo_opts` - options for each call to the repo, such as
    `prefix:` for a tenant's schema.
  * `:count_limit` - the most rows the count counts: past it, the
    count is `{:at_least, limit}`.
  * `:read` - a read of a block of rows of the app's own: a function
    of the query and `%{offset:, limit:, order:, after:}` (see "A
    read of your own" in the [Sources](sources.md) guide).

---

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