defmodule Permit.Ecto do defmacro __using__(opts) do alias Permit.Types alias Permit.Ecto.Permissions.UndefinedConditionError alias Permit.Ecto.Permissions.UnconvertibleConditionError quote do use Permit, unquote(opts) require Ecto.Query @spec repo() :: Ecto.Repo.t() def repo, do: unquote(opts[:repo]) @spec accessible_by( Types.subject(), Types.action_group(), Types.resource(), keyword() ) :: {:ok, Ecto.Query.t()} | {:error, term()} def accessible_by(current_user, action, resource, opts \\ []) do # base_query is (Types.resource() -> Ecto.Query.t()) opts = opts |> Keyword.put_new(:params, %{}) |> Keyword.put_new(:base_query, fn _action, resource_module, _subject, _params -> Ecto.Query.from(_ in resource_module) end) current_user |> can() |> Map.get(:permissions) |> Permit.Ecto.Permissions.construct_query( action, resource, current_user, actions_module(), opts ) end @spec accessible_by!( Types.subject(), Types.action_group(), Types.resource(), keyword() ) :: Ecto.Query.t() def accessible_by!(current_user, action, resource, opts \\ []) do case accessible_by(current_user, action, resource, opts) do {:ok, query} -> query {:error, {:undefined_condition, key}} -> raise UndefinedConditionError, key {:error, errors} -> raise UnconvertibleConditionError, errors end end def resolver_module, do: Permit.Ecto.Resolver end end require Ecto.Query @spec from(Ecto.Queryable.t()) :: Ecto.Query.t() def from(queryable) do Ecto.Query.from(queryable) end def filter_by_field(query, field_name, value) do query |> Ecto.Query.where([it], field(it, ^field_name) == ^value) end end