Rewriting this where using private fn

I have the following function that I want to rewrite using the defp

def list_items(%{matching: name}) when is_binary(name) do
    Item
    |> where([m], ilike(m.name, ^"%#{name}%"))
    |> Repo.all()
  end

What I tried

def list_items(%{matching: name}) when is_binary(name) do
    Item
    |> search(term)
    |> Repo.all()
  end

  defp search(term) do
    term
    |> from t in Item
    |> where([t], ilike(t.name, ^"%#{term}%"))
  end

Can someone explain how to do this?

from` must be a compile time keyword list

Shouldn’t Item work here?
Thanks

    term
    |> from t in Item

This isn’t a valid way to use from, it expands to from(term, t in Item) since |> puts arguments at the front.

1 Like

What can I pipe it through?

When you’re using from you don’t pipe.

See this topic:

#keywords query syntax
import Ecto.Query
from u in “users”, where: u.age > 18, select: u.name

#pipe-based syntax
“users”
|> where([u], u.age > 18)
|> select([u], u.name)
1 Like

This works

def list_items(%{matching: name}) when is_binary(name) do
    Item
    # |> where([m], ilike(m.name, ^"%#{name}%"))
    |> search(name)
    |> Repo.all()
  end

  defp search(query, name) do
    query = from(query in Item)

    query
    |> where([t], ilike(t.name, ^"%#{name}%"))
  end

But I get a dializer error with unused query variable. Is there a better way to do this?

You can’t pipe into from. The ecto docs contain examples of how to use pipe with where, you don’t need to use from.

1 Like

I couldn’t think of another way that is why, I am asking.

I also read through the docs.

Hi , I kind of did this for my requirement. hope it helps you,

def search(params)
 qfilters       = reject_empty_values(params)
search_q =  profile_q(qfilters)
(from p in search_q , where: p.id == 2) |> Repo.all
end
defp profile_query([]), do: Profile
defp profile_query(filters) do
  from q in Profile, where: filters
end
1 Like

Thanks but i am trying to keep the public fn clean and use only pipes there and do the actual work in private fn.

How about this

def search(model, %{name: name} = params) do
   model
   |> search_q(name)
   |> Repo.all
end

defp search_q(model, name) do
  from m in model, where: m.name == name
end
1 Like

Interesting, I am now wondering if if can keep and do

def list_items(%{matching: name, query: query}) when is_binary(name) do
    Item
    # |> where([m], ilike(m.name, ^"%#{name}%"))
    |> search(name)
    |> Repo.all()
  end

This works without errors and it gets simple when i wnat to add other defp and pipe them together in a composition

def list_items(%{matching: name}) when is_binary(name) do
    Item
    # |> where([m], ilike(m.name, ^"%#{name}%"))
    |> search(name)
    |> Repo.all()
  end

  defp search(_query, name) do
    query = from(query in Item)

    query
    |> where([t], ilike(t.name, ^"%#{name}%"))
  end

you are trying to search name or query? , we can still pass it as params and do another where,
ecto supports array in query for and operations

filters = [ name: params[:name], age: params[:age] ]
qfilters = reject_empty_values(filters)
from m in model, where: qfilters
 
1 Like

No, I am rewriting this to suit my style and understand more how Ecto works with phoenix and absinthe. Also to make it more compos-able using the composition pattern.

def list_items(%{matching: name}) when is_binary(name) do
   Item
   |> where([m], ilike(m.name, ^"%#{name}%"))
   |> Repo.all()
 end

try the from using like this:
from "items"

1 Like

ahh, i get it. cool.
you are planning to |> search_by_name, search_by_age

def search(%{name: name, age: age} = params}) do
  model 
  |> sname(name)
  |> sage(age)
  |> Repo.all
end

defp sname(query, name), do:  from q in query, where: q.name == name
defp sage(query, age), do: from q in query, where: q.age == age

Hope it works, 
1 Like

Something like that.

If you don’t want to get a Dializer error use _query.

Thanks I will try that.

hmm okay, but we are using query in those private functions. right. Did it work?

Yep, if the query is there it will be used but Dializer will not complain