Introduce endpoint to retrieve a summary of groups and invite attendance #122
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										29
									
								
								app/queries/groups/summary_query.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app/queries/groups/summary_query.rb
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										96
									
								
								spec/queries/groups/summary_query_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								spec/queries/groups/summary_query_spec.rb
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user