Skip to content

Instantly share code, notes, and snippets.

@codesnik
Created July 20, 2015 21:00
Show Gist options
  • Save codesnik/193268afe065a5187ae8 to your computer and use it in GitHub Desktop.
Save codesnik/193268afe065a5187ae8 to your computer and use it in GitHub Desktop.
ActiveRecord::Relation#subgroup
# TODO make a gem, a module or whatever
class ActiveRecord::Relation
# allows nesting of results of several groupings
# with groups,
# Payment.group(:system).group(:total_currency, :service_name).sum(:total_cents)
# => {["payture_in_pay", "RUB", "payture"]=>976067825,
# ["payture_in_pay", "RUB", "payture_test_ru"]=>637500,
# ...
#
# but with subgroups:
#
# Payment.group(:system).subgroup(:total_currency, :service_name) {|g| g.sum(:total_cents) }
# => {"payture_in_pay"=>{
# ["RUB", "payture"]=>976067825,
# ["RUB", "payture_test_ru"]=>637500,
# ...
#
# TODO use extending of resulting relation and override calculate function
# it will work without a block.
def subgroup(*subgroups)
relation = self
old_key_size = relation.group_values.size
relation = relation.group(*subgroups) unless subgroups.blank?
result = yield relation
raise ArgumentError, "result.inspect isn't a Hash. Call aggregate function in block!" unless result.is_a? Hash
return result if result.empty?
return result if old_key_size == 0
key_sample = result.first.first
new_key_size = key_sample.is_a?(Array) ? key_sample.size : 1
result.group_by {|key, value|
old_key_size == 1 ? key[0] : key[0, old_key_size]
}.transform_values {|groups|
groups.map {|subkey, value|
[
(new_key_size - old_key_size == 1) ? subkey[-1] : subkey[old_key_size..-1],
value
]
}.to_h
}
end
end
class ActiveRecord::Base
delegate :subgroup, to: :all
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment