From 452b5b2040061e760b761e539373212491083cfd Mon Sep 17 00:00:00 2001 From: Manuel Bustillo Date: Wed, 13 Nov 2024 08:57:20 +0100 Subject: [PATCH 1/2] Introduce endpoint to retrieve a summary of groups and invite attendance --- app/controllers/groups_controller.rb | 3 +- app/models/group.rb | 2 + app/queries/groups/summary_query.rb | 29 +++++++ spec/queries/groups/summary_query_spec.rb | 96 +++++++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 app/queries/groups/summary_query.rb create mode 100644 spec/queries/groups/summary_query_spec.rb diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 232ac85..37df884 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -2,7 +2,6 @@ class GroupsController < ApplicationController def index - roots = Group.where(parent_id: nil) - render jsonapi: roots, include: [children: [children: [:children]]] + render json: Groups::SummaryQuery.new.call.as_json end end diff --git a/app/models/group.rb b/app/models/group.rb index 105d08c..b06c1ba 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -30,6 +30,8 @@ class Group < ApplicationRecord private def set_color + return if color.present? + new_color = "##{SecureRandom.hex(3)}".paint new_color = new_color.lighten(30) if new_color.dark? self.color = new_color diff --git a/app/queries/groups/summary_query.rb b/app/queries/groups/summary_query.rb new file mode 100644 index 0000000..830ab59 --- /dev/null +++ b/app/queries/groups/summary_query.rb @@ -0,0 +1,29 @@ +module Groups + class SummaryQuery + def call + ActiveRecord::Base.connection.execute(query).to_a + end + + private + + def query + <<~SQL.squish + SELECT#{' '} + groups.id, + groups.name, + groups.icon, + groups.parent_id, + groups.color, + count(*) filter (where status IS NOT NULL) as total, + count(*) filter (where status = 0) as considered, + count(*) filter (where status = 10) as invited, + count(*) filter (where status = 20) as confirmed, + count(*) filter (where status = 30) as declined, + count(*) filter (where status = 40) as tentative + FROM groups + LEFT JOIN guests on groups.id = guests.group_id + GROUP BY groups.id + SQL + end + end +end diff --git a/spec/queries/groups/summary_query_spec.rb b/spec/queries/groups/summary_query_spec.rb new file mode 100644 index 0000000..71650c9 --- /dev/null +++ b/spec/queries/groups/summary_query_spec.rb @@ -0,0 +1,96 @@ +require 'rails_helper' + +module Groups + RSpec.describe SummaryQuery do + describe '#call' do + subject { described_class.new.call } + + context 'when there are no groups' do + it { is_expected.to eq([]) } + end + + context 'when groups are defined' do + let!(:parent) { create(:group, name: 'Friends', icon: 'icon-1', color: '#FF0000') } + let!(:child) { create(:group, name: 'Family', icon: 'icon-2', color: '#00FF00', parent:) } + + context 'when there are no guests' do + it 'returns the summary of groups' do + is_expected.to contain_exactly( + { 'id' => parent.id, + 'name' => 'Friends', + 'icon' => 'icon-1', + 'parent_id' => nil, + 'color' => '#FF0000', + 'total' => 0, + 'considered' => 0, + 'invited' => 0, + 'confirmed' => 0, + 'declined' => 0, + 'tentative' => 0 }, + { 'id' => child.id, + 'name' => 'Family', + 'icon' => 'icon-2', + 'parent_id' => parent.id, + 'color' => '#00FF00', + 'total' => 0, + 'considered' => 0, + 'invited' => 0, + 'confirmed' => 0, + 'declined' => 0, + 'tentative' => 0 } + ) + end + end + + context 'when there are guests' do + before do + # Parent group + create_list(:guest, 2, group: parent, status: :considered) + create_list(:guest, 3, group: parent, status: :invited) + create_list(:guest, 4, group: parent, status: :confirmed) + create_list(:guest, 5, group: parent, status: :declined) + create_list(:guest, 6, group: parent, status: :tentative) + + # Child group + create_list(:guest, 7, group: child, status: :considered) + create_list(:guest, 8, group: child, status: :invited) + create_list(:guest, 9, group: child, status: :confirmed) + create_list(:guest, 10, group: child, status: :declined) + create_list(:guest, 11, group: child, status: :tentative) + end + + it 'returns the summary of groups' do + is_expected.to contain_exactly( + { + 'id' => parent.id, + 'name' => 'Friends', + 'icon' => 'icon-1', + 'parent_id' => nil, + 'color' => '#FF0000', + 'total' => 20, + 'considered' => 2, + 'invited' => 3, + 'confirmed' => 4, + 'declined' => 5, + 'tentative' => 6 + }, + { + 'id' => child.id, + 'name' => 'Family', + 'icon' => 'icon-2', + 'parent_id' => parent.id, + 'color' => '#00FF00', + 'total' => 45, + 'considered' => 7, + 'invited' => 8, + 'confirmed' => 9, + 'declined' => 10, + 'tentative' => 11 + } + ) + end + end + end + end + end +end From 4be1fc6cad084a581009b48e5da90fdf9460d1eb Mon Sep 17 00:00:00 2001 From: Manuel Bustillo Date: Wed, 13 Nov 2024 07:59:07 +0000 Subject: [PATCH 2/2] Add copyright notice --- app/queries/groups/summary_query.rb | 2 ++ spec/queries/groups/summary_query_spec.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/queries/groups/summary_query.rb b/app/queries/groups/summary_query.rb index 830ab59..637a508 100644 --- a/app/queries/groups/summary_query.rb +++ b/app/queries/groups/summary_query.rb @@ -1,3 +1,5 @@ +# Copyright (C) 2024 Manuel Bustillo + module Groups class SummaryQuery def call diff --git a/spec/queries/groups/summary_query_spec.rb b/spec/queries/groups/summary_query_spec.rb index 71650c9..6e2c3d2 100644 --- a/spec/queries/groups/summary_query_spec.rb +++ b/spec/queries/groups/summary_query_spec.rb @@ -1,3 +1,5 @@ +# Copyright (C) 2024 Manuel Bustillo + require 'rails_helper' module Groups