Merge pull request 'Introduce endpoint to retrieve a summary of groups and invite attendance' (#122) from groups-index-stats into main
Reviewed-on: #122
This commit is contained in:
commit
f15545d13a
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
class GroupsController < ApplicationController
|
class GroupsController < ApplicationController
|
||||||
def index
|
def index
|
||||||
roots = Group.where(parent_id: nil)
|
render json: Groups::SummaryQuery.new.call.as_json
|
||||||
render jsonapi: roots, include: [children: [children: [:children]]]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -30,6 +30,8 @@ class Group < ApplicationRecord
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_color
|
def set_color
|
||||||
|
return if color.present?
|
||||||
|
|
||||||
new_color = "##{SecureRandom.hex(3)}".paint
|
new_color = "##{SecureRandom.hex(3)}".paint
|
||||||
new_color = new_color.lighten(30) if new_color.dark?
|
new_color = new_color.lighten(30) if new_color.dark?
|
||||||
self.color = new_color
|
self.color = new_color
|
||||||
|
31
app/queries/groups/summary_query.rb
Normal file
31
app/queries/groups/summary_query.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (C) 2024 Manuel Bustillo
|
||||||
|
|
||||||
|
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
|
98
spec/queries/groups/summary_query_spec.rb
Normal file
98
spec/queries/groups/summary_query_spec.rb
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# Copyright (C) 2024 Manuel Bustillo
|
||||||
|
|
||||||
|
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
|
Loading…
x
Reference in New Issue
Block a user