diff --git a/app/queries/expenses/total_query.rb b/app/queries/expenses/total_query.rb new file mode 100644 index 0000000..b0b72c7 --- /dev/null +++ b/app/queries/expenses/total_query.rb @@ -0,0 +1,24 @@ +module Expenses + class TotalQuery + def call + ActiveRecord::Base.connection.execute(query).first + end + + private + + def query + <<~SQL + SELECT count(amount) as fixed, + 0 as fixed_count, + 0 as variable, + 0 as variable_count, + 0 as total, + 0 as total_count, + 0 as max_projected, + 0 as per_person + FROM EXPENSES + LIMIT 1; + SQL + end + end +end \ No newline at end of file diff --git a/spec/factories/expense.rb b/spec/factories/expense.rb new file mode 100644 index 0000000..f9bf6c3 --- /dev/null +++ b/spec/factories/expense.rb @@ -0,0 +1,16 @@ +FactoryBot.define do + factory :expense do + sequence(:name) { |i| "Expense #{i}" } + pricing_type { "fixed" } + amount { 100 } + end + + trait :fixed do + pricing_type { "fixed" } + end + + trait :per_person do + pricing_type { "per_person" } + end + end + \ No newline at end of file diff --git a/spec/queries/expenses/total_query_spec.rb b/spec/queries/expenses/total_query_spec.rb new file mode 100644 index 0000000..65da11e --- /dev/null +++ b/spec/queries/expenses/total_query_spec.rb @@ -0,0 +1,84 @@ +require 'rails_helper' + +module Expenses + RSpec.describe TotalQuery do + describe '#call' do + let(:response) { described_class.new.call } + + before do + create_list(:guest, 2, status: :confirmed) + create_list(:guest, 3, status: :considered) + create_list(:guest, 4, status: :invited) + create_list(:guest, 5, status: :tentative) + create_list(:guest, 6, status: :declined) + end + + context "when there is no expense" do + it "returns zero in all values", :aggregate_failures do + expect(response["fixed"]).to be_zero + expect(response["fixed_count"]).to be_zero + expect(response["variable"]).to be_zero + expect(response["variable_count"]).to be_zero + expect(response["total"]).to be_zero + expect(response["total_count"]).to be_zero + expect(response["max_projected"]).to be_zero + expect(response["per_person"]).to be_zero + end + end + + context "when there are only fixed expenses" do + before do + create(:expense, :fixed, amount: 100) + create(:expense, :fixed, amount: 200) + end + + it "returns the sum of fixed expenses" do + expect(response["fixed"]).to eq(300) + expect(response["fixed_count"]).to eq(2) + expect(response["variable"]).to be_zero + expect(response["variable_count"]).to be_zero + expect(response["total"]).to eq(300) + expect(response["total_count"]).to eq(2) + expect(response["max_projected"]).to eq(300) + expect(response["per_person"]).to eq(150) + end + end + + context "when there are only variable expenses" do + before do + create(:expense, :per_person, amount: 100) + create(:expense, :per_person, amount: 200) + end + + it "returns zero in the values and nonzero in the count", :aggregate_failures do + expect(response["fixed"]).to be_zero + expect(response["fixed_count"]).to be_zero + expect(response["variable"]).to eq(300) + expect(response["variable_count"]).to eq(2) + expect(response["total"]).to eq(2*300) + expect(response["total_count"]).to eq(2) + expect(response["max_projected"]).to eq(11*300) + end + end + + context "when there are both fixed and variable expenses" do + before do + create(:expense, :fixed, amount: 100) + create(:expense, :fixed, amount: 200) + create(:expense, :per_person, amount: 50) + end + + it "returns the sum of fixed and variable expenses", :aggregate_failures do + expect(response["fixed"]).to eq(300) + expect(response["fixed_count"]).to eq(2) + expect(response["variable"]).to eq(50) + expect(response["variable_count"]).to eq(1) + expect(response["total"]).to eq(100 + 200 + 50 * 2) + expect(response["total_count"]).to eq(3) + expect(response["max_projected"]).to eq(100 + 200 + 11*50) + expect(response["per_person"]).to eq(200) + end + end + end + end +end