Created
September 15, 2016 19:57
-
-
Save mrzasa/6aa745a0fa4f4e5437f5c8e049b14950 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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