reports_kit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -5
  3. data/app/assets/javascripts/reports_kit/lib/chart.js +33 -8
  4. data/app/assets/javascripts/reports_kit/lib/report.js +27 -26
  5. data/app/assets/javascripts/reports_kit/lib/table.js +58 -0
  6. data/app/assets/javascripts/reports_kit/vendor/jquery.tablesorter.min.js +4 -0
  7. data/app/assets/stylesheets/reports_kit/reports.css.sass +20 -0
  8. data/config/initializers/mime_types.rb +1 -0
  9. data/docs/dimensions.md +34 -26
  10. data/docs/display_options.md +15 -12
  11. data/docs/filters.md +2 -2
  12. data/docs/measures.md +4 -3
  13. data/gemfiles/mysql.gemfile.lock +14 -1
  14. data/gemfiles/postgresql.gemfile.lock +14 -1
  15. data/lib/reports_kit.rb +15 -0
  16. data/lib/reports_kit/cache.rb +37 -0
  17. data/lib/reports_kit/configuration.rb +13 -1
  18. data/lib/reports_kit/helper.rb +54 -3
  19. data/lib/reports_kit/model_configuration.rb +6 -1
  20. data/lib/reports_kit/order.rb +33 -0
  21. data/lib/reports_kit/relative_time.rb +42 -0
  22. data/lib/reports_kit/report_builder.rb +34 -15
  23. data/lib/reports_kit/reports/abstract_measure.rb +9 -0
  24. data/lib/reports_kit/reports/adapters/mysql.rb +8 -1
  25. data/lib/reports_kit/reports/adapters/postgresql.rb +8 -1
  26. data/lib/reports_kit/reports/composite_measure.rb +43 -0
  27. data/lib/reports_kit/reports/data/chart_options.rb +5 -0
  28. data/lib/reports_kit/reports/data/composite_aggregation.rb +96 -0
  29. data/lib/reports_kit/reports/data/entity.rb +7 -0
  30. data/lib/reports_kit/reports/data/format_one_dimension.rb +120 -0
  31. data/lib/reports_kit/reports/data/format_two_dimensions.rb +141 -0
  32. data/lib/reports_kit/reports/data/generate.rb +72 -25
  33. data/lib/reports_kit/reports/data/generate_for_properties.rb +75 -0
  34. data/lib/reports_kit/reports/data/one_dimension.rb +15 -49
  35. data/lib/reports_kit/reports/data/populate_one_dimension.rb +36 -0
  36. data/lib/reports_kit/reports/data/populate_two_dimensions.rb +104 -0
  37. data/lib/reports_kit/reports/data/two_dimensions.rb +15 -110
  38. data/lib/reports_kit/reports/data/utils.rb +77 -12
  39. data/lib/reports_kit/reports/data/value.rb +7 -0
  40. data/lib/reports_kit/reports/dimension.rb +4 -110
  41. data/lib/reports_kit/reports/dimension_with_measure.rb +137 -0
  42. data/lib/reports_kit/reports/filter.rb +5 -64
  43. data/lib/reports_kit/reports/filter_types/base.rb +1 -1
  44. data/lib/reports_kit/reports/filter_types/boolean.rb +9 -7
  45. data/lib/reports_kit/reports/filter_types/datetime.rb +7 -5
  46. data/lib/reports_kit/reports/filter_types/number.rb +2 -0
  47. data/lib/reports_kit/reports/filter_with_measure.rb +84 -0
  48. data/lib/reports_kit/reports/generate_autocomplete_results.rb +1 -1
  49. data/lib/reports_kit/reports/inferrable_configuration.rb +32 -13
  50. data/lib/reports_kit/reports/measure.rb +48 -12
  51. data/lib/reports_kit/reports_controller.rb +42 -3
  52. data/lib/reports_kit/version.rb +1 -1
  53. data/reports_kit.gemspec +2 -0
  54. data/spec/fixtures/generate_inputs.yml +146 -21
  55. data/spec/fixtures/generate_outputs.yml +768 -17
  56. data/spec/reports_kit/relative_time_spec.rb +29 -0
  57. data/spec/reports_kit/report_builder_spec.rb +28 -0
  58. data/spec/reports_kit/reports/data/generate_spec.rb +614 -27
  59. data/spec/reports_kit/reports/dimension_with_measure_spec.rb +69 -0
  60. data/spec/reports_kit/reports/{filter_spec.rb → filter_with_measure_spec.rb} +4 -3
  61. data/spec/spec_helper.rb +7 -2
  62. data/spec/support/config.rb +11 -0
  63. data/spec/support/helpers.rb +3 -3
  64. data/spec/support/models/issue.rb +7 -0
  65. metadata +53 -4
  66. data/spec/reports_kit/reports/dimension_spec.rb +0 -54
