Is there a "Ash way" to group db items?

Say I’ve got a resource

defmodule Log do
...
  attributes do
    uuid_primary_key :id
    attribute :fiber_id, :string
    attribute :process_id, :integer
    attribute :data, :map
    ...
  end
end

I would like to read the db, then group these logs in a certain way

[
  %{
    process_id: 406,
    fiber_id: "1751574781326x565732960809615900",
    logs: [
      %Bubblelog.Bubble.Log{
        id: "3100d75b-069b-411e-885f-ac002217eb9c",
        data: %{...}
       ...
     },
     %Bubblelog.Bubble.Log{...},
   ] 
...

I figured I should create a read action, then put it through a Preparation using Ash.Query.after_action, etc.. But I was running into the problem that this action was returning something that is not a Struct. My imaginary friend Claude suggested a manual_action which didn’t work so we settled on a normal Elixir function do this transformation.

Is there an Ash way of doing this?

I think what you want is a generic action. That’s like a normal elixir function the ash way.

1 Like

Thanks!

Could I integrate it with a read action into the generic action and use the built-in Ash pagination? In my simple mind it seems easier to keep them separate: first read, then group them. Is there a way to build the read action into the generic action?

Don’t see why not. You could even make an interface for the read action and first thing you do in your generic action is call that.

1 Like

Make synthetic resource for process and have that as your entry point. You can use a combination of a has many with no attributes linking to a process id attribute on the process resource.

Then fill the process id with an arg in a prepare on the read. This should let you do a Process read and then load the logs.

You can use calcs or aggregates to fill the other columns for process, I didnt study the data model too closely.

You can do a lot of this stuff with datalayerless resources. You could even have two resources point to the same table and just map with a has many :man_shrugging:t2:

2 Likes

Great, thanks! I got a lot of homework for the weekend.

Couldn’t you even do something like this?

defmodule Bubblelog.Bubble.Process do
  use Ash.Resource

  attributes do
    integer_primary_key :id
  end
  
  actions do
    defaults [:read, :destroy, create: :*, update: :*]
  end
  
  code_interface do
    define :read
  end

  relationships do
    has_many :logs, Bubblelog.Bubble.Log
  end
end

defmodule Bubblelog.Bubble.Log do
  use Ash.Resource

  attributes do
    uuid_primary_key :id
    attribute :data, :map, description: "I dont know what this is?"
  end

  relationships do
    belongs_to :process, Bubblelog.Bubble.Process
  end
  
  actions do
    defaults [:read, :destroy, create: :*, update: :*]
  end
end

For sure this is missing some keys in the relationships and what not and at least the Log module should probably also have a proper data_layer but I think you could model this with regular relationships?