Ash Calculation on an array of maps

I have a resource that has an attribute that is an array of embedded resources.

I have module calculation that maps the embedded resources and returns a list of values. Pretty trivial in elixir. I’d like to also implement this as an Ash expression so that can be selected (and filtered against) at the data layer (postgres).

  def calculate(records, opts, _) do
    Enum.map(records, fn record -> 
      Map.get(record, opts[:embedded_resources])
      |> Enum.map(fn embedded_resource ->
        Map.get(embedded_resource, opts[:embedded_attribute])
      end)
    end)
  end

Is this possible with Ash expressions? Or should I just normalize this and have an attribute on record that is set on create/update?

I’ve experimented with doing this as a SQL fragment but that requires unnesting the embedded resource, lateral joining tables, and grouping. Technically possible, but doesn’t make for an Ash expression.

There is nothing in Ash expressions that will currently let you do that unfortunately. You’ll either need to use a fragment or normalize the value you want calculated into an attribute.

Do you know if it’s possible with a fragment? The only way I’ve been able to do it is by unnesting the embedded resources into a subquery and then grouping the unnested values back together?

You can do entire subqueries in a fragment:

fragment("(SELECT ... FROM UNNEST(?))", array)

If you’re using Postgres jsonb columns then you can do aggregates with one of the json aggregrate functions. Postgres aggregates are listed here.