igor

igor

How to add a group of or_where conditions to the query which already has some where closes

If I have a form with filters filtering entities by some field and I want to add a group of or_where closes to the query dynamically.
And the query could already have some where closes which I want my group of or_where to be separated from by AND operator in db query.
So, I’d like to build the function like:

def add_composite_where_to_query(query, field_name, values) do
  # here is something I can't figure out..
end

This function should add where closes to query like:
SELECT * from entities e where (e.field1=‘value1’ OR e.field1=‘value2’) AND (e.field2=‘value3’ OR e.field2=‘value4’ OR …)

I’ve already tried many ways, but no luck.
As examples of what didn’t work:

def add_composite_where_to_query(query, field_name, values) do
  Enum.reduce(values, query, fn(value, acc) ->
    or_where(acc, [q], field(q, ^field_name) == ^value)
  end)
end
def add_composite_where_to_query(query, field_name, values) do
    dynamic = Enum.reduce(values, query, fn(value, dynamic) ->
      or_where(dynamic, association, ^field_name == ^value)
    end)
    where(query, ^dynamic)
end
def add_composite_where_to_query(query, field_name, values) do
    dynamics = Enum.reduce(values, [], fn(value, dynamics) ->
      dynamic([q], field(q, ^field_name) == ^value)
    end)
    where(query, ^dynamics)
end

Most Liked

al2o3cr

al2o3cr

FWIW, or_where does things that aren’t exactly intuitive - see the failing test here for an example. Be careful when composing queries with it.

OTOH, based on the function heads above I wonder if you’d be better served by an IN query rather than ORs since the query is checking for a single field being one of multiple values.

LostKobrakai

LostKobrakai

So where as well as or_where don’t just add a new condition to a query, but they also do it in a certain precedence order: (all_prev_conditions_of_the_query) AND|OR (newly_added_condition_s). So order plays an important role when composing where conditions.

If you’re looking for a different composition of conditions then you should probably look into the dynamic macro to build up the conditions and only attach the final result to the actual query.

LostKobrakai

LostKobrakai

If you need to group (put parenthesis around) conditions in a particular fashion, which contradicts the way precedence is handled by the where and or_where handling, then you need to create logic to explicitly create dynamic‘s for each group separately and only in the end put those groups together. Simply reducing over everything once probably won‘t cut it for those more complex conditions. As you cannot „add parenthesis“ after the fact you need to build up the correct groups when you‘re composing the single parts.

igor

igor

Thanks for all of you, guys, especially for you, @LostKobrakai, it seems finally struck me, here is what I came to for now:

def build_query_from_filters(query, filters) do
  if length(filters) do
    first = hd(filters)
    tail = tail(filters)
    conditions = build_dynamic_from_filter(first)
    conditions = Enum.reduce(tail, conditions, fn(filter, conditions) ->
      filter_conditions = build_dynamic_from_filter(filter)
      dynamic([q], ^filter_conditions and ^conditions)
    end)
    query |> where(^conditions)
  else
    query
  end  
end

def build_dynamic_from_filter(filter) do
  if is_list(filter.value) do
    conditions = false
    Enum.reduce(filter.value, conditions, fn(value, conditions) ->
      dynamic([q], field(q, ^filter.field_name) ilike ^value or ^conditions)
    end)
  else
    dynamic([q], field(q, ^filter.field_name) ilike ^filter.value)
  end
end

Where Next?

Popular in Questions Top

belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement