Your original example actually has an interesting issue that comes down to how Elixir as a language works
filter expr(definition_id == ^arg(:definition)[:id])
maps to this
filter expr(definition_id == ^(arg(:definition)[:id]))
But that isn’t what you want. thing[:id]
is a valid expression in Ash’s expression syntax. But to use it on something pinned, you need to add parenthesis
filter expr(definition_id == (^arg(:definition))[:id])
As for accepting multiple types, Ash has a built in union type for that. I wouldn’t suggest using :term
in general, but it is there to be an escape hatch for cases where it matters.
read :by_definition do
argument :definition, :union do
allow_nil? false
constraints [
types: [
definition: [type: :struct, constraints: [instance_of: Definition]],
definition_id: [type: :uuid]
]
]
end
prepare fn query, _ ->
definition_id =
case query.arguments.definition do
%Ash.Union{type: :definition_id, value: definition_id} -> definition_id
%Ash.Union{type: :definition, value: %{id: definition_id}} -> definition_id
end
Ash.Query.filter(query, definition_id == ^definition_id
end
end
It is a bit verbose, but there are ways to shrink it down and/or extract it into something reusable.