@@ -8,55 +8,102 @@ module ReportsKit
8
8
 
9
9
  def initialize(properties, context_record: nil)
10
10
  self.properties = properties.deep_symbolize_keys
11
+ self.properties = Utils.normalize_properties(self.properties)
11
12
  self.context_record = context_record
12
13
  end
13
14
 
14
15
  def perform
15
- if second_dimension
16
- data = Data::TwoDimensions.new(measure, dimension, second_dimension).perform
16
+ data = ReportsKit::Cache.get(properties, context_record)
17
+ return data if data
18
+
19
+ if two_dimensions?
20
+ raw_data = Data::FormatTwoDimensions.new(measures.first, measures_results.first.last, order: order).perform
17
21
  else
18
- data = Data::OneDimension.new(measure, dimension).perform
22
+ raw_data = Data::FormatOneDimension.new(measures_results, order: order).perform
19
23
  end
24
+ raw_data = data_format_method.call(raw_data) if data_format_method
25
+ chart_data = format_chart_data(raw_data)
20
26
 
21
- ChartOptions.new(data, options: properties[:chart], inferred_options: inferred_options).perform
27
+ data = { chart_data: chart_data }
28
+ data = ChartOptions.new(data, options: properties[:chart], inferred_options: inferred_options).perform
29
+ if format == 'table'
30
+ data[:table_data] = format_table(data.delete(:chart_data))
31
+ data[:type] = format
32
+ end
33
+ ReportsKit::Cache.set(properties, context_record, data)
34
+ data
22
35
  end
23
36
 
24
37
  private
25
38
 
26
- def measure
27
- @measure ||= begin
28
- measure_hash = properties[:measure]
29
- raise ArgumentError.new('The number of measures must be exactly one') if measure_hash.blank?
30
- Measure.new(measure_hash, context_record: context_record)
39
+ def format_chart_data(raw_data)
40
+ chart_data = {}
41
+ chart_data[:labels] = raw_data[:entities].map(&:label)
42
+ chart_data[:datasets] = raw_data[:datasets].map do |raw_dataset|
43
+ {
44
+ label: raw_dataset[:entity].label,
45
+ data: raw_dataset[:values].map(&:formatted)
46
+ }
31
47
  end
48
+ chart_data
32
49
  end
33
50
 
34
- def dimension
35
- @dimension ||= begin
36
- Dimension.new(dimension_hashes[0], measure: measure)
37
- end
51
+ def measures_results
52
+ @measures_results ||= GenerateForProperties.new(properties, context_record: context_record).perform
53
+ end
54
+
55
+ def two_dimensions?
56
+ dimension_keys = measures_results.first.last.keys
57
+ dimension_keys.first.is_a?(Array)
38
58
  end
39
59
 
40
- def second_dimension
41
- @second_dimension ||= begin
42
- Dimension.new(dimension_hashes[1], measure: measure) if dimension_hashes[1]
60
+ def order
61
+ @order ||= begin
62
+ return Order.parse(properties[:order]) if properties[:order].present?
63
+ inferred_order
43
64
  end
44
65
  end
45
66
 
