Hey there, still learning elixir with a python background, I came across an error that I can not fully understand.
I’m building an Ecto query dynamically, I have several functions handling several filters that I compose reducing the filter enum. This is a sample of what I’m doing:
...
def make_query(some_id, filters \\ %{}) do
from(
t in Thing, as: :thing,
left_join: s in assoc(s, :stuff), as: :stuff,
where: t.id == ^some_id,
group_by: t.id
)
|> apply_filters(filters)
|> Repo.all()
end
defp apply_filters(query, filters) do
Enum.reduce(filters, query, &apply_filter/2)
end
defp apply_filter({:name, name}, query) when present?(name) do
where(query, [thing: t], fragment("lower(?) = lower(?)", t.name, ^name))
end
defp apply_filter({:some_bool, bool_value}, query) when present?(bool_value) do
case bool_value do
0 -> where(query, [stuff: s], is_nil(s.id))
_ -> where(query, [stuff: s], not is_nil(s.id))
end
end
... some other filter funcs, and then:
defp apply_filter({:fuzzy, text}, query) when present?(text) do
Enum.reduce(String.split(text), query, &apply_fuzzy/2)
end
defp apply_fuzzy(word, query) when present?(word) do
where(
query,
[thing: t, stuff: s],
(fragment("metaphone(?, 2) = metaphone(?, 2)", t.foo, ^word) or
fragment("metaphone(?, 2) = metaphone(?, 2)", t.bar, ^word) or
fragment("metaphone(?, 2) = metaphone(?, 2)", s.baz, ^word)) and
(fragment("levenshtein(lower(?),lower(?)) < 4", t.foo, ^word) or
fragment("levenshtein(lower(?),lower(?)) < 4", t.bar, ^word) or
fragment("levenshtein(lower(?),lower(?)) < 4", s.baz, ^word))
)
end
...
The problem here shows up in the apply_fuzzy/2
, if I run this everything works fine, but if I change the where
in apply_fuzzy/2
with or_where
, I get a compilation error:
defp apply_fuzzy(word, query) when present?(word) do
or_where(
query,
....
→
warning: variable "t" does not exist and is being expanded to "t()", please use parentheses to remove the ambiguity or change the variable name
lib/app/thing/loader.ex:125: App.Thing.Loader.apply_fuzzy/2
warning: variable "t" does not exist and is being expanded to "t()", please use parentheses to remove the ambiguity or change the variable name
lib/app/thing/loader.ex:125: App.Thing.Loader.apply_fuzzy/2
warning: variable "s" does not exist and is being expanded to "s)", please use parentheses to remove the ambiguity or change the variable name
lib/app/thing/loader.ex:126: App.Thing.apply_fuzzy/2
== Compilation error in file lib/app/thing/loader.ex ==
** (CompileError) lib/app/thing/loader.ex:126: cannot use ^word outside of match clauses
(elixir 1.13.4) expanding macro: Kernel.or/2
lib/app/thing/loader.ex:126: App.Thing.Loader.apply_fuzzy/2
(elixir 1.13.4) expanding macro: Kernel.or/2
Docs says:
An OR where query expression.
Behaves exactly the same as
where
except it combines with any previous expression by using anOR
.
I’m considering “Behaves exactly the same as where
” to mean that I can replace one with another to only change and AND
with an OR
, is this assumption wrong? What am I missing?
I’m not looking for a solution to my fuzzy query, I’m only trying to understand why I get the compilation error.