refactor date_trunc queries using groupdate gem

This commit is contained in:
maatinito 2021-12-02 15:46:45 -10:00 committed by Pierre de La Morinerie
parent 573b3d39e2
commit 0a31c8bc79
4 changed files with 67 additions and 77 deletions

View file

@ -27,8 +27,8 @@ class StatsController < ApplicationController
"Terminé" => stat.dossiers_termines "Terminé" => stat.dossiers_termines
} }
@procedures_cumulative = cumulative_hash(procedures, :published_at) @procedures_cumulative = cumulative_month_serie(procedures, :published_at)
@procedures_in_the_last_4_months = last_four_months_hash(procedures, :published_at) @procedures_in_the_last_4_months = last_four_months_serie(procedures, :published_at)
@dossiers_cumulative = stat.dossiers_cumulative @dossiers_cumulative = stat.dossiers_cumulative
@dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months @dossiers_in_the_last_4_months = stat.dossiers_in_the_last_4_months
@ -136,27 +136,18 @@ class StatsController < ApplicationController
end end
end end
def last_four_months_hash(association, date_attribute) def last_four_months_serie(association, date_attribute)
min_date = 3.months.ago.beginning_of_month.to_date
association association
.where(date_attribute => min_date..max_date) .group_by_month(date_attribute, last: 4, current: super_admin_signed_in?)
.group("DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)")
.count .count
.to_a .transform_keys { |date| l(date, format: "%B %Y") }
.sort_by { |a| a[0] }
.map { |e| [I18n.l(e.first, format: "%B %Y"), e.last] }
end end
def cumulative_hash(association, date_attribute) def cumulative_month_serie(association, date_attribute)
sum = 0 sum = 0
association association
.where("#{date_attribute} < ?", max_date) .group_by_month(date_attribute, current: super_admin_signed_in?)
.group("DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)")
.count .count
.to_a .transform_values { |count| sum += count }
.sort_by { |a| a[0] }
.map { |x, y| { x => (sum += y) } }
.reduce({}, :merge)
end end
end end

View file

@ -30,11 +30,11 @@ class Stat < ApplicationRecord
dossiers_deposes_entre_60_et_30_jours: states['dossiers_deposes_entre_60_et_30_jours'], dossiers_deposes_entre_60_et_30_jours: states['dossiers_deposes_entre_60_et_30_jours'],
dossiers_not_brouillon: states['not_brouillon'], dossiers_not_brouillon: states['not_brouillon'],
dossiers_termines: states['termines'], dossiers_termines: states['termines'],
dossiers_cumulative: cumulative_hash([ dossiers_cumulative: cumulative_month_serie([
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]), ]),
dossiers_in_the_last_4_months: last_four_months_hash([ dossiers_in_the_last_4_months: last_four_months_serie([
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]), ]),
@ -75,39 +75,33 @@ class Stat < ApplicationRecord
) )
end end
def last_four_months_hash(associations_with_date_attribute) def last_four_months_serie(associations_with_date_attribute)
min_date = 3.months.ago.beginning_of_month
timeseries = associations_with_date_attribute.map do |association, date_attribute| timeseries = associations_with_date_attribute.map do |association, date_attribute|
association association.group_by_month(date_attribute, last: 4, current: false).count
.where(date_attribute => min_date..max_date)
.group("DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)")
.count
end end
sum_hashes(*timeseries) month_serie(sum_hashes(*timeseries))
.to_a
.sort_by { |a| a[0] }
.map { |e| [I18n.l(e.first, format: "%B %Y"), e.last] }
end end
def cumulative_hash(associations_with_date_attribute) def month_serie(date_serie)
date_serie.keys.sort.each_with_object({}) { |date, h| h[I18n.l(date, format: "%B %Y")] = date_serie[date] }
end
def cumulative_month_serie(associations_with_date_attribute)
timeseries = associations_with_date_attribute.map do |association, date_attribute| timeseries = associations_with_date_attribute.map do |association, date_attribute|
association association.group_by_month(date_attribute, current: false).count
.where("#{date_attribute} < ?", max_date)
.group("DATE_TRUNC('month', #{date_attribute}::TIMESTAMPTZ AT TIME ZONE '#{Time.zone.formatted_offset}'::INTERVAL)")
.count
end end
cumulative_serie(sum_hashes(*timeseries))
end
def cumulative_serie(sums)
sum = 0 sum = 0
sum_hashes(*timeseries) sums.keys.sort.index_with { |date| sum += sums[date] }
.to_a
.sort_by { |a| a[0] }
.map { |x, y| { x => (sum += y) } }
.reduce({}, :merge)
end end
def sum_hashes(*hashes) def sum_hashes(*hashes)
{}.merge(*hashes) { |_k, hash_one_value, hash_two_value| hash_one_value + hash_two_value } {}.merge(*hashes) { |_k, v1, v2| v1 + v2 }
end end
def max_date def max_date

View file