46
- def dimension_hashes
47
- @dimension_hashes ||= begin
48
- dimension_hashes = properties[:dimensions]
49
- raise ArgumentError.new('Blank dimensions') if dimension_hashes.blank?
50
- raise ArgumentError.new('The number of dimensions must be 1-2') unless dimension_hashes.length.in?([1, 2])
51
- dimension_hashes = dimension_hashes.values if dimension_hashes.is_a?(Hash) && dimension_hashes.key?(:'0')
52
- dimension_hashes
67
+ def inferred_order
68
+ return Order.new('dimension1', nil, 'asc') if primary_dimension.configured_by_time?
69
+ Order.new('count', nil, 'desc')
70
+ end
71
+
72
+ def measures
73
+ @measures ||= Measure.new_from_properties!(properties, context_record: context_record)
74
+ end
75
+
76
+ def data_format_method
77
+ ReportsKit.configuration.custom_method(properties[:data_format_method])
78
+ end
79
+
80
+ def format
81
+ properties[:format]
82
+ end
83
+
84
+ def format_table(data)
85
+ column_names = [primary_dimension.label]
86
+ column_values = []
87
+ data[:datasets].each do |dataset|
88
+ column_names << dataset[:label]
89
+ column_values << dataset[:data]
90
+ end
91
+ rows = column_values.transpose
92
+ rows = rows.map.with_index do |row, index|
93
+ label = data[:labels][index]
94
+ row.unshift(label)
53
95
  end
96
+ [column_names] + rows
97
+ end
98
+
99
+ def primary_dimension
100
+ measures.first.dimensions.first
54
101
  end
55
102
 
56
103
  def inferred_options
57
104
  {
58
- x_axis_label: dimension.label,
59
- y_axis_label: measure.label
105
+ x_axis_label: primary_dimension.label,
106
+ y_axis_label: measures.length == 1 ? measures.first.label : nil
60
107
  }
61
108
  end
62
109
  end
@@ -0,0 +1,75 @@
1
+ module ReportsKit
2
+ module Reports
3
+ module Data
4
+ class GenerateForProperties
5
+ ROUND_PRECISION = 3
6
+
7
+ attr_accessor :properties, :context_record
8
+
9
+ def initialize(properties, context_record: nil)
10
+ self.properties = properties.deep_symbolize_keys
11
+ self.context_record = context_record
12
+ end
13
+
14
+ def perform
15
+ if composite_operator
16
+ raise ArgumentError.new('Aggregations require at least one measure') if all_measures.length == 0
17
+ dimension_keys_values = Data::CompositeAggregation.new(properties, context_record: context_record).perform
18
+ measures_dimension_keys_values = { CompositeMeasure.new(properties) => dimension_keys_values }
19
+ elsif all_measures.length == 1 && composite_measures.length == 1
20
+ dimension_keys_values = Data::CompositeAggregation.new(composite_measures.first.properties, context_record: context_record).perform
21
+ measures_dimension_keys_values = { all_measures.first => dimension_keys_values }
22
+ elsif all_measures.length == 1 && all_measures.first.dimensions.length == 2
23
+ dimension_keys_values = Data::TwoDimensions.new(all_measures.first).perform
24
+ measures_dimension_keys_values = { all_measures.first => dimension_keys_values }
25
+ measures_dimension_keys_values = Data::PopulateTwoDimensions.new(measures_dimension_keys_values).perform
26
+ elsif all_measures.length > 0
27
+ measures_dimension_keys_values = measures_dimension_keys_values_for_one_dimension
28
+ else
29
+ raise ArgumentError.new('The configuration of measurse and dimensions is invalid')
30
+ end
31
+
32
+ measures_dimension_keys_values
33
+ end
34
+
35
+ private
36
+
37
+ def composite_operator
38
+ properties[:composite_operator]
39
+ end
40
+
41
+ def name
42
+ properties[:name]
43
+ end
44
+
45
+ def measures_dimension_keys_values_for_one_dimension
46
+ multi_dimension_measures_exist = all_measures.any? { |measure| measure.dimensions.length > 1 }
47
+ raise ArgumentError.new('When more than one measures are configured, only one dimension may be used per measure') if multi_dimension_measures_exist
48
+
49
+ measures_dimension_keys_values = all_measures.map do |measure|
50
+ if measure.is_a?(CompositeMeasure)
51
+ dimension_keys_values = Data::CompositeAggregation.new(measure.properties, context_record: context_record).perform
52
+ else
53
+ dimension_keys_values = Data::OneDimension.new(measure).perform
54
+ end
55
+ [measure, dimension_keys_values]
56
+ end
57
+ measures_dimension_keys_values = Hash[measures_dimension_keys_values]
58
+ Data::PopulateOneDimension.new(measures_dimension_keys_values).perform
59
+ end
60
+
61
+ def all_measures
62
+ @all_measures ||= Measure.new_from_properties!(properties, context_record: context_record)
63
+ end
64
+
65
+ def composite_measures
66
+ @composite_measures ||= all_measures.grep(CompositeMeasure)
67
+ end
68
+
69
+ def measures
70
+ @measures ||= all_measures.grep(Measure)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -4,66 +4,32 @@ module ReportsKit
4
4
  class OneDimension
