6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
# File 'lib/calculate_in_group.rb', line 6
def calculate_in_group(operation_type, field, groups, options = {})
raise ArgumentError.new("Please specify options for groups. Check the documentation") if groups.empty?
raise ArgumentError.new("Operation #{operation_type} not supported. Try to use: :count, :average, :sum, :maximum, :minimum") if ![:count, :average, :sum, :maximum, :minimum].include?(operation_type.to_s.to_sym)
raise ArgumentError.new("Column #{field} not found in `#{table_name}`") if !column_names.include?(field.to_s)
raise ArgumentError.new("Groups `#{groups}` can be array or hash. Check the documentation") unless groups.is_a?(Array) || groups.is_a?(Hash)
table = self.arel_table
group_field = "__#{field}"
operation_attribute = "__#{operation_type}_all"
query = Arel::Nodes::Case.new
conditions = []
groupings = groups.is_a?(Array) ? groups.inject({}) {|res, e| res[e.to_s] = e; res} : groups
groupings.each do |(k, v)|
c = case v
when Range
a = table[field].gteq(v.begin) if v.begin
if v.end
b = if v.exclude_end? table[field].lt(v.end)
else
table[field].lteq(v.end) end
end
[a, b].compact.inject(&:and)
when Array
table[field].in(v)
else
table[field].eq(v)
end
query = query.when(Arel.sql("(" + c.to_sql + ")#{__calculate_in_group_db_addon}")).then(k)
conditions.push(where(field => v))
end
operation = if operation_type == :count
Arel.star.count.as(operation_attribute)
else
table[field].send(operation_type).as(operation_attribute)
end
res = select([operation, query.as(group_field)])
res = res.merge(conditions.inject(&:or)) if !options[:include_nil] && conditions.any?
res = res.group(group_field)
result = res.inject({}) do |res, e|
key = e.send(group_field)
if key.nil? && options[:include_nil].present? && !!options[:include_nil] != options[:include_nil] key = options[:include_nil]
end
res[key] = e.send(operation_attribute)
res
end
if options.has_key?(:default_for_missing)
(groupings.keys.map(&:to_s) - result.keys).each do |k|
result[k] = options[:default_for_missing]
end
end
result
end
|