Merge pull request 'Introduce endpoint to retrieve a summary of groups and invite attendance' (#122) from groups-index-stats into main
All checks were successful
Check usage of free licenses / build-static-assets (pull_request) Successful in 1m39s
Add copyright notice / copyright_notice (pull_request) Successful in 2m20s
Run unit tests / unit_tests (pull_request) Successful in 5m23s

Reviewed-on: #122
This commit is contained in:
bustikiller 2024-11-13 08:12:46 +00:00 committed by Manuel Bustillo
commit d75b117c60
13 changed files with 285 additions and 4 deletions

58
.annotaterb.yml Normal file
View File

@ -0,0 +1,58 @@
---
:position: before
:position_in_additional_file_patterns: before
:position_in_class: before
:position_in_factory: before
:position_in_fixture: before
:position_in_routes: before
:position_in_serializer: before
:position_in_test: before
:classified_sort: true
:exclude_controllers: true
:exclude_factories: true
:exclude_fixtures: false
:exclude_helpers: true
:exclude_scaffolds: true
:exclude_serializers: false
:exclude_sti_subclasses: false
:exclude_tests: true
:force: false
:format_markdown: false
:format_rdoc: false
:format_yard: false
:frozen: false
:ignore_model_sub_dir: false
:ignore_unknown_models: false
:include_version: false
:show_check_constraints: false
:show_complete_foreign_keys: false
:show_foreign_keys: true
:show_indexes: true
:simple_indexes: false
:sort: false
:timestamp: false
:trace: false
:with_comment: true
:with_column_comments: true
:with_table_comments: true
:active_admin: false
:command:
:debug: false
:hide_default_column_types: ''
:hide_limit_column_types: ''
:ignore_columns:
:ignore_routes:
:models: true
:routes: false
:skip_on_db_migrate: false
:target_action: :do_annotations
:wrapper:
:wrapper_close:
:wrapper_open:
:classes_default_to_s: []
:additional_file_patterns: []
:model_dir:
- app/models
:require: []
:root_dir:
- ''

View File

@ -22,6 +22,7 @@ gem 'react-rails'
gem 'rubytree'
group :development, :test do
gem 'annotaterb'
gem 'debug', platforms: %i[mri windows]
gem 'factory_bot_rails'
gem 'license_finder'

View File

@ -72,6 +72,7 @@ GEM
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
annotaterb (4.13.0)
ast (2.4.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
@ -341,6 +342,7 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
annotaterb
bootsnap
chroma
csv

View File

@ -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

View File

@ -1,4 +1,15 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: expenses
#
# id :uuid not null, primary key
# amount :decimal(, )
# name :string
# pricing_type :enum default("fixed"), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Expense < ApplicationRecord
end

View File

@ -1,5 +1,27 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: groups
#
# id :uuid not null, primary key
# color :string
# icon :string
# name :string not null
# order :integer default(1), not null
# created_at :datetime not null
# updated_at :datetime not null
# parent_id :uuid
#
# Indexes
#
# index_groups_on_name (name) UNIQUE
# index_groups_on_parent_id (parent_id)
#
# Foreign Keys
#
# fk_rails_... (parent_id => groups.id)
#
class Group < ApplicationRecord
validates :name, uniqueness: true
validates :name, :order, presence: true
@ -30,6 +52,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

View File

@ -1,5 +1,25 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: guests
#
# id :uuid not null, primary key
# name :string
# phone :string
# status :integer default("considered")
# created_at :datetime not null
# updated_at :datetime not null
# group_id :uuid not null
#
# Indexes
#
# index_guests_on_group_id (group_id)
#
# Foreign Keys
#
# fk_rails_... (group_id => groups.id)
#
class Guest < ApplicationRecord
belongs_to :group

View File

@ -1,5 +1,26 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: seats
#
# id :uuid not null, primary key
# table_number :integer
# created_at :datetime not null
# updated_at :datetime not null
# guest_id :uuid not null
# tables_arrangement_id :uuid not null
#
# Indexes
#
# index_seats_on_guest_id (guest_id)
# index_seats_on_tables_arrangement_id (tables_arrangement_id)
#
# Foreign Keys
#
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (tables_arrangement_id => tables_arrangements.id) ON DELETE => cascade
#
class Seat < ApplicationRecord
belongs_to :guest
belongs_to :table_arrangement

View File

@ -1,5 +1,15 @@
# Copyright (C) 2024 Manuel Bustillo
# == Schema Information
#
# Table name: tables_arrangements
#
# id :uuid not null, primary key
# discomfort :integer
# name :string not null
# created_at :datetime not null
# updated_at :datetime not null
#
class TablesArrangement < ApplicationRecord
has_many :seats
has_many :guests, through: :seats

View 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

2
db/schema.rb generated
View File

@ -1,5 +1,3 @@
# Copyright (C) 2024 Manuel Bustillo
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.

View File

@ -0,0 +1,8 @@
# This rake task was added by annotate_rb gem.
# Can set `ANNOTATERB_SKIP_ON_DB_TASKS` to be anything to skip this
if Rails.env.development? && ENV["ANNOTATERB_SKIP_ON_DB_TASKS"].nil?
require "annotate_rb"
AnnotateRb::Core.load_rake_tasks
end

View 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