Calculations Using Relationships

I'm writing a simple chat app to try to learn Ash. I have models like below and I'd like to write an :unread_count calculation on the Channel. It would take the current user as the actor and find the associated member of the channel, use that :last_read_at time to filter down the messages associated with the channel to ones that has a :created_at after that time, and count them. I'm having a hard time figuring out how to do that based on the examples. What I think I want is something like:
calculations do
calculate :unread_count,
:integer, expr(length(messages.channel_id == ^arg(:channel_id) && messages.created_at > current_member.last_read_at))
end
calculations do
calculate :unread_count,
:integer, expr(length(messages.channel_id == ^arg(:channel_id) && messages.created_at > current_member.last_read_at))
end
Assuming :current_member is another calculation that exists to get the member associated with the current user. Apologies if I'm thinking about this in the completely wrong way and thanks in advance for the help! Models
defmodule App.Chat.Channel do
relationships do
many_to_many :members, App.Account.User do
through App.Chat.ChannelMember
source_attribute_on_join_resource :channel_id
destination_attribute_on_join_resource :user_id
writable? true
filterable? true
end

has_many :messages, App.Chat.Message do
sort created_at: :desc
filterable? true
end
end
end
defmodule App.Chat.Channel do
relationships do
many_to_many :members, App.Account.User do
through App.Chat.ChannelMember
source_attribute_on_join_resource :channel_id
destination_attribute_on_join_resource :user_id
writable? true
filterable? true
end

has_many :messages, App.Chat.Message do
sort created_at: :desc
filterable? true
end
end
end
defmodule App.Chat.ChannelMember do
attributes do
attribute :channel_last_read_at, :utc_datetime_usec
end

relationships do
belongs_to :channel, App.Chat.Channel, primary_key?: true, allow_nil?: false
belongs_to :user, App.Account.User, primary_key?: true, allow_nil?: false
end
end
defmodule App.Chat.ChannelMember do
attributes do
attribute :channel_last_read_at, :utc_datetime_usec
end

relationships do
belongs_to :channel, App.Chat.Channel, primary_key?: true, allow_nil?: false
belongs_to :user, App.Account.User, primary_key?: true, allow_nil?: false
end
end
defmodule App.Chat.Message do
attributes do
create_timestamp :created_at
end

relationships do
belongs_to :channel, App.Chat.Channel do
allow_nil? false
attribute_writable? true
end
end
end
defmodule App.Chat.Message do
attributes do
create_timestamp :created_at
end

relationships do
belongs_to :channel, App.Chat.Channel do
allow_nil? false
attribute_writable? true
end
end
end
4 Replies
ZachDaniel
ZachDaniel•2y ago
You're thinking about it in the right way, but this might be one that requires dipping down into SQL actually There are a few ways you can go about it You can do it in a separate query like so:
defmodule YourCalc do
def calculate(records, _, _) do
run_ecto_query
|> group_by_record_id()
end
end
defmodule YourCalc do
def calculate(records, _, _) do
run_ecto_query
|> group_by_record_id()
end
end
Theres a lot to unpack in that calculation 😆 What might be easier is adding calculation args Do you need to be able to filter/sort on this value?
bahalperin
bahalperinOP•2y ago
Thanks for the quick response! Nope, was just going to display it next to the name of the channel, like slack. When you say "adding calculation args" do you mean like having multiple separate calculations that take arguments? Like getting all the unread messages given a timestamp? And then do more of the work in separate steps outside of one calculation? Like load current channel member -> get unread messages given their last read timestamp?
ZachDaniel
ZachDaniel•2y ago
In that case, I'd suggest using a module-based calculation 🙂 You can run an ecto query or any other thing to get the data you want that way
bahalperin
bahalperinOP•2y ago
Just making sure I'm looking at the right thing, this is what you're talking about? https://ash-hq.org/docs/guides/ash/latest/topics/calculations#module-calculations. Think I missed those in the docs before. Thank you!!
Ash HQ
Guide: Calculations
Read the "Calculations" guide on Ash HQ

Did you find this page helpful?