5
5
  attr_accessor :measure, :dimension
6
6
 
7
- def initialize(measure, dimension)
7
+ def initialize(measure)
8
8
  self.measure = measure
9
- self.dimension = dimension
9
+ self.dimension = measure.dimensions[0]
10
10
  end
11
11
 
12
12
  def perform
13
- {
14
- chart_data: {
15
- labels: labels,
16
- datasets: datasets
17
- }
18
- }
13
+ dimension_keys_values
19
14
  end
20
15
 
21
16
  private
22
17
 
23
18
  def dimension_keys_values
24
- @dimension_keys_values ||= begin
25
- relation = measure.filtered_relation
26
- relation = relation.group(dimension.group_expression)
27
- relation = relation.joins(dimension.joins) if dimension.joins
28
- relation = relation.limit(dimension.dimension_instances_limit) if dimension.dimension_instances_limit
29
- if dimension.should_be_sorted_by_count?
30
- relation = relation.order('1 DESC')
31
- else
32
- relation = relation.order('2')
33
- end
34
- dimension_keys_values = relation.distinct.public_send(*measure.aggregate_function)
35
- dimension_keys_values = Utils.populate_sparse_hash(dimension_keys_values, dimension: dimension)
36
- dimension_keys_values.delete(nil)
37
- dimension_keys_values.delete('')
38
- dimension_keys_values
39
- end
19
+ relation = measure.filtered_relation
20
+ relation = relation.group(dimension.group_expression)
21
+ relation = relation.joins(dimension.joins) if dimension.joins
22
+ relation = relation.limit(dimension.dimension_instances_limit) if dimension.dimension_instances_limit
23
+ relation = relation.order(order)
24
+ dimension_keys_values = relation.distinct.public_send(*measure.aggregate_function)
25
+ dimension_keys_values = Utils.populate_sparse_hash(dimension_keys_values, dimension: dimension)
26
+ dimension_keys_values.delete(nil)
27
+ dimension_keys_values.delete('')
28
+ Hash[dimension_keys_values]
40
29
  end
41
30
 
42
- def datasets
43
- [
44
- {
45
- label: measure.label,
46
- data: values
47
- }
48
- ]
49
- end
50
-
51
- def values
52
- dimension_keys_values.values.map { |value| value.round(Generate::ROUND_PRECISION) }
53
- end
54
-
55
- def labels
56
- keys = dimension_keys_values.keys
57
- keys.map do |key|
58
- Utils.dimension_key_to_label(key, dimension, dimension_ids_dimension_instances)
59
- end
60
- end
61
-
62
- def dimension_ids_dimension_instances
63
- @dimension_ids_dimension_instances ||= begin
64
- dimension_ids = dimension_keys_values.keys
65
- Utils.dimension_to_dimension_ids_dimension_instances(dimension, dimension_ids)
66
- end
31
+ def order
32
+ dimension.configured_by_time? ? '2' : '1 DESC'
67
33
  end
68
34
  end
69
35
  end
