reports_kit 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.travis.yml +20 -0
- data/README.md +17 -19
- data/app/assets/javascripts/reports_kit/lib/_init.js +2 -1
- data/app/assets/javascripts/reports_kit/lib/chart.js +25 -16
- data/app/assets/javascripts/reports_kit/lib/report.js +42 -25
- data/app/assets/javascripts/reports_kit/lib/table.js +37 -2
- data/app/assets/stylesheets/reports_kit/reports.css.sass +3 -0
- data/docs/dimensions.md +26 -34
- data/docs/display_options.md +12 -15
- data/docs/filters.md +54 -63
- data/docs/measures.md +3 -4
- data/lib/reports_kit.rb +12 -10
- data/lib/reports_kit/base_controller.rb +1 -2
- data/lib/reports_kit/configuration.rb +19 -4
- data/lib/reports_kit/entity.rb +3 -0
- data/lib/reports_kit/helper.rb +17 -21
- data/lib/reports_kit/model_configuration.rb +1 -1
- data/lib/reports_kit/report_builder.rb +11 -11
- data/lib/reports_kit/reports/{abstract_measure.rb → abstract_series.rb} +1 -1
- data/lib/reports_kit/reports/{composite_measure.rb → composite_series.rb} +12 -8
- data/lib/reports_kit/reports/data/add_table_aggregations.rb +105 -0
- data/lib/reports_kit/reports/data/{composite_aggregation.rb → aggregate_composite.rb} +28 -27
- data/lib/reports_kit/reports/data/{one_dimension.rb → aggregate_one_dimension.rb} +9 -7
- data/lib/reports_kit/reports/data/{two_dimensions.rb → aggregate_two_dimensions.rb} +9 -8
- data/lib/reports_kit/reports/data/chart_options.rb +6 -11
- data/lib/reports_kit/reports/data/format_one_dimension.rb +56 -36
- data/lib/reports_kit/reports/data/format_table.rb +65 -0
- data/lib/reports_kit/reports/data/format_two_dimensions.rb +10 -8
- data/lib/reports_kit/reports/data/generate.rb +51 -28
- data/lib/reports_kit/reports/data/generate_for_properties.rb +52 -30
- data/lib/reports_kit/reports/data/populate_one_dimension.rb +30 -12
- data/lib/reports_kit/reports/data/populate_two_dimensions.rb +31 -31
- data/lib/reports_kit/reports/data/utils.rb +28 -24
- data/lib/reports_kit/reports/dimension.rb +4 -0
- data/lib/reports_kit/reports/{dimension_with_measure.rb → dimension_with_series.rb} +8 -9
- data/lib/reports_kit/reports/filter.rb +4 -0
- data/lib/reports_kit/reports/filter_types/base.rb +4 -3
- data/lib/reports_kit/reports/filter_types/boolean.rb +4 -4
- data/lib/reports_kit/reports/filter_types/datetime.rb +13 -3
- data/lib/reports_kit/reports/filter_types/number.rb +5 -5
- data/lib/reports_kit/reports/{filter_with_measure.rb → filter_with_series.rb} +7 -7
- data/lib/reports_kit/reports/generate_autocomplete_results.rb +2 -2
- data/lib/reports_kit/reports/inferrable_configuration.rb +6 -6
- data/lib/reports_kit/reports/{measure.rb → series.rb} +28 -15
- data/lib/reports_kit/reports_controller.rb +25 -5
- data/lib/reports_kit/value.rb +3 -0
- data/lib/reports_kit/version.rb +1 -1
- data/spec/fixtures/generate_inputs.yml +116 -63
- data/spec/fixtures/generate_outputs.yml +64 -0
- data/spec/reports_kit/report_builder_spec.rb +10 -12
- data/spec/reports_kit/reports/data/generate_spec.rb +559 -140
- data/spec/reports_kit/reports/{dimension_with_measure_spec.rb → dimension_with_series_spec.rb} +5 -7
- data/spec/reports_kit/reports/{filter_with_measure_spec.rb → filter_with_series_spec.rb} +3 -3
- data/spec/spec_helper.rb +5 -5
- data/spec/support/config.rb +31 -1
- data/spec/support/helpers.rb +6 -2
- metadata +17 -14
- data/lib/reports_kit/reports/data/entity.rb +0 -7
- data/lib/reports_kit/reports/data/value.rb +0 -7
@@ -2,12 +2,13 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module Data
|
4
4
|
class FormatOneDimension
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :serieses_results, :serieses, :order, :limit
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
self.
|
9
|
-
self.
|
7
|
+
def initialize(serieses_results, order:, limit:)
|
8
|
+
self.serieses_results = serieses_results
|
9
|
+
self.serieses = serieses_results.keys
|
10
10
|
self.order = order
|
11
|
+
self.limit = limit
|
11
12
|
end
|
12
13
|
|
13
14
|
def perform
|
@@ -21,99 +22,118 @@ module ReportsKit
|
|
21
22
|
|
22
23
|
def entities
|
23
24
|
sorted_dimension_keys.map do |key|
|
24
|
-
Utils.dimension_key_to_entity(key,
|
25
|
+
Utils.dimension_key_to_entity(key, primary_dimension_with_series, dimension_ids_dimension_instances)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def datasets
|
29
|
-
|
30
|
+
sorted_serieses_results.map do |series, result|
|
30
31
|
values = result.values.map do |raw_value|
|
31
|
-
Utils.raw_value_to_value(raw_value,
|
32
|
+
Utils.raw_value_to_value(raw_value, series.value_format_method)
|
32
33
|
end
|
33
34
|
{
|
34
|
-
entity:
|
35
|
+
entity: series,
|
35
36
|
values: values
|
36
37
|
}
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
40
41
|
def dimension_summaries
|
41
|
-
@dimension_summaries ||=
|
42
|
-
label = Utils.dimension_key_to_label(dimension_key,
|
42
|
+
@dimension_summaries ||= raw_dimension_keys.map do |dimension_key|
|
43
|
+
label = Utils.dimension_key_to_label(dimension_key, primary_dimension_with_series, dimension_ids_dimension_instances)
|
44
|
+
next if label.blank?
|
43
45
|
[dimension_key, label]
|
44
|
-
end
|
46
|
+
end.compact
|
45
47
|
end
|
46
48
|
|
47
49
|
def sorted_dimension_keys
|
48
|
-
|
50
|
+
sorted_serieses_results.first.last.keys
|
49
51
|
end
|
50
52
|
|
51
53
|
def dimension_keys_sorted_by_label
|
52
|
-
|
54
|
+
dimension_summaries.sort_by { |key, label| label.is_a?(String) ? label.downcase : label }.map(&:first)
|
53
55
|
end
|
54
56
|
|
55
57
|
def dimension_keys
|
56
|
-
|
58
|
+
dimension_summaries.map(&:first)
|
59
|
+
end
|
60
|
+
|
61
|
+
def raw_dimension_keys
|
62
|
+
serieses_results.first.last.keys
|
57
63
|
end
|
58
64
|
|
59
65
|
def dimension_ids_dimension_instances
|
60
66
|
@dimension_ids_dimension_instances ||= begin
|
61
|
-
dimension_ids =
|
62
|
-
Utils.dimension_to_dimension_ids_dimension_instances(
|
67
|
+
dimension_ids = raw_dimension_keys
|
68
|
+
Utils.dimension_to_dimension_ids_dimension_instances(primary_dimension_with_series, dimension_ids)
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
67
|
-
@
|
72
|
+
def primary_dimension_with_series
|
73
|
+
@primary_dimension_with_series ||= DimensionWithSeries.new(dimension: primary_series.dimensions.first, series: primary_series)
|
68
74
|
end
|
69
75
|
|
70
|
-
def
|
71
|
-
|
76
|
+
def primary_series
|
77
|
+
serieses.first
|
72
78
|
end
|
73
79
|
|
74
|
-
def
|
75
|
-
@
|
80
|
+
def sorted_serieses_results
|
81
|
+
@sorted_serieses_results ||= begin
|
76
82
|
if order.relation == 'dimension1' && order.field == 'label'
|
77
|
-
|
83
|
+
sorted_serieses_results = serieses_results.map do |series, dimension_keys_values|
|
84
|
+
dimension_keys_values = filter_dimension_keys_values(dimension_keys_values)
|
78
85
|
sorted_dimension_keys_values = dimension_keys_values.sort_by { |key, _| dimension_keys_sorted_by_label.index(key) }
|
79
86
|
sorted_dimension_keys_values = sorted_dimension_keys_values.reverse if order.direction == 'desc'
|
80
|
-
[
|
87
|
+
[series, Hash[sorted_dimension_keys_values]]
|
81
88
|
end
|
82
89
|
elsif (order.relation == 'dimension1' && order.field.nil?) || (order.relation == 0)
|
83
|
-
|
90
|
+
sorted_serieses_results = serieses_results.map do |series, dimension_keys_values|
|
91
|
+
dimension_keys_values = filter_dimension_keys_values(dimension_keys_values)
|
84
92
|
sorted_dimension_keys_values = dimension_keys_values.sort_by(&:first)
|
85
93
|
sorted_dimension_keys_values = sorted_dimension_keys_values.reverse if order.direction == 'desc'
|
86
|
-
[
|
94
|
+
[series, Hash[sorted_dimension_keys_values]]
|
87
95
|
end
|
88
96
|
elsif order.relation.is_a?(Fixnum)
|
89
|
-
|
90
|
-
raise ArgumentError.new("Invalid order column: #{order.relation}") unless
|
91
|
-
dimension_keys_values =
|
97
|
+
series_index = order.relation - 1
|
98
|
+
raise ArgumentError.new("Invalid order column: #{order.relation}") unless series_index.in?((0..(serieses_results.length - 1)))
|
99
|
+
dimension_keys_values = serieses_results.values.to_a[series_index]
|
92
100
|
sorted_dimension_keys = dimension_keys_values.sort_by(&:last).map(&:first)
|
93
101
|
sorted_dimension_keys = sorted_dimension_keys.reverse if order.direction == 'desc'
|
94
|
-
|
102
|
+
sorted_serieses_results = serieses_results.map do |series, dimension_keys_values|
|
103
|
+
dimension_keys_values = filter_dimension_keys_values(dimension_keys_values)
|
95
104
|
dimension_keys_values = dimension_keys_values.sort_by { |dimension_key, _| sorted_dimension_keys.index(dimension_key) }
|
96
|
-
[
|
105
|
+
[series, Hash[dimension_keys_values]]
|
97
106
|
end
|
98
107
|
elsif order.relation == 'count'
|
99
108
|
dimension_keys_sums = Hash.new(0)
|
100
|
-
|
109
|
+
serieses_results.values.each do |dimension_keys_values|
|
110
|
+
dimension_keys_values = filter_dimension_keys_values(dimension_keys_values)
|
101
111
|
dimension_keys_values.each do |dimension_key, value|
|
102
112
|
dimension_keys_sums[dimension_key] += value
|
103
113
|
end
|
104
114
|
end
|
105
115
|
sorted_dimension_keys = dimension_keys_sums.sort_by(&:last).map(&:first)
|
106
116
|
sorted_dimension_keys = sorted_dimension_keys.reverse if order.direction == 'desc'
|
107
|
-
|
117
|
+
sorted_serieses_results = serieses_results.map do |series, dimension_keys_values|
|
118
|
+
dimension_keys_values = filter_dimension_keys_values(dimension_keys_values)
|
108
119
|
dimension_keys_values = dimension_keys_values.sort_by { |dimension_key, _| sorted_dimension_keys.index(dimension_key) }
|
109
|
-
[
|
120
|
+
[series, Hash[dimension_keys_values]]
|
110
121
|
end
|
111
122
|
else
|
112
|
-
|
123
|
+
sorted_serieses_results = serieses_results
|
113
124
|
end
|
114
|
-
|
125
|
+
if limit
|
126
|
+
sorted_serieses_results = sorted_serieses_results.map do |series, results|
|
127
|
+
[series, Hash[results.to_a.take(limit)]]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
Hash[sorted_serieses_results]
|
115
131
|
end
|
116
132
|
end
|
133
|
+
|
134
|
+
def filter_dimension_keys_values(dimension_keys_values)
|
135
|
+
dimension_keys_values.select { |key, values| dimension_keys.include?(key) }
|
136
|
+
end
|
117
137
|
end
|
118
138
|
end
|
119
139
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module ReportsKit
|
2
|
+
module Reports
|
3
|
+
module Data
|
4
|
+
class FormatTable
|
5
|
+
attr_accessor :data, :format, :first_column_label, :report_options
|
6
|
+
|
7
|
+
VALID_AGGREGATION_OPERATORS = [:sum]
|
8
|
+
|
9
|
+
def initialize(data, format:, first_column_label:, report_options:)
|
10
|
+
self.data = data
|
11
|
+
self.format = format
|
12
|
+
self.first_column_label = first_column_label
|
13
|
+
self.report_options = report_options || {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform
|
17
|
+
table_data
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def table_data
|
23
|
+
data_rows_with_labels = data_rows.map.with_index do |data_row, index|
|
24
|
+
label = format_string(data[:labels][index])
|
25
|
+
[label] + data_row
|
26
|
+
end
|
27
|
+
[column_names] + data_rows_with_labels
|
28
|
+
end
|
29
|
+
|
30
|
+
def column_names
|
31
|
+
column_names_column_values[0]
|
32
|
+
end
|
33
|
+
|
34
|
+
def column_values
|
35
|
+
column_names_column_values[1]
|
36
|
+
end
|
37
|
+
|
38
|
+
def data_rows
|
39
|
+
@data_rows ||= column_values.transpose
|
40
|
+
end
|
41
|
+
|
42
|
+
def column_names_column_values
|
43
|
+
@column_names_column_values ||= begin
|
44
|
+
column_names = [format_string(first_column_label)]
|
45
|
+
column_values = []
|
46
|
+
data[:datasets].each do |dataset|
|
47
|
+
column_names << format_string(dataset[:label])
|
48
|
+
column_values << dataset[:data]
|
49
|
+
end
|
50
|
+
[column_names, column_values]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def format_string(string)
|
55
|
+
return string unless string && strip_html_tags?
|
56
|
+
ActionView::Base.full_sanitizer.sanitize(string)
|
57
|
+
end
|
58
|
+
|
59
|
+
def strip_html_tags?
|
60
|
+
format == 'csv'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -2,14 +2,15 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module Data
|
4
4
|
class FormatTwoDimensions
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :series, :dimension, :second_dimension, :dimension_keys_values, :order, :limit
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
self.
|
9
|
-
self.dimension =
|
10
|
-
self.second_dimension =
|
7
|
+
def initialize(series, dimension_keys_values, order:, limit:)
|
8
|
+
self.series = series
|
9
|
+
self.dimension = series.dimensions[0]
|
10
|
+
self.second_dimension = series.dimensions[1]
|
11
11
|
self.dimension_keys_values = dimension_keys_values
|
12
12
|
self.order = order
|
13
|
+
self.limit = limit
|
13
14
|
end
|
14
15
|
|
15
16
|
def perform
|
@@ -33,7 +34,7 @@ module ReportsKit
|
|
33
34
|
primary_keys_secondary_keys_values[primary_key][secondary_key]
|
34
35
|
end
|
35
36
|
values = raw_values.map do |raw_value|
|
36
|
-
Utils.raw_value_to_value(raw_value,
|
37
|
+
Utils.raw_value_to_value(raw_value, series.value_format_method)
|
37
38
|
end
|
38
39
|
[secondary_key, values]
|
39
40
|
end
|
@@ -120,12 +121,13 @@ module ReportsKit
|
|
120
121
|
def primary_summaries
|
121
122
|
primary_keys.map do |key|
|
122
123
|
label = Utils.dimension_key_to_label(key, dimension, dimension_ids_dimension_instances)
|
124
|
+
next if label.blank?
|
123
125
|
[key, label]
|
124
|
-
end
|
126
|
+
end.compact
|
125
127
|
end
|
126
128
|
|
127
129
|
def primary_dimension_keys_sorted_by_label
|
128
|
-
@primary_dimension_keys_sorted_by_label ||= primary_summaries.sort_by(
|
130
|
+
@primary_dimension_keys_sorted_by_label ||= primary_summaries.sort_by { |key, label| label.is_a?(String) ? label.downcase : label }.map(&:first)
|
129
131
|
end
|
130
132
|
|
131
133
|
def primary_keys
|
@@ -8,28 +8,30 @@ module ReportsKit
|
|
8
8
|
|
9
9
|
def initialize(properties, context_record: nil)
|
10
10
|
self.properties = properties.deep_symbolize_keys
|
11
|
+
self.properties = ReportsKit.configuration.default_properties.deep_merge(self.properties) if ReportsKit.configuration.default_properties
|
11
12
|
self.properties = Utils.normalize_properties(self.properties)
|
12
13
|
self.context_record = context_record
|
13
14
|
end
|
14
15
|
|
15
16
|
def perform
|
16
17
|
data = ReportsKit::Cache.get(properties, context_record)
|
17
|
-
return data if data
|
18
|
+
return data.deep_symbolize_keys if data
|
18
19
|
|
19
20
|
if two_dimensions?
|
20
|
-
raw_data = Data::FormatTwoDimensions.new(
|
21
|
+
raw_data = Data::FormatTwoDimensions.new(serieses.first, serieses_results.first.last, order: order, limit: limit).perform
|
21
22
|
else
|
22
|
-
raw_data = Data::FormatOneDimension.new(
|
23
|
+
raw_data = Data::FormatOneDimension.new(serieses_results, order: order, limit: limit).perform
|
23
24
|
end
|
24
|
-
raw_data =
|
25
|
+
raw_data = format_csv_times(raw_data) if format == 'csv'
|
26
|
+
raw_data = Data::AddTableAggregations.new(raw_data, report_options: report_options).perform if table_or_csv?
|
27
|
+
raw_data = data_format_method.call(data: raw_data, properties: properties, context_record: context_record) if data_format_method
|
28
|
+
raw_data = csv_data_format_method.call(data: raw_data, properties: properties, context_record: context_record) if csv_data_format_method && format == 'csv'
|
25
29
|
chart_data = format_chart_data(raw_data)
|
26
30
|
|
27
31
|
data = { chart_data: chart_data }
|
28
32
|
data = ChartOptions.new(data, options: properties[:chart], inferred_options: inferred_options).perform
|
29
|
-
|
30
|
-
|
31
|
-
data[:type] = format
|
32
|
-
end
|
33
|
+
data[:report_options] = report_options if report_options
|
34
|
+
data = format_table_data(data) if table_or_csv?
|
33
35
|
ReportsKit::Cache.set(properties, context_record, data)
|
34
36
|
data
|
35
37
|
end
|
@@ -48,12 +50,23 @@ module ReportsKit
|
|
48
50
|
chart_data
|
49
51
|
end
|
50
52
|
|
51
|
-
def
|
52
|
-
|
53
|
+
def format_table_data(data)
|
54
|
+
data[:table_data] = Data::FormatTable.new(
|
55
|
+
data.delete(:chart_data),
|
56
|
+
format: format,
|
57
|
+
first_column_label: primary_dimension.label,
|
58
|
+
report_options: report_options
|
59
|
+
).perform
|
60
|
+
data[:type] = format
|
61
|
+
data
|
62
|
+
end
|
63
|
+
|
64
|
+
def serieses_results
|
65
|
+
@serieses_results ||= GenerateForProperties.new(properties, context_record: context_record).perform
|
53
66
|
end
|
54
67
|
|
55
68
|
def two_dimensions?
|
56
|
-
dimension_keys =
|
69
|
+
dimension_keys = serieses_results.first.last.keys
|
57
70
|
dimension_keys.first.is_a?(Array)
|
58
71
|
end
|
59
72
|
|
@@ -64,46 +77,56 @@ module ReportsKit
|
|
64
77
|
end
|
65
78
|
end
|
66
79
|
|
80
|
+
def limit
|
81
|
+
properties[:limit]
|
82
|
+
end
|
83
|
+
|
67
84
|
def inferred_order
|
68
85
|
return Order.new('dimension1', nil, 'asc') if primary_dimension.configured_by_time?
|
69
86
|
Order.new('count', nil, 'desc')
|
70
87
|
end
|
71
88
|
|
72
|
-
def
|
73
|
-
@
|
89
|
+
def serieses
|
90
|
+
@serieses ||= Series.new_from_properties!(properties, context_record: context_record)
|
91
|
+
end
|
92
|
+
|
93
|
+
def report_options
|
94
|
+
properties[:report_options]
|
74
95
|
end
|
75
96
|
|
76
97
|
def data_format_method
|
77
|
-
ReportsKit.configuration.custom_method(
|
98
|
+
ReportsKit.configuration.custom_method(report_options.try(:[], :data_format_method))
|
99
|
+
end
|
100
|
+
|
101
|
+
def csv_data_format_method
|
102
|
+
ReportsKit.configuration.custom_method(report_options.try(:[], :csv_data_format_method))
|
78
103
|
end
|
79
104
|
|
80
105
|
def format
|
81
106
|
properties[:format]
|
82
107
|
end
|
83
108
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
column_values << dataset[:data]
|
109
|
+
def format_csv_times(raw_data)
|
110
|
+
return raw_data unless primary_dimension.configured_by_time?
|
111
|
+
raw_data[:entities] = raw_data[:entities].map do |entity|
|
112
|
+
entity.label = Utils.format_csv_time(entity.instance)
|
113
|
+
entity
|
90
114
|
end
|
91
|
-
|
92
|
-
rows = rows.map.with_index do |row, index|
|
93
|
-
label = data[:labels][index]
|
94
|
-
row.unshift(label)
|
95
|
-
end
|
96
|
-
[column_names] + rows
|
115
|
+
raw_data
|
97
116
|
end
|
98
117
|
|
99
118
|
def primary_dimension
|
100
|
-
|
119
|
+
serieses.first.dimensions.first
|
120
|
+
end
|
121
|
+
|
122
|
+
def table_or_csv?
|
123
|
+
format.in?(%w(table csv))
|
101
124
|
end
|
102
125
|
|
103
126
|
def inferred_options
|
104
127
|
{
|
105
128
|
x_axis_label: primary_dimension.label,
|
106
|
-
y_axis_label:
|
129
|
+
y_axis_label: serieses.length == 1 ? serieses.first.label : nil
|
107
130
|
}
|
108
131
|
end
|
109
132
|
end
|
@@ -13,23 +13,23 @@ module ReportsKit
|
|
13
13
|
|
14
14
|
def perform
|
15
15
|
if composite_operator
|
16
|
-
raise ArgumentError.new('Aggregations require at least one
|
17
|
-
dimension_keys_values = Data::
|
18
|
-
|
19
|
-
elsif
|
20
|
-
dimension_keys_values = Data::
|
21
|
-
|
22
|
-
elsif
|
23
|
-
dimension_keys_values = Data::
|
24
|
-
|
25
|
-
|
26
|
-
elsif
|
27
|
-
|
16
|
+
raise ArgumentError.new('Aggregations require at least one series') if all_serieses.length == 0
|
17
|
+
dimension_keys_values = Data::AggregateComposite.new(properties, context_record: context_record).perform
|
18
|
+
serieses_dimension_keys_values = { CompositeSeries.new(properties) => dimension_keys_values }
|
19
|
+
elsif all_serieses.length == 1 && composite_serieses.length == 1
|
20
|
+
dimension_keys_values = Data::AggregateComposite.new(composite_serieses.first.properties, context_record: context_record).perform
|
21
|
+
serieses_dimension_keys_values = { all_serieses.first => dimension_keys_values }
|
22
|
+
elsif all_serieses.length == 1 && all_serieses.first.dimensions.length == 2
|
23
|
+
dimension_keys_values = Data::AggregateTwoDimensions.new(all_serieses.first).perform
|
24
|
+
serieses_dimension_keys_values = { all_serieses.first => dimension_keys_values }
|
25
|
+
serieses_dimension_keys_values = Data::PopulateTwoDimensions.new(serieses_dimension_keys_values).perform
|
26
|
+
elsif all_serieses.length > 0
|
27
|
+
serieses_dimension_keys_values = serieses_dimension_keys_values_for_one_dimension
|
28
28
|
else
|
29
29
|
raise ArgumentError.new('The configuration of measurse and dimensions is invalid')
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
serieses_dimension_keys_values
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
@@ -42,32 +42,54 @@ module ReportsKit
|
|
42
42
|
properties[:name]
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
46
|
-
|
47
|
-
raise ArgumentError.new('When more than one
|
45
|
+
def serieses_dimension_keys_values_for_one_dimension
|
46
|
+
multi_dimension_serieses_exist = all_serieses.any? { |series| series.dimensions.length > 1 }
|
47
|
+
raise ArgumentError.new('When more than one series are configured, only one dimension may be used per series') if multi_dimension_serieses_exist
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
if all_serieses.length > 1 && ReportsKit.configuration.use_concurrent_queries
|
50
|
+
serieses_dimension_keys_values = multithreaded_serieses_dimension_keys_values
|
51
|
+
else
|
52
|
+
serieses_dimension_keys_values = all_serieses.map do |series|
|
53
|
+
[series, dimension_keys_values_for_series(series)]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
serieses_dimension_keys_values = Hash[serieses_dimension_keys_values]
|
57
|
+
Data::PopulateOneDimension.new(serieses_dimension_keys_values, context_record: context_record, properties: properties).perform
|
58
|
+
end
|
59
|
+
|
60
|
+
def multithreaded_serieses_dimension_keys_values
|
61
|
+
threads = all_serieses.map do |series|
|
62
|
+
Thread.new do
|
63
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
64
|
+
begin
|
65
|
+
[series, dimension_keys_values_for_series(series)]
|
66
|
+
ensure
|
67
|
+
ActiveRecord::Base.connection.close if ActiveRecord::Base.connection
|
68
|
+
end
|
69
|
+
end
|
54
70
|
end
|
55
|
-
[measure, dimension_keys_values]
|
56
71
|
end
|
57
|
-
|
58
|
-
|
72
|
+
threads.map(&:join).map(&:value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def dimension_keys_values_for_series(series)
|
76
|
+
if series.is_a?(CompositeSeries)
|
77
|
+
Data::AggregateComposite.new(series.properties, context_record: context_record).perform
|
78
|
+
else
|
79
|
+
Data::AggregateOneDimension.new(series).perform
|
80
|
+
end
|
59
81
|
end
|
60
82
|
|
61
|
-
def
|
62
|
-
@
|
83
|
+
def all_serieses
|
84
|
+
@all_serieses ||= Series.new_from_properties!(properties, context_record: context_record)
|
63
85
|
end
|
64
86
|
|
65
|
-
def
|
66
|
-
@
|
87
|
+
def composite_serieses
|
88
|
+
@composite_serieses ||= all_serieses.grep(CompositeSeries)
|
67
89
|
end
|
68
90
|
|
69
|
-
def
|
70
|
-
@
|
91
|
+
def serieses
|
92
|
+
@serieses ||= all_serieses.grep(Series)
|
71
93
|
end
|
72
94
|
end
|
73
95
|
end
|