Search code examples
elixirecto

Is it possible to merge two separate ecto queries?


I am wondering if it is possible to combine two queries together in ecto.

I would like to create a function which takes an ecto query and modifies it depending on the case.

For example, let's imagine we have a users table that allows duplicate usernames to be entered and a user creates the following query...

query = from(u in "users", select: u)
select_all_unique_users(query)

I would like the select_all_unique_users function to take query and add to it, so that it only selects the distinct usernames.

this is only an example, I know that I could create a unique_index on the table to avoid this in reality =D

As query is a struct under the hood, I figured I could update the distinct key do this. This seems to work, however the downside is that it doesn't seem very flexible and looks like it will be hard to implement if I ever want to add a more complicated logic.

Simply put, what I would like to do is create a function that takes a query and adds some more logic to it...

iex()> query = from(u in "users", select: u)
#Ecto.Query<from u0 in "users", select: u0>

iex()> select_all_unique_users(query)
#Ecto.Query<from u0 in "users", distinct: [asc: u0.username], select: u0>

Solution

  • The select_all_unique_users function would be implemented like this:

    defmodule TestModule do
      def select_all_unique_users(q) do
        from u in q, distinct: u.username
      end
    end
    

    And you can use it like below:

    iex(2)> query = from(u in "users", select: u)
    #Ecto.Query<from u in "users", select: u>
    
    iex(3)> distinct = TestModule.select_all_unique_users(query)
    #Ecto.Query<from u in "users", distinct: [asc: u.username], select: u>
    

    I wrapped select_all_unique_users in a module I created for the purpose of this answer, but you can place it in any module you see fit.