@@ -0,0 +1,36 @@
1
+ module ReportsKit
2
+ module Reports
3
+ module Data
4
+ class PopulateOneDimension
5
+ attr_accessor :sparse_measures_dimension_keys_values
6
+
7
+ def initialize(sparse_measures_dimension_keys_values)
8
+ self.sparse_measures_dimension_keys_values = sparse_measures_dimension_keys_values
9
+ end
10
+
11
+ def perform
12
+ return sparse_measures_dimension_keys_values if sparse_measures_dimension_keys_values.length == 1
13
+ measures_dimension_keys_values
14
+ end
15
+
16
+ private
17
+
18
+ def measures_dimension_keys_values
19
+ measures_dimension_keys_values = sparse_measures_dimension_keys_values.map do |measure, dimension_keys_values|
20
+ dimension_keys.each do |key|
21
+ dimension_keys_values[key] ||= 0
22
+ end
23
+ [measure, dimension_keys_values]
24
+ end
25
+ Hash[measures_dimension_keys_values]
26
+ end
27
+
28
+ def dimension_keys
29
+ sparse_measures_dimension_keys_values.map do |measure, dimension_keys_values|
30
+ dimension_keys_values.keys
31
+ end.reduce(&:+).uniq
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,104 @@
1
+ module ReportsKit
2
+ module Reports
3
+ module Data
4
+ class PopulateTwoDimensions
5
+ attr_accessor :measures, :dimension, :second_dimension, :sparse_measures_dimension_keys_values
6
+
7
+ def initialize(sparse_measures_dimension_keys_values)
8
+ self.measures = sparse_measures_dimension_keys_values.keys
9
+ self.dimension = measures.first.dimensions[0]
10
+ self.second_dimension = measures.first.dimensions[1]
11
+ self.sparse_measures_dimension_keys_values = sparse_measures_dimension_keys_values
12
+ end
13
+
14
+ def perform
15
+ measures_populated_dimension_keys_values
16
+ end
17
+
18
+ private
19
+
20
+ def measures_populated_dimension_keys_values
21
+ measures_dimension_keys_values = {}
22
+ secondary_keys_sums = Hash.new(0)
23
+ measures_populated_primary_keys_secondary_keys_values.each do |measure, primary_keys_secondary_keys_values|
24
+ primary_keys_secondary_keys_values.each do |primary_key, secondary_keys_values|
25
+ secondary_keys_values.each do |secondary_key, value|
26
+ secondary_keys_sums[secondary_key] += value
27
+ end
28
+ end
29
+ end
30
+ sorted_secondary_keys = secondary_keys_sums.sort_by(&:last).reverse.map(&:first)
31
+ measures_populated_primary_keys_secondary_keys_values.each do |measure, primary_key_secondary_keys_values|
32
+ measures_dimension_keys_values[measure] = {}
33
+ primary_key_secondary_keys_values.each do |primary_key, secondary_keys_values|
34
+ secondary_keys_values = secondary_keys_values.sort_by { |key, _| sorted_secondary_keys.index(key) }
35
+ secondary_keys_values.each do |secondary_key, value|
36
+ dimension_key = [primary_key, secondary_key]
37
+ measures_dimension_keys_values[measure][dimension_key] = value
38
+ secondary_keys_sums[secondary_key] += value
39
+ end
40
+ end
41
+ end
42
+ measures_dimension_keys_values
43
+ end
44
+
45
+ def measures_populated_primary_keys_secondary_keys_values
46
+ @populated_dimension_keys_values ||= begin
47
+ measures_populated_primary_keys_secondary_keys_values = {}
48
+ measures.each do |measure|
49
+ measures_populated_primary_keys_secondary_keys_values[measure] = {}
50
+ primary_keys.each do |primary_key|
51
+ measures_populated_primary_keys_secondary_keys_values[measure][primary_key] = {}
52
+ secondary_keys.each do |secondary_key|
53
+ value = measures_primary_keys_secondary_keys_values[measure][primary_key].try(:[], secondary_key) || 0
54
+ measures_populated_primary_keys_secondary_keys_values[measure][primary_key][secondary_key] = value
55
+ end
56
+ end
57
+ end
58
+ measures_populated_primary_keys_secondary_keys_values
59
+ end
60
+ end
61
+
62
+ def measures_primary_keys_secondary_keys_values
63
+ @measures_primary_keys_secondary_keys_values ||= begin
64
+ measures_primary_keys_secondary_keys_values = {}
65
+ sparse_measures_dimension_keys_values.each do |measure, dimension_keys_values|
66
+ measures_primary_keys_secondary_keys_values[measure] = {}
67
+ dimension_keys_values.each do |(primary_key, secondary_key), value|
68
+ primary_key = primary_key.to_date if primary_key.is_a?(Time)
69
+ secondary_key = secondary_key.to_date if secondary_key.is_a?(Time)
70
+ measures_primary_keys_secondary_keys_values[measure][primary_key] ||= {}
71
+ measures_primary_keys_secondary_keys_values[measure][primary_key][secondary_key] = value
72
+ end
73
+ end
74
+ measures_primary_keys_secondary_keys_values
75
+ end
76
+ end
77
+
78
+ def dimension_keys
79
+ @dimension_keys ||= sparse_measures_dimension_keys_values.values.map(&:keys).reduce(&:+).uniq
80
+ end
81
+
82
+ def primary_keys
83
+ @primary_keys ||= begin
84
+ keys = Utils.populate_sparse_keys(dimension_keys.map(&:first).uniq, dimension: dimension)
85
+ unless dimension.configured_by_time?
86
+ limit = dimension.dimension_instances_limit
87
+ keys = keys.first(limit) if limit
88
+ end
89
+ keys
90
+ end
91
+ end
92
+
93
+ def secondary_keys
94
+ @secondary_keys ||= begin
95
+ keys = Utils.populate_sparse_keys(dimension_keys.map(&:last).uniq, dimension: second_dimension)
96
+ limit = second_dimension.dimension_instances_limit
97
+ keys = keys.first(limit) if limit
98
+ keys
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -4,128 +4,33 @@ module ReportsKit
4
4
  class TwoDimensions
