sezaru

sezaru

In my system, I have the following resources:

defmodule Core.Feedbacks.Student do
  relationships do
    alias Core.Feedbacks

    has_many :feedbacks, Feedbacks.Feedback

    many_to_many :classes, Feedbacks.Class do
      through Feedbacks.StudentClass
      join_relationship :student_classes

      source_attribute_on_join_resource :student_id
      destination_attribute_on_join_resource :class_id
    end
  end
end

defmodule Core.Feedbacks.Class do
  relationships do
    alias Core.Feedbacks

    has_many :feedbacks, Feedbacks.Feedback

    many_to_many :students, Feedbacks.Student do
      through Feedbacks.StudentClass

      source_attribute_on_join_resource :class_id
      destination_attribute_on_join_resource :student_id
    end
  end
end

defmodule Core.Feedbacks.StudentClass do
  relationships do
    alias Core.Feedbacks.{Student, Class}

    belongs_to :student, Student do
      primary_key? true
      allow_nil? false
      attribute_writable? true
    end

    belongs_to :class, Class do
      primary_key? true
      allow_nil? false
      attribute_writable? true
    end
  end
end

defmodule Core.Feedbacks.Feedback do
  relationships do
    alias Core.Feedbacks

    belongs_to :student, Feedbacks.Student do
      allow_nil? false
      attribute_writable? true
    end

    belongs_to :class, Feedbacks.Class do
      allow_nil? false
      attribute_writable? true
    end
  end
end

As you can see, the Student resource has a many_to_many relationship with the Class resource and both resources have a has_many relationship with the Feedback resource.

I wan´t to create an aggregate that will tell me how many feedbacks a student has inside a class.

If I just wanted all the student feedbacks, an aggregate like this in my Student resource would work just fine:

count :total_feedbacks, :feedbacks

But I want to count all the feedbacks that are from that student and from an specific class, meaning that I would to, somehow, pass an :class_id argument to inside that count aggregate filter expression.

I’m not sure how to solve that using aggregates

Showing Posts 1 to 5

zachdaniel

zachdaniel

Creator of Ash

You can’t do that with standard aggregates, but you can do that with the new(-ish) inline aggregates syntax.

calculate :total_feedbacks, :integer, expr(
  count(feedbacks, query: [filter: expr(class_id == ^arg(:class_id))])
) do
  argument :class_id, :uuid, allow_nil?: false
end
sezaru

sezaru OP

As always, worked like a charm! :smile:

sezaru

sezaru OP

Hey @zachdaniel, I have another case where I’m not 100% sure how to solve it.

The calculations with inline aggregates worked great, but what if I want to aggregate something from one of the relationships?

For example.

Let’s say that the Class resource has a has_many relationship with another resource called Lessons.

I want to have a calculation in my Student resource that would give me number of lessons inside that class that a student is in.

What I tried to do was to first create an aggregate in the Class resource like this:

  aggregates do
    count :total_lessons, :lessons
  end

And then, inside the Student resource, I tried to create a calculation using that:

    calculate :total_lessons_in_class,
              :integer,
              expr(first(classes, query: [filter: expr(class_id == ^arg(:class_id))]).total_lessons) do
      argument :class_id, :string, allow_nil?: false
    end

But that doesn’t work.

I also tried adding a calculation that would return the current class and then I would be able to get the total_lessons field directly from it:

  calculate :current_class, :struct, expr(first(classes, query: [filter: expr(id == ^arg(:class_id))])) do
      constraints [instance_of: Core.Feedbacks.Class]

      argument :class_id, :string, allow_nil?: false
    end

But using the first aggregate doesn´t seem to be working, not sure if I’m doing something wrong with it.

zachdaniel

zachdaniel

Creator of Ash

So, what I’m about to show you wont’ work, but what you would want is this:

    calculate :total_lessons_in_class,
              :integer,
              expr(first(classes, query: [filter: expr(class_id == ^arg(:class_id))], field: :total_lessons)) do
      argument :class_id, :string, allow_nil?: false
    end

However, you can’t use an aggregate as the field of another aggregate. However, you can do this:

    calculate :total_lessons_in_class,
              :integer,
              expr(count(classes.lessons, query: [filter: expr(class_id == ^arg(:class_id))])) do
      argument :class_id, :string, allow_nil?: false
    end

Assuming that lesson has class_id on it.

sezaru

sezaru OP

Yep, this worked great, thanks again!

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews