I have the following functions that wraps my ecto queries in :ok|:error
tuples, with the accompanying specs
@type fetch_one_result :: {:ok, Ecto.Schema.t()} | {:error, :not_found | :too_many_results}
@spec fetch_one(Ecto.Queryable.t()) :: fetch_one_result()
@doc """
Get one row from repo, wraps result in {:ok, _} or {:error, _} tuple.
{:ok, result} when one row is returned
{:error, :not_found} when no rows are returned
{:error, :too_many_results} when more than one row is returned
"""
def fetch_one(query) do
...
end
@spec fetch_one_by(Ecto.Queryable.t(), [{atom(), any()}]) :: fetch_one_result()
@doc """
Get one row from repo, by key-values provided, wraps result in {:ok, _} or {:error, _} tuple.
{:ok, result} when one row is returned
{:error, :not_found} when no rows are returned
{:error, :too_many_results} when more than one row is returned
"""
def fetch_one_by(schema, [{key, value}]) do
...
|> where(^[{key, value}])
|> fetch_one()
end
fetch_one_by
delegates to fetch_one
. I didn’t want to have to keep the two specs in sync manually, so I define the return type (fetch_one_result
) and use that.
My issue is that my LSP/tooling (correctly) reports the return type as :: fetch_one_result
, not the actual tuple values. This isn’t terrible but it’s a bit of a UX/DX pain.
Is there a way to:
- Not have to duplicate my tuple definitions and
- Have tooling recognize the “through” typing?
I tried a simple @fetch_one_result {:ok..
but it fails because I have the pipe in there for different error types, it’s not valid “code”.