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

Where Next?

Popular in Questions Top

dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
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
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
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
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 I...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
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

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 127089 1222
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
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
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
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
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement