Skip to content

Instantly share code, notes, and snippets.

@mrzasa
Created Sep 15, 2016
Embed
What would you like to do?
# This file is an implementation of multi-level statistics.
# Value object. It can be created basing on SQL output.
SingleSubmissionStats =
Struct.new(:shift, :retreat_type,
:retreat_level, :retreat_type_and_level_id,
:gender, :reserve, :status, :count)
# Vlass responsible for calculating various staatistics.
# It contains a stats array that can consist of SingleSubmissionStats
class StatusSubmissionStats
attr_accessor :title, :stats
def initialize(title, stats)
@title = title
@stats = stats
end
def total
@total ||= stats.sum(&:count)
end
def draft
@draft ||= query(:draft) { |s| s.status.to_sym == :draft }
end
def downpayment_due
@downpayment_due ||=
query(:downpayment_due) { |s| s.status.to_sym == :downpayment_due }
end
def booked
@blocked ||= query(:booked) do |s|
s.status.to_sym == :open ||
s.status.to_sym == :closed ||
s.status.to_sym == :downpayment_due
end
end
def accepted
@accepted ||= query(:accepted) do
|s| s.status.to_sym == :open || s.status.to_sym == :closed
end
end
def male
@male ||= query(:male) { |s| s.gender.to_sym == :male }
end
def female
@female ||= query(:female) { |s| s.gender.to_sym == :female }
end
def regular
@regular ||= query(:reserve) { |s| !s.reserve }
end
def reserve
@reserve ||= query(:reserve) { |s| s.reserve }
end
private
# Filter stats using block and create a new object basing on the result.
# It allows chaining methods defined in this class.
def query(title, &block)
StatusSubmissionStats.new(title, stats.select(&block))
end
end
# Top-level class containing data used for
# identification (shift, type, level). Stats
# are counted for given (shift, type, level) tuple.
class TotalSubmissionStats < StatusSubmissionStats
attr_accessor :shift, :type, :level, :stats
def initialize(shift, type, level, stats)
super(:total, stats)
@shift = shift
@type = type
@level = level
end
def type_and_level
"#{level} #{type}"
end
end
# Usage example: data is aggregated by the DB and fetched as hashes.
# The hahses creates SingleSubmissionStats objects that are grouped by
# shifr, type and level to TotalSubmissionStats. Owing to the methods defined
# in StatusSubmissionStats user can calculate various complex statistics, e.g.
# number of male participant that are accepted.
#
def submission_statistics
statistics =
joins([{retreat_type_and_level: :retreat_type}, :shift, :list]).
joins('LEFT OUTER JOIN retreat_levels ON
retreat_type_and_levels.retreat_level_id = retreat_levels.id').
group('shifts.name',
'retreat_types.acronym',
'retreat_levels.number',
'retreat_type_and_levels.id',
'gender',
'reserve',
'participant_lists.status').
count
statistics.default = 0
statistics.
map{|k,v| SingleSubmissionStats.new(*[k, v].flatten) }.
group_by {|ss|[ss.shift, ss.retreat_type, ss.retreat_level]}.
map{|k, v| TotalSubmissionStats.new(*(k + [v]))}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment