luzny
luzny

Reputation: 2400

How to build dynamic where clause?

I have list of field names eg. [:type, :car_id] and changeset whereof I want to get data from each field as scope. How to build dynamic where clause with and between each expression created from list of fields, can I interpolate in where expression created earlier?

Not dynamic example:

def scoped_query(query, changeset, fields_names) do
  type_field = List.first(fields_names)
  car_id_field = List.last(fields_names)
  scope1 = get_field(changeset, type_field)
  scope2 = get_field(changeset, car_id_field)
  query |> where([m], field(m, ^type_field) == ^scope1 and field(m, ^car_id_field) == ^scope2)
end

Upvotes: 1

Views: 1101

Answers (2)

Dogbert
Dogbert

Reputation: 222138

Since you want to compare on == and join them with and, you can simply pass a keyword list to where making use of Bindingless Queries in Ecto 2.0+:

def scoped_query(query, changeset, fields_names) do
  criteria = for field <- fields_names, do: {field, get_field(changeset, field)}
  query |> where(^criteria)
end

Upvotes: 5

Gazler
Gazler

Reputation: 84150

You can use Enum.reduce/3 with the initial query to build up the wheres:

Enum.reduce([:type, :car_id], query, fn field, acc ->
  value = get_field(changeset, field)
  where(acc, [m],field(m, ^field) == ^value)
end)

Upvotes: 1

Related Questions