@ -14,13 +14,15 @@ describe StatsController, type: :controller do
let(:association) { Procedure.all } let(:association) { Procedure.all }
subject { @controller.send(:last_four_months_hash, association, :updated_at) } subject { @controller.send(:last_four_months_serie, association, :updated_at) }
it do it do
expect(subject).to match_array([ expect(subject).to eq({
[I18n.l(62.days.ago.beginning_of_month, format: "%B %Y"), 2], 4.months.ago => 0,
[I18n.l(31.days.ago.beginning_of_month, format: "%B %Y"), 1] 3.months.ago => 0,
]) 62.days.ago => 2,
31.days.ago => 1
}.transform_keys { |date| I18n.l(date, format: '%B %Y') })
end end
end end
@ -38,13 +40,15 @@ describe StatsController, type: :controller do
let (:association) { Procedure.all } let (:association) { Procedure.all }
subject { @controller.send(:last_four_months_hash, association, :updated_at) } subject { @controller.send(:last_four_months_serie, association, :updated_at) }
it do it do
expect(subject).to eq([ expect(subject).to eq({
[I18n.l(45.days.ago.beginning_of_month, format: "%B %Y"), 1], 3.months.ago => 0,
[I18n.l(1.day.ago.beginning_of_month, format: "%B %Y"), 2] 45.days.ago => 1,
]) 1.month.ago => 0,
1.day.ago => 2
}.transform_keys { |date| I18n.l(date, format: '%B %Y') })
end end
end end
end end
@ -66,13 +70,13 @@ describe StatsController, type: :controller do
context "while a super admin is logged in" do context "while a super admin is logged in" do
before { allow(@controller).to receive(:super_admin_signed_in?).and_return(true) } before { allow(@controller).to receive(:super_admin_signed_in?).and_return(true) }
subject { @controller.send(:cumulative_hash, association, :updated_at) } subject { @controller.send(:cumulative_month_serie, association, :updated_at) }
it do it do
expect(subject).to eq({ expect(subject).to eq({
Time.utc(2016, 8, 1) => 2, Date.new(2016, 8, 1) => 2,
Time.utc(2016, 9, 1) => 4, Date.new(2016, 9, 1) => 4,
Time.utc(2016, 10, 1) => 5 Date.new(2016, 10, 1) => 5
}) })
end end
end end
@ -80,12 +84,12 @@ describe StatsController, type: :controller do
context "while a super admin is not logged in" do context "while a super admin is not logged in" do
before { allow(@controller).to receive(:super_admin_signed_in?).and_return(false) } before { allow(@controller).to receive(:super_admin_signed_in?).and_return(false) }
subject { @controller.send(:cumulative_hash, association, :updated_at) } subject { @controller.send(:cumulative_month_serie, association, :updated_at) }
it do it do
expect(subject).to eq({ expect(subject).to eq({
Time.utc(2016, 8, 1) => 2, Date.new(2016, 8, 1) => 2,
Time.utc(2016, 9, 1) => 4 Date.new(2016, 9, 1) => 4
}) })
end end
end end

View file

@ -57,24 +57,24 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end end
rs = Stat.send(:cumulative_hash, [ rs = Stat.send(:cumulative_month_serie, [
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]) ])
expect(rs).to eq({ expect(rs).to eq({
12.months.ago.utc.beginning_of_month => 2, 12 => 2,
11.months.ago.utc.beginning_of_month => 4, 11 => 4,
10.months.ago.utc.beginning_of_month => 6, 10 => 6,
9.months.ago.utc.beginning_of_month => 8, 9 => 8,
8.months.ago.utc.beginning_of_month => 10, 8 => 10,
7.months.ago.utc.beginning_of_month => 12, 7 => 12,
6.months.ago.utc.beginning_of_month => 14, 6 => 14,
5.months.ago.utc.beginning_of_month => 16, 5 => 16,
4.months.ago.utc.beginning_of_month => 18, 4 => 18,
3.months.ago.utc.beginning_of_month => 20, 3 => 20,
2.months.ago.utc.beginning_of_month => 22, 2 => 22,
1.month.ago.utc.beginning_of_month => 24 1 => 24
}) }.transform_keys { |i| i.months.ago.beginning_of_month.to_date })
end end
end end
@ -85,15 +85,16 @@ describe Stat do
create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end end
rs = Stat.send(:last_four_months_hash, [ rs = Stat.send(:last_four_months_serie, [
[Dossier.state_not_brouillon, :depose_at], [Dossier.state_not_brouillon, :depose_at],
[DeletedDossier.where.not(state: :brouillon), :deleted_at] [DeletedDossier.where.not(state: :brouillon), :deleted_at]
]) ])
expect(rs).to eq([ expect(rs).to eq({
["août 2021", 2], "juillet 2021" => 2,
["septembre 2021", 2], "août 2021" => 2,
["octobre 2021", 2] "septembre 2021" => 2,
]) "octobre 2021" => 2
})
end end
end end
end end