Ecto.Queryable протокол
Исходный кодПреобразует структуру данных в Ecto.Query.
Это используется в Ecto.Repo, а также макросом from. Например, Repo.all ожидает в качестве аргумента любой объект, поддерживающий запросы, поэтому можно написать Repo.all(MySchema) или Repo.all(query). Кроме того, когда вы пишете from ALIAS in QUERYABLE, QUERYABLE принимает любую структуру данных, реализующую Ecto.Queryable.
Этот модуль определяет несколько реализаций по умолчанию. Рассмотрим каждую из них и способы их использования.
Atom
Наиболее распространённый вариант использования этого протокола — преобразование атомов, представляющих модуль Ecto.Schema, в запрос. Это происходит, когда вы пишете:
query = from(p in Person)
Или когда напрямую передаёте схему репозиторию:
Repo.all(Person)
Если вы не знали, модули Elixir — это просто атомы. Эта реализация принимает имя указанного модуля и пытается загрузить связанную с ним схему. Если схема не существует, будет вызвано исключение Protocol.UndefinedError.
BitString
Эта реализация позволяет напрямую указать таблицу, из которой нужно выполнить запрос:
from(
p in "people",
select: {p.first_name, p.last_name}
)
Или:
Repo.delete_all("people")
Хотя это довольно просто, для некоторых операций репозитория, таких как Repo.all, требуется выражение select. При запросе к схеме список выбираемых полей определяется автоматически на основе полей схемы, но при прямой передаче таблицы их нужно перечислить явно. Это ограничение подводит нас к следующей реализации!
Tuple
Подобно реализации BitString, эта реализация позволяет указать базовую таблицу, из которой нужно выполнить запрос; однако, кроме того, она позволяет указать используемую схему:
from(p in {"filtered_people", Person})
Это может быть особенно полезно, если у вас есть представления базы данных, которые фильтруют или агрегируют данные исходной таблицы, но используют ту же схему. Это позволяет повторно использовать одну и ту же схему, указывая отдельный «источник» данных.
Ecto.Query
Это простая передача без изменений. Ведь любой экземпляр Ecto.Query можно преобразовать в Ecto.Query:
Repo.all(from u in User, where: u.active)
Это также позволяет объединять запросы Ecto: один запрос можно передать в качестве источника другого:
active_users = from u in User, where: u.active ordered_active_users = from u in active_users, order_by: u.created_at
Ecto.SubQuery
Ecto также позволяет объединять запросы с помощью подзапросов. Представьте, что у вас есть таблица «люди». Теперь представьте, что вы хотите выполнить операцию над людьми с наиболее распространёнными фамилиями. Чтобы получить такой список, можно написать следующее:
sub = from(
p in Person,
group_by: p.last_name,
having: count(p.last_name) > 1,
select: %{last_name: p.last_name, count: count(p.last_name)}
)
Если теперь вы хотите выполнить с этими данными что-то ещё, например присоединить дополнительные таблицы и выполнить вычисления, это можно сделать так:
from( p in subquery(sub), # other filtering etc here )
Обратите внимание, что здесь необходим макрос Ecto.Query.subquery/2, чтобы преобразовать Ecto.Query в экземпляр Ecto.SubQuery. Затем этот протокол оборачивает его в Ecto.Query, используя переданный подзапрос в предложении FROM. Дополнительные сведения см. в разделе Ecto.Query.subquery/2.
Сводка
- t()
Все типы, реализующие этот протокол.
Типы
- to_query(data)
Преобразует переданный
dataвEcto.Query.
Функции
Типы
t()Исходный код
@type t() :: term()
Все типы, реализующие этот протокол.
Функции
to_query(data)Исходный код
Преобразует переданный data в Ecto.Query.
© 2014 Chris McCord
Licensed under the MIT License.
https://ecto.hexdocs.pm/Ecto.Queryable.html