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

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New

Other popular topics 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
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
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
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New

We're in Beta

About us Mission Statement