5
5
  attr_accessor :measure, :dimension, :second_dimension
6
6
 
7
- def initialize(measure, dimension, second_dimension)
7
+ def initialize(measure)
8
8
  self.measure = measure
9
- self.dimension = dimension
10
- self.second_dimension = second_dimension
9
+ self.dimension = measure.dimensions[0]
10
+ self.second_dimension = measure.dimensions[1]
11
11
  end
12
12
 
13
13
  def perform
14
- {
15
- chart_data: {
16
- labels: labels,
17
- datasets: datasets
18
- }
19
- }
14
+ dimension_keys_values
20
15
  end
21
16
 
22
17
  private
23
18
 
24
19
  def dimension_keys_values
25
- @dimension_keys_values ||= begin
26
- relation = measure.filtered_relation
27
- relation = measure.conditions.call(relation) if measure.conditions
28
- relation = relation.group(dimension.group_expression, second_dimension.group_expression)
29
-
30
- relation = relation.joins(dimension.joins) if dimension.joins
31
- relation = relation.joins(second_dimension.joins) if second_dimension.joins
32
-
33
- if dimension.should_be_sorted_by_count?
34
- relation = relation.order('1 DESC')
35
- else
36
- relation = relation.order('2')
37
- end
38
- dimension_keys_values = relation.distinct.public_send(*measure.aggregate_function)
39
-
40
- if dimension.should_be_sorted_by_count?
41
- dimension_keys_values = sort_dimension_keys_values_by_count(dimension_keys_values)
42
- end
43
- dimension_keys_values = Utils.populate_sparse_hash(dimension_keys_values, dimension: dimension)
44
- Hash[dimension_keys_values]
45
- end
46
- end
47
-
48
- def primary_keys_secondary_keys_values
49
- @primary_keys_secondary_keys_values ||= begin
50
- primary_keys_secondary_keys_values = {}
51
- dimension_keys_values.each do |(primary_key, secondary_key), value|
52
- primary_key = primary_key.to_date if primary_key.is_a?(Time)
53
- secondary_key = secondary_key.to_date if secondary_key.is_a?(Time)
54
- primary_keys_secondary_keys_values[primary_key] ||= {}
55
- primary_keys_secondary_keys_values[primary_key][secondary_key] = value
56
- end
57
- primary_keys_secondary_keys_values
58
- end
59
- end
60
-
61
- def sort_dimension_keys_values_by_count(dimension_keys_values)
62
- primary_keys_counts = Hash.new(0)
63
- dimension_keys_values.each do |(primary_key, secondary_key), count|
64
- primary_keys_counts[primary_key] += count
65
- end
66
- primary_keys_counts = primary_keys_counts.to_a
67
- sorted_primary_keys = primary_keys_counts.sort_by { |primary_key, count| count }.reverse.map(&:first)
68
- dimension_keys_values = dimension_keys_values.sort_by { |(primary_key, secondary_key), count| sorted_primary_keys.index(primary_key) }
20
+ relation = measure.filtered_relation
21
+ relation = relation.group(dimension.group_expression, second_dimension.group_expression)
22
+ relation = relation.joins(dimension.joins) if dimension.joins
23
+ relation = relation.joins(second_dimension.joins) if second_dimension.joins
24
+ relation = relation.order(order)
25
+ dimension_keys_values = relation.distinct.public_send(*measure.aggregate_function)
26
+ dimension_keys_values = Utils.populate_sparse_hash(dimension_keys_values, dimension: dimension)
27
+ dimension_keys_values.delete(nil)
28
+ dimension_keys_values.delete('')
69
29
  Hash[dimension_keys_values]
