Hi there, basically I’m trying to create an aggregation that would be similar to this:
Enum.any?(values, fn x -> x end)
The value I’m trying to aggregate is called :fix_and_flip?
which is a boolean calculation inside a resource that I get from a has_many
called :owner_records
I think I can achieve that with the first
aggregate:
first :fix_and_flip?, :owner_records, :fix_and_flip? do
filter [fix_and_flip?: true]
end
But when I load this aggregate, I get the following error:
{:error,
%Ash.Error.Unknown{
errors: [
%Ash.Error.Unknown.UnknownError{
error: "** (Ecto.SubQueryError) the following exception happened when compiling a subquery.\n\n ** (Ecto.QueryError) /run/host/home/sezdocs/projects/rebuilt/platform/pacman/deps/ash_postgres/lib/aggregate.ex:1049: field `property_id` in `select` does not exist in schema Pacman.Raw.Record in query:\n \n from r0 in Pacman.Raw.Record,\n as: 0,\n left_join: r1 in Pacman.Raw.Record,\n on: type(\n as(1).external_id,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ) ==\n type(\n as(0).external_id,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ) and\n fragment(\n \"(? %> ?)\",\n type(\n as(1).first_grantor_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ),\n type(\n as(0).first_grantee_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n )\n ) and\n not (is_nil(\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n )\n ) == ^true) and\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) >=\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(0).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) and not type(as(1).deleted?, {:parameterized, Ash.Type.Boolean.EctoType, []}),\n where: fragment(\n \"(? %> ?)\",\n type(\n as(0).first_grantee_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ),\n type(\n fragment(\n \"jsonb_extract_path_text(?::jsonb,?::text)\",\n type(\n parent_as(0).first_owner,\n {:parameterized, Pacman.Markets.Property.Owner.EctoType, []}\n ),\n ^\"full_name\"\n ),\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n )\n ),\n where: type(\n fragment(\n \"coalesce(? between ? and ?, false)\",\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) -\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(0).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ),\n ^90,\n ^270\n ),\n {:parameterized, Ash.Type.Boolean.EctoType, []}\n ) == type(^true, {:parameterized, Ash.Type.Boolean.EctoType, []}),\n where: parent_as(0).id == as(0).property_id,\n group_by: [r0.property_id],\n select: %{\n fix_and_flip?:\n type(\n fragment(\n \"(?)[1]\",\n fragment(\n \"array_agg(?)\",\n type(\n fragment(\n \"coalesce(? between ? and ?, false)\",\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) -\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n " <> ...,
field: nil,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}
],
stacktraces?: true,
changeset: nil,
query: #Ash.Query<
resource: Pacman.Markets.Property,
load: [owner_records: []],
aggregates: %{
fix_and_flip?: #first<
owner_records.fix_and_flip? from #Ash.Query<resource: Pacman.Raw.Record,
filter: #Ash.Filter<fix_and_flip? == true>>
>
},
errors: [
%Ash.Error.Unknown.UnknownError{
error: "** (Ecto.SubQueryError) the following exception happened when compiling a subquery.\n\n ** (Ecto.QueryError) /run/host/home/sezdocs/projects/rebuilt/platform/pacman/deps/ash_postgres/lib/aggregate.ex:1049: field `property_id` in `select` does not exist in schema Pacman.Raw.Record in query:\n \n from r0 in Pacman.Raw.Record,\n as: 0,\n left_join: r1 in Pacman.Raw.Record,\n on: type(\n as(1).external_id,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ) ==\n type(\n as(0).external_id,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ) and\n fragment(\n \"(? %> ?)\",\n type(\n as(1).first_grantor_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ),\n type(\n as(0).first_grantee_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n )\n ) and\n not (is_nil(\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n )\n ) == ^true) and\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) >=\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(0).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) and not type(as(1).deleted?, {:parameterized, Ash.Type.Boolean.EctoType, []}),\n where: fragment(\n \"(? %> ?)\",\n type(\n as(0).first_grantee_full_name,\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n ),\n type(\n fragment(\n \"jsonb_extract_path_text(?::jsonb,?::text)\",\n type(\n parent_as(0).first_owner,\n {:parameterized, Pacman.Markets.Property.Owner.EctoType, []}\n ),\n ^\"full_name\"\n ),\n {:parameterized, Ash.Type.StringWrapper.EctoType, allow_empty?: false, trim?: true,\n max_length: 255}\n )\n ),\n where: type(\n fragment(\n \"coalesce(? between ? and ?, false)\",\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) -\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(0).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ),\n ^90,\n ^270\n ),\n {:parameterized, Ash.Type.Boolean.EctoType, []}\n ) == type(^true, {:parameterized, Ash.Type.Boolean.EctoType, []}),\n where: parent_as(0).id == as(0).property_id,\n group_by: [r0.property_id],\n select: %{\n fix_and_flip?:\n type(\n fragment(\n \"(?)[1]\",\n fragment(\n \"array_agg(?)\",\n type(\n fragment(\n \"coalesce(? between ? and ?, false)\",\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(1).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n type(as(1).instrument_date, {:parameterized, Ash.Type.Date.EctoType, []})\n ) -\n fragment(\n \"ash_elixir_or(?, ?)\",\n type(as(0).recording_date, {:parameterized, Ash.Type.Date.EctoType, []}),\n " <> ...,
field: nil,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}
]
>,
error_context: [nil],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :unknown
}}
Just for completeness, here is the has_many
block:
has_many :owner_records, Record do
no_attributes? true
read_action :valid
filter expr(
fragment("(? %> ?)", first_grantee_full_name, parent(first_owner[:full_name]))
)
end
And here is the calculation I’m using in the joined resource:
calculate :fix_and_flip?,
:boolean,
expr(
fragment(
"coalesce(? between ? and ?, false)",
(sell_record.recording_date || sell_record.instrument_date) -
(recording_date || instrument_date),
90,
270
)
) do
allow_nil? false
end