Hi everyone! I’m trying to build a generic prepare statement for a read operation. I’m working on a project with several “search” queries, and to include the search term on the query to postgress we use prepare. The goal here is to create a separate module with the prepare statement inside, so then we can call that module without having to duplicate code. The read operation would be something like this:
read :list do
argument :search_term, :string do
allow_nil? true
constraints min_length: 1, max_length: 50
end
prepare {Preparations.SearchTerm, field: "title"}
end
and the module:
defmodule Preparations.SearchTerm do
use Ash.Resource.Preparation
require Ash.Query
def init(opts) do
if is_nil(opts[:field]) do
{:error, "field is nil!"}
else
{:ok, opts}
end
end
def prepare(query, _, _) do
with term <- Ash.Query.get_argument(query, :search_term) do
search_term = "#{String.replace(term, ~r/\*%/, "\\\\1")}%"
## here's the error
query |> Ash.Query.filter(ilike(opts[:field], ^search_term))
else
_ ->
query
end
end
end
(“title” is an argument of the original module)
The thing is that when the query gets traslated to SQL, the field is translated as a literal string, which causes the query to don’t match with anything. I’ve tried by working with strings for the field and with atoms, with no success. The only way i could find to make it work was by referencing the actual title field on the ilike statement:
query |> Ash.Query.filter(ilike(title, ^search_term))
The problem with this is that it will only work for queries on tables with the “title” column on it. Not so generic.
Any clues on this? Any help is welcome!
Thanks!