-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathdata_aggregator.rb
146 lines (132 loc) · 5.12 KB
/
data_aggregator.rb
1
2
3
4
5
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
class DataAggregator < Aggregator
# Outgoing volume as a sum of all relations,
# even if the target countries are not currently selected
def sum_out(country_ids, year, type_with_unit)
cached('sum_out', country_ids, year, type_with_unit) do
DataValue.where(
data_type_id: type_with_unit.type.id,
unit_id: type_with_unit.unit.id,
year: year,
country_from_id: country_ids
)
.where('country_to_id NOT IN (?)', country_ids)
.sum(:value)
end
end
# Incoming volume as a sum of all relations,
# even if the source countries are not currently selected
def sum_in(country_ids, year, type_with_unit)
country_ids = country_ids.sort
cached('sum_in', country_ids, year, type_with_unit) do
DataValue.where(
data_type_id: type_with_unit.type.id,
unit_id: type_with_unit.unit.id,
year: year,
country_to_id: country_ids,
)
.where('country_from_id NOT IN (?)', country_ids)
.sum(:value)
end
end
# Calculates sum for given groups and data_type for all years
# Adds highest single value in whole timespan
# groups_as_ids := [ [group1_id1, group1_id2, ...], [group2_id1, group2_id2, ...], ...]
def sum_yearly_for_groups(groups_as_ids, type_with_unit)
cached('sum_yearly_for_groups', groups_as_ids, type_with_unit) do
YearSum.yearly_for_groups(groups_as_ids, type_with_unit)
end
end
# Calculates outgoing relations and their position with other existing groups in mind
def stacked_outgoing(id, other_ids, type_with_unit, year)
other_ids.sort!
cached('stacked_outgoing', id, other_ids, type_with_unit, year) do
values = DataValueStacked.outgoing_stacked(id, other_ids, type_with_unit, year)
values.reduce({}) do |memo, stacked|
memo[iso3_by_group_id(stacked[:group_to])] = {
value: stacked[:value],
stacked_amount_from: stacked[:running_sum] - stacked[:value]
}
memo
end
end
end
# Calculates incoming relations and their position with other existing groups in mind
def stacked_incoming(id, other_ids, type_with_unit, year)
other_ids.sort!
cached('stacked_incoming', id, other_ids, type_with_unit, year) do
values = DataValueStacked.incoming_stacked(id, other_ids, type_with_unit, year)
values.reduce([]) do |memo, stacked|
memo << {
from_group_id: stacked[:group_from],
to_group_iso3: iso3_by_group_id(stacked[:group_to]),
value: stacked[:value],
stacked_amount_to: stacked[:running_sum] - stacked[:value]
}
memo
end
end
end
# Calculates the five biggest outgoing relations
# This method has to pay attention to other country groups,
# so the positioning of the sparklines is correct
def outgoing_top5(id, other_ids, type_with_unit, year)
other_ids.sort!
cached('outgoing_top5', id, other_ids, type_with_unit, year) do
values = DataValueStacked.outgoing_stacked(id, other_ids, type_with_unit, year, 'TOP 5')
values.reduce({}) do |memo, stacked|
memo[iso3_by_group_id(stacked[:group_to])] = {
value: stacked[:value],
stacked_amount_from: stacked[:running_sum] - stacked[:value]
}
memo
end
end
end
# Calculates the five biggest incoming relations
# This method has to pay attention to other country groups,
# so the positioning of the sparklines is correct
def incoming_top5(id, other_ids, type_with_unit, year)
other_ids.sort!
cached('incoming_top5', id, other_ids, type_with_unit, year) do
values = DataValueStacked.incoming_stacked(id, other_ids, type_with_unit, year, 'TOP 5')
values.reduce({}) do |memo, stacked|
memo[iso3_by_group_id(stacked[:group_from])] = {
value: stacked[:value],
stacked_amount_to: stacked[:running_sum] - stacked[:value]
}
memo
end
end
end
# Returns all missing relation data points between the given country ids
# as an array of hashes:
# { country_from_id, country_from_iso3, country_to_id, country_to_iso3}
def missing_relations_for_countries(ids, type_with_unit, year)
cached('missing_relations', ids, type_with_unit, year) do
MissingData.missing_relations(ids, type_with_unit, year)
end
end
# Returns all country ids without a single relation given a direction, type and year
# as an array of { country_id, iso3, direction: 'data_from|data_to' }
def countries_without_relations(ids, type_with_unit, year)
cached('without_relations', ids, type_with_unit, year) do
MissingData.without_relations(ids, type_with_unit, year)
end
end
# Returns an array with all years in the database.
def all_years
DataValue.uniq.pluck(:year)
end
private
# Returns iso3 values for countries and country groups
def iso3_by_group_id(group_id)
if group_id.is_a?(Integer)
return Country.where(id: group_id).pluck(:iso3).first
end
cached('iso3_by_group_id', group_id) do
group_id.split('-').map do |id|
Country.where(id: id).pluck(:iso3).first
end.sort.join('-')
end
end
end