How to pass "asc" or "desc" to the Ecto.query function

I have created some basic select list (asc, desc). I want to pass either strings to Ecto.query.

# order by order_by_expires
def order_by_expires(query, nil), do: query
def order_by_expires(query, direction) do
  query |> order_by(direction: :expires)
end

The above does not work, I get the error:

Ecto.Query.CompileError) expected :asc, :desc or interpolated value in order_by, got: :direction

I think you need to write:

order_by({direction, :expires})

Else direction: is the atom :direction.

I guess direction has to be converted to atom first:

if direction in ~W[asc desc], do: String.to_existing_atom(direction), else: :asc

Or much better, do pattern matching on direction:

defp do_order_by_expires(query, direction) do
    query |> order_by({direction, :expires})
end

def order_by_expires(query, "desc") do
  do_order_by_expires(query, :desc)
end

def order_by_expires(query, _) do
  do_order_by_expires(query, :asc)
end
2 Likes

A little modification was needed to get it to work:

defp do_order_by_expires(query, direction) do
    query |> order_by({^direction, :expires})
end

Thank you.

1 Like

The short method throws some strange error:

  def order_by_expires(query, direction) do
    if direction in ~W[asc desc], do: String.to_existing_atom(direction), else: :asc
    query |> order_by({^direction, :expires})
  end

I get this error message:

expected :asc or :desc in order_by, got: "asc" on line:

query |> order_by({^direction, :expires})

Any ideas what might be going on here? Thank you.

There has already been an answer to that question:

I had to rewrite the single method solution like this in order for it to work:

def order_by_expires(query, direction) do
if direction in ~W[asc desc], do: direction = String.to_existing_atom(direction), else: direction = :asc
query |> order_by({^direction, :expires})
end

Move the assignment out of the if:

def order_by_expires(query, direction) do
  direction = if direction in ~W[asc desc], do: String.to_existing_atom(direction), else: :asc
  query |> order_by({^direction, :expires})
end

You can also simplify it to:

def order_by_expires(query, direction) do
  direction = if direction == "desc", do: :desc, else: :asc
  query |> order_by({^direction, :expires})
end
5 Likes

Thank you very much Jose.