70
30
  end
71
31
 
72
- def dimension_ids
73
- dimension_keys_values.keys.map(&:first)
74
- end
75
-
76
- def dimension_ids_dimension_instances
77
- @dimension_ids_dimension_instances ||= begin
78
- Utils.dimension_to_dimension_ids_dimension_instances(dimension, dimension_keys_values.keys.map(&:first))
79
- end
80
- end
81
-
82
- def second_dimension_ids_dimension_instances
83
- @second_dimension_ids_dimension_instances ||= begin
84
- Utils.dimension_to_dimension_ids_dimension_instances(second_dimension, dimension_keys_values.keys.map(&:last))
85
- end
86
- end
87
-
88
- def datasets
89
- secondary_keys_values = secondary_keys.map do |secondary_key|
90
- values = primary_keys.map do |primary_key|
91
- primary_keys_secondary_keys_values[primary_key].try(:[], secondary_key) || 0
92
- end
93
- [secondary_key, values]
94
- end
95
- secondary_keys_values = secondary_keys_values.sort_by { |_, values| values.sum }.reverse
96
- secondary_keys_values.map do |secondary_key, values|
97
- next if secondary_key.blank?
98
- {
99
- label: Utils.dimension_key_to_label(secondary_key, second_dimension, second_dimension_ids_dimension_instances),
100
- data: values
101
- }
102
- end.compact
103
- end
104
-
105
- def primary_keys
106
- @primary_keys ||= begin
107
- keys = Utils.populate_sparse_keys(dimension_keys_values.keys.map(&:first).uniq, dimension: dimension)
108
- if dimension.should_be_sorted_by_count?
109
- limit = dimension.dimension_instances_limit
110
- keys = keys.first(limit) if limit
111
- end
112
- keys
113
- end
114
- end
115
-
116
- def secondary_keys
117
- @secondary_keys ||= begin
118
- keys = Utils.populate_sparse_keys(dimension_keys_values.keys.map(&:last).uniq, dimension: second_dimension)
119
- limit = second_dimension.dimension_instances_limit
120
- keys = keys.first(limit) if limit
121
- keys
122
- end
123
- end
124
-
125
- def labels
126
- primary_keys.map do |primary_key|
127
- Utils.dimension_key_to_label(primary_key, dimension, dimension_ids_dimension_instances)
128
- end
32
+ def order
33
+ dimension.configured_by_time? ? '2' : '1 DESC'
129
34
  end
130
35
  end
131
36
  end