Search code examples
elixirecto

Calling my own predicate in "where" in Ecto


I want to be able to call a function or my predicated in "where" of Ecto. I'm trying this:

items = where(Item, [x], Item.my_predicate?(x))

# items = where(Item, [x], Item.my_predicate?(x) == true)

It throws an exception:

`Item.my_predicate?(x)` is not a valid query expression

How to fix it?


Solution

  • Of course it is possible however you cannot use functions but macros.

    Example:

    defmodule Foo do
      defmacro concat_ws(joiner, columns) do
        params_list = "?" |> List.duplicate(Enum.count(columns)) |> Enum.join(",")
    
        quote do
          fragment(unquote("concat_ws(?," <> params_list <>" )", joiner, unquote_splicing(columns))
        end
      end
    end
    
    items = where(Item, [x], Foo.concat_ws(" ", [x.a, x.b]) == "a b")
    

    Example without fragment:

    defmodule Foo do
      defmacro eql(a, b) do
        quote do: not (is_nil(a) or is_nil(b)) and a == b 
      end
    end
    

    But still macro result need to be valid query AST, so nothing fancy can land there.