tankh7

tankh7

Ecto.Query need help writing a query with expressions and dynamic queries

I’m writing a query to filter out payments. We can filter on payment name, status, date from, date to, amount from, and amount to. I’ve gotten the queries working for all but amount from and amount to, as they are a bit more complex and involve using a join/subquery.

A payment relates to a payment_method which contains the information for the amount that was sent. It’s a one to one relationship, with payment referencing a payment_method's id through a funding_id.

I need to be able to filter all payments that fall within an amount range.

Here’s the part of the query I’m in need of help on:

def search(user_id, params) do
#MAIN QUERY
q = Payments.Schema
      |> where([user_id: ^user_id])
      |> where(^filter_name(params[:name]))
      |> where(^filter_status(params[:status]))
      |> where(^filter_date_from(params[:date_from]))
      |> where(^filter_date_to(params[:date_to]))
      |> join(:inner, ^filter_amount(params[:amount_from], params[:amount_to]))

#THIS FUNCTION DOESN'T CURRENTLY WORK  
defp filter_amount(amount_from, amount_to) when is_integer(amount_from) and is_integer(amount_to) do
    dynamic([t], t.funding_id in subquery(
        p = PaymentMethods.Schema
          |> where(p.amount >= ^amount_from)
          |> where(p.amount <= ^amount_to)
    ), t.funding_id = p.id)
  end
defp filter_amount(_amount_from, _amount_to), do: true

I get this error currently in the terminal:

== Compilation error in file lib/users/payments/payments.ex ==
** (Ecto.Query.CompileError) unbound variable `p` in query

Any help would be appreciated!

UPDATE

I’ve changed the code to the below:

def search(user_id, params) do
    #MAIN QUERY
    q = Payments.Schema
          |> where([user_id: ^user_id])
          |> where(^filter_name(params[:name]))
          |> where(^filter_status(params[:status]))
          |> where(^filter_date_from(params[:date_from]))
          |> where(^filter_date_to(params[:date_to]))
          |> join(:inner, [t], p in subquery(^filter_amount(params[:amount_from], params[:amount_to]), t.funding_id == p.id))


defp filter_amount(amount_from, amount_to) when is_integer(amount_from) and is_integer(amount_to) do
     PullTransactions.Schema
         |> where(pt.amount >= ^amount_from)
         |> where(pt.amount <= ^amount_to)
end
defp filter_amount(_amount_from, _amount_to), do: true

The error I’m getting in the terminal is this:

cannot use ^filter_amount(params[:amount_from], params[:amount_to]) outside of match clauses

Most Liked

blatyo

blatyo

Conduit Core Team

My preference is to write things like this because it makes compossible filters and requires much less of the odd dynamic functions and looks more like the SQL I would write:

def search(user_id, params) do
  __MODULE__
  |> filter_by_user(user_id)
  |> filter_by_name(params[:name])
  |> filter_by_amount(params[:amount_from], params[:amount_to])
end

def filter_by_user(query, user_id) do
  from(p in query, where: p.user_id == ^user_id)
end

def filter_by_name(query, name) do
  from(p in query, where: p.name == ^name)
end

def filter_by_amount(query, amount_from, amount_to) do
  from(p in query, 
    inner_join: pm in PaymentMethods.Schema,
    on: p.funding_id = pm.id 
      and pm.amount >= ^amount_from 
      and pm.amount <= ^amount_to)
end
yurko

yurko

It’s a one to one relationship, with payment referencing a payment_method’s id through a funding_id.

If it’s one to one then you can just join it normally and then write another where for further filtering (you’d have both table bindings then).

tankh7

tankh7

@dokuzbir

Thanks for the help - I tried what you suggested and I get the following in the terminal.

These two warnings:

warning: variable "t" does not exist and is being expanded to "t()", please use parentheses to remove the ambiguity or change the variable name

warning: variable "p" does not exist and is being expanded to "p()", please use parentheses to remove the ambiguity or change the variable name

And I get this compile error:

Compilation error in file lib/users/payments/payments.ex ==
** (CompileError) lib/teller/users/payments/payments.ex:42: undefined function p/0
dokuzbir

dokuzbir

as @yurko commented try that simpler way

|> join(:inner, [t], q in PullTransactions.Schema, t.funding_id == q.id) 
|> where([p,pt], pt.amount >= ^params[:amount_from] and pt.amount <= ^params[:amount_to] )

Where Next?

Popular in Questions Top

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
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
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
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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
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
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement