reports_kit 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f73a1370ec5380438c97d70101c44741b71e11d4
4
- data.tar.gz: 512485a9a8703592305f62bc0af6f21cc339d4f0
3
+ metadata.gz: dce804c6f31b50a81956706d29aa594ecc4f945c
4
+ data.tar.gz: 03fc82ecfa636b3e20ae44b21d679d30b1b25f0a
5
5
  SHA512:
6
- metadata.gz: 7f05e2853acc4f162d822351bdeb4e25243557334af27cde8b20edbccc825f95b1458e076a514490b054eb733807d32fa6d310f84e20412f9793d4d56fa47c46
7
- data.tar.gz: 58c18993f9d3e24025a4fafe901b2c0345b8fa0019aedc01258873d0a128cc22bf1c92fbd173a7703bf5000c3919d10720f1b4b766c6d0fe5e509b7e9ad31e9b
6
+ metadata.gz: 0a7c324823890a61f417e69b923c18c5ab946ae6ecc238f8ed1fc8e9dfbf28a46e517772b5f248a6e9c9d8e6522dbd5b5410aeffa091d3efe76bbdd3709f62c0
7
+ data.tar.gz: 3de91410a8d07370d2664bae9a4deb04cd57100074c66672db30ae591e4f21d824fec442819946dd8993ff5675a50508eb9cebaec40970c68a6624ddd7856bf1
@@ -15,6 +15,7 @@ before_install: gem update bundler
15
15
  before_script:
16
16
  - psql -c 'CREATE DATABASE reports_kit_test;' -U postgres
17
17
  - mysql -e 'CREATE DATABASE IF NOT EXISTS reports_kit_test;'
18
+ - mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
18
19
  - bundle exec appraisal install
19
20
 
20
21
  script: bundle exec appraisal rspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.5.0)
4
+ reports_kit (0.7.0)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -63,6 +63,8 @@ GEM
63
63
  activesupport (>= 3.0.0)
64
64
  globalid (0.4.0)
65
65
  activesupport (>= 4.2.0)
66
+ groupdate (3.2.0)
67
+ activesupport (>= 3)
66
68
  i18n (0.8.6)
67
69
  loofah (2.1.1)
68
70
  crass (~> 1.0.2)
@@ -149,6 +151,7 @@ DEPENDENCIES
149
151
  appraisal
150
152
  database_cleaner (~> 1)
151
153
  factory_girl (~> 4)
154
+ groupdate (~> 3)
152
155
  mysql2
153
156
  pg (>= 0.15)
154
157
  pry (~> 0)
@@ -159,4 +162,4 @@ DEPENDENCIES
159
162
  timecop (~> 0)
160
163
 
161
164
  BUNDLED WITH
162
- 1.15.4
165
+ 1.16.1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.5.0)
4
+ reports_kit (0.7.0)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -63,6 +63,8 @@ GEM
63
63
  activesupport (>= 3.0.0)
64
64
  globalid (0.4.0)
65
65
  activesupport (>= 4.2.0)
66
+ groupdate (3.2.0)
67
+ activesupport (>= 3)
66
68
  i18n (0.8.6)
67
69
  loofah (2.1.1)
68
70
  crass (~> 1.0.2)
@@ -148,6 +150,7 @@ DEPENDENCIES
148
150
  appraisal
149
151
  database_cleaner (~> 1)
150
152
  factory_girl (~> 4)
153
+ groupdate (~> 3)
151
154
  pg
152
155
  pry (~> 0)
153
156
  pry-byebug (~> 1)
@@ -157,4 +160,4 @@ DEPENDENCIES
157
160
  timecop (~> 0)
158
161
 
159
162
  BUNDLED WITH
160
- 1.15.4
163
+ 1.16.1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.4.1)
4
+ reports_kit (0.7.0)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -66,6 +66,8 @@ GEM
66
66
  activesupport (>= 3.0.0)
67
67
  globalid (0.4.0)
68
68
  activesupport (>= 4.2.0)
69
+ groupdate (3.2.0)
70
+ activesupport (>= 3)
69
71
  i18n (0.8.6)
70
72
  loofah (2.1.1)
71
73
  crass (~> 1.0.2)
@@ -154,6 +156,7 @@ DEPENDENCIES
154
156
  appraisal
155
157
  database_cleaner (~> 1)
156
158
  factory_girl (~> 4)
159
+ groupdate (~> 3)
157
160
  pg
158
161
  pry (~> 0)
159
162
  pry-byebug (~> 1)
@@ -163,4 +166,4 @@ DEPENDENCIES
163
166
  timecop (~> 0)
164
167
 
165
168
  BUNDLED WITH
166
- 1.15.4
169
+ 1.16.1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.5.0)
4
+ reports_kit (0.7.0)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -66,6 +66,8 @@ GEM
66
66
  activesupport (>= 3.0.0)
67
67
  globalid (0.4.0)
68
68
  activesupport (>= 4.2.0)
69
+ groupdate (3.2.0)
70
+ activesupport (>= 3)
69
71
  i18n (0.8.6)
70
72
  loofah (2.1.1)
71
73
  crass (~> 1.0.2)
@@ -155,6 +157,7 @@ DEPENDENCIES
155
157
  appraisal
156
158
  database_cleaner (~> 1)
157
159
  factory_girl (~> 4)
160
+ groupdate (~> 3)
158
161
  mysql2
159
162
  pg (>= 0.15)
160
163
  pry (~> 0)
@@ -165,4 +168,4 @@ DEPENDENCIES
165
168
  timecop (~> 0)
166
169
 
167
170
  BUNDLED WITH
168
- 1.15.4
171
+ 1.16.1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- reports_kit (0.5.0)
4
+ reports_kit (0.7.0)
5
5
  rails (>= 3)
6
6
  spreadsheet (>= 1.1)
7
7
 
@@ -66,6 +66,8 @@ GEM
66
66
  activesupport (>= 3.0.0)
67
67
  globalid (0.4.0)
68
68
  activesupport (>= 4.2.0)
69
+ groupdate (3.2.0)
70
+ activesupport (>= 3)
69
71
  i18n (0.8.6)
70
72
  loofah (2.1.1)
71
73
  crass (~> 1.0.2)
@@ -154,6 +156,7 @@ DEPENDENCIES
154
156
  appraisal
155
157
  database_cleaner (~> 1)
156
158
  factory_girl (~> 4)
159
+ groupdate (~> 3)
157
160
  pg
158
161
  pry (~> 0)
159
162
  pry-byebug (~> 1)
@@ -163,4 +166,4 @@ DEPENDENCIES
163
166
  timecop (~> 0)
164
167
 
165
168
  BUNDLED WITH
166
- 1.15.4
169
+ 1.16.1
@@ -15,6 +15,7 @@ require 'reports_kit/order'
15
15
  require 'reports_kit/relative_time'
16
16
  require 'reports_kit/report_builder'
17
17
  require 'reports_kit/reports_controller'
18
+ require 'reports_kit/utils'
18
19
  require 'reports_kit/value'
19
20
  require 'reports_kit/version'
20
21
 
@@ -25,6 +26,7 @@ require 'reports_kit/reports/data/add_table_aggregations'
25
26
  require 'reports_kit/reports/data/aggregate_composite'
26
27
  require 'reports_kit/reports/data/aggregate_one_dimension'
27
28
  require 'reports_kit/reports/data/aggregate_two_dimensions'
29
+ require 'reports_kit/reports/data/chart_data_for_data_method'
28
30
  require 'reports_kit/reports/data/chart_options'
29
31
  require 'reports_kit/reports/data/format_one_dimension'
30
32
  require 'reports_kit/reports/data/format_table'
@@ -51,6 +53,7 @@ require 'reports_kit/reports/dimension_with_series'
51
53
  require 'reports_kit/reports/filter'
52
54
  require 'reports_kit/reports/filter_with_series'
53
55
  require 'reports_kit/reports/generate_autocomplete_results'
56
+ require 'reports_kit/reports/generate_autocomplete_method_results'
54
57
  require 'reports_kit/reports/inferrable_configuration'
55
58
  require 'reports_kit/reports/model_settings'
56
59
  require 'reports_kit/reports/properties'
@@ -65,4 +68,12 @@ module ReportsKit
65
68
  def self.configuration
66
69
  @configuration ||= Configuration.new
67
70
  end
71
+
72
+ def self.parse_date_range(string)
73
+ ReportsKit::Reports::Data::Utils.parse_date_range(string)
74
+ end
75
+
76
+ def self.format_date_range(string)
77
+ ReportsKit::Reports::Data::Utils.format_date_range(string)
78
+ end
68
79
  end
@@ -13,7 +13,6 @@ module ReportsKit
13
13
  self.autocomplete_results_method = nil
14
14
  self.cache_duration = 5.minutes
15
15
  self.cache_store = nil
16
- self.context_record_method = nil
17
16
  self.custom_methods = {}
18
17
  self.default_dimension_limit = 30
19
18
  self.default_properties = nil
@@ -15,7 +15,7 @@ module ReportsKit
15
15
 
16
16
  def check_box(filter_key, options = {})
17
17
  filter = properties_to_filter.perform(filter_key)
18
- checked = filter.normalized_properties[:criteria][:value] == 'true'
18
+ checked = options.key?(:value) ? options[:value] : filter.normalized_properties[:criteria].try(:[], :value) == 'true'
19
19
  check_box_tag(filter_key, '1', checked, options)
20
20
  end
21
21
 
@@ -23,7 +23,7 @@ module ReportsKit
23
23
  filter = properties_to_filter.perform(filter_key)
24
24
  defaults = { class: 'form-control input-sm date_range_picker' }
25
25
  options = defaults.deep_merge(options)
26
- value = filter.normalized_properties[:criteria][:value].presence
26
+ value = options[:value].presence || filter.normalized_properties[:criteria].try(:[], :value).presence
27
27
  value ||= default_date_range_value
28
28
  text_field_tag(filter_key, value, options)
29
29
  end
@@ -50,7 +50,7 @@ module ReportsKit
50
50
  filter = properties_to_filter.perform(filter_key)
51
51
  defaults = { class: 'form-control input-sm' }
52
52
  options = defaults.deep_merge(options)
53
- text_field_tag(filter_key, filter.normalized_properties[:criteria][:value], options)
53
+ text_field_tag(filter_key, filter.normalized_properties[:criteria].try(:[], :value), options)
54
54
  end
55
55
 
56
56
  private
@@ -16,6 +16,10 @@ module ReportsKit
16
16
  raise ArgumentError.new("Unsupported first_day_of_week: #{ReportsKit.configuration.first_day_of_week}")
17
17
  end
18
18
  end
19
+
20
+ def self.truncate_to_month(column)
21
+ "DATE_SUB(DATE(#{column}), INTERVAL DAY(#{column}) - 1 DAY)"
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -16,6 +16,10 @@ module ReportsKit
16
16
  raise ArgumentError.new("Unsupported first_day_of_week: #{ReportsKit.configuration.first_day_of_week}")
17
17
  end
18
18
  end
19
+
20
+ def self.truncate_to_month(column)
21
+ "DATE_TRUNC('month', #{column}::date)"
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -0,0 +1,62 @@
1
+ module ReportsKit
2
+ class ChartDataForDataMethod
3
+ attr_accessor :properties
4
+
5
+ def initialize(properties)
6
+ self.properties = properties
7
+ end
8
+
9
+ def perform
10
+ klass, method_name = ReportsKit::Utils.string_to_class_method(properties[:data_method], 'data_method')
11
+ raw_data = klass.public_send(method_name, properties)
12
+ {
13
+ raw_data: raw_data,
14
+ formatted_data: format_returned_data(raw_data)
15
+ }
16
+ end
17
+
18
+ private
19
+
20
+ def format_returned_data(returned_data)
21
+ return [] if returned_data.blank?
22
+ returned_data = returned_data.to_a
23
+
24
+ first_key = returned_data.first.first
25
+ if first_key.is_a?(Array) && first_key.length == 2
26
+ format_two_dimensional_returned_data(returned_data)
27
+ else
28
+ {
29
+ labels: returned_data.map(&:first),
30
+ datasets: [
31
+ {
32
+ data: returned_data.map(&:last)
33
+ }
34
+ ]
35
+ }
36
+ end
37
+ end
38
+
39
+ def format_two_dimensional_returned_data(returned_data)
40
+ primary_keys_secondary_keys_values = {}
41
+ secondary_keys_primary_keys_values = {}
42
+ secondary_keys = []
43
+ returned_data.each do |(primary_key, secondary_key), value|
44
+ secondary_keys_primary_keys_values[secondary_key] ||= {}
45
+ secondary_keys_primary_keys_values[secondary_key][primary_key] = value
46
+ primary_keys_secondary_keys_values[primary_key] ||= {}
47
+ primary_keys_secondary_keys_values[primary_key][secondary_key] = value
48
+ end
49
+ primary_keys = primary_keys_secondary_keys_values.keys
50
+ datasets = secondary_keys_primary_keys_values.map do |secondary_key, primary_keys_values|
51
+ {
52
+ label: secondary_key,
53
+ data: primary_keys.map { |primary_key| primary_keys_values[primary_key] || 0 }
54
+ }
55
+ end
56
+ {
57
+ labels: primary_keys,
58
+ datasets: datasets
59
+ }
60
+ end
61
+ end
62
+ end
@@ -18,6 +18,23 @@ module ReportsKit
18
18
  data = ReportsKit::Cache.get(properties, context_record)
19
19
  return data.deep_symbolize_keys if data
20
20
 
21
+ data_method_data = ChartDataForDataMethod.new(properties).perform if has_data_method?
22
+ chart_data = data_method_data ? data_method_data[:formatted_data] : properties_to_chart_data
23
+ data = { chart_data: chart_data }
24
+ data = ChartOptions.new(data, options: properties[:chart], inferred_options: inferred_options).perform
25
+ data[:report_options] = report_options if report_options
26
+ data = format_table_data(data, data_method_data) if table_or_csv?
27
+ ReportsKit::Cache.set(properties, context_record, data)
28
+ data
29
+ end
30
+
31
+ private
32
+
33
+ def has_data_method?
34
+ properties[:data_method].present?
35
+ end
36
+
37
+ def properties_to_chart_data
21
38
  if two_dimensions?
22
39
  raw_data = Data::FormatTwoDimensions.new(serieses.first, serieses_results.first.last, order: order, limit: limit).perform
23
40
  else
@@ -27,18 +44,9 @@ module ReportsKit
27
44
  raw_data = Data::AddTableAggregations.new(raw_data, report_options: report_options).perform if table_or_csv?
28
45
  raw_data = data_format_method.call(data: raw_data, properties: properties, context_record: context_record) if data_format_method
29
46
  raw_data = csv_data_format_method.call(data: raw_data, properties: properties, context_record: context_record) if csv_data_format_method && format == 'csv'
30
- chart_data = format_chart_data(raw_data)
31
-
32
- data = { chart_data: chart_data }
33
- data = ChartOptions.new(data, options: properties[:chart], inferred_options: inferred_options).perform
34
- data[:report_options] = report_options if report_options
35
- data = format_table_data(data) if table_or_csv?
36
- ReportsKit::Cache.set(properties, context_record, data)
37
- data
47
+ format_chart_data(raw_data)
38
48
  end
39
49
 
40
- private
41
-
42
50
  def format_chart_data(raw_data)
43
51
  chart_data = {}
44
52
  chart_data[:labels] = raw_data[:entities].map(&:label)
@@ -51,14 +59,18 @@ module ReportsKit
51
59
  chart_data
52
60
  end
53
61
 
54
- def format_table_data(data)
62
+ def format_table_data(data, data_method_data)
63
+ data[:type] = format
64
+ if has_data_method?
65
+ data[:table_data] = data_method_data[:raw_data]
66
+ return data
67
+ end
55
68
  data[:table_data] = Data::FormatTable.new(
56
69
  data.delete(:chart_data),
57
70
  format: format,
58
- first_column_label: primary_dimension.label,
71
+ first_column_label: primary_dimension.try(:label),
59
72
  report_options: report_options
60
73
  ).perform
61
- data[:type] = format
62
74
  data
63
75
  end
64
76
 
@@ -132,6 +144,7 @@ module ReportsKit
132
144
  end
133
145
 
134
146
  def inferred_options
147
+ return {} if has_data_method?
135
148
  {
136
149
  x_axis_label: primary_dimension.label,
137
150
  y_axis_label: serieses.length == 1 ? serieses.first.label : nil
@@ -14,6 +14,11 @@ module ReportsKit
14
14
  time.strftime('%b %-d, \'%y')
15
15
  end
16
16
 
17
+ def self.format_date_range(string)
18
+ start_at, end_at = parse_date_range(string, type: Array)
19
+ [format_display_time(start_at), FilterTypes::Datetime::SEPARATOR, format_display_time(end_at)].join(' ')
20
+ end
21
+
17
22
  def self.format_time_value(value)
18
23
  time = RelativeTime.parse(value, prevent_exceptions: true)
19
24
  return value unless time
@@ -36,6 +41,18 @@ module ReportsKit
36
41
  RelativeTime.parse(string)
37
42
  end
38
43
 
44
+ def self.parse_date_range(string, type: nil)
45
+ return if string.blank?
46
+ start_string, end_string = string.split(FilterTypes::Datetime::SEPARATOR)
47
+ start_at = parse_date_string(start_string)
48
+ end_at = parse_date_string(end_string)
49
+ if type == Array
50
+ [start_at, end_at]
51
+ else
52
+ (start_at..end_at)
53
+ end
54
+ end
55
+
39
56
  def self.populate_sparse_hash(hash, dimension:)
40
57
  keys = hash.keys
41
58
  is_nested = dimension.series.has_two_dimensions?
@@ -69,15 +86,23 @@ module ReportsKit
69
86
  first_key = first_key.to_date
70
87
  granularity = dimension.granularity
71
88
 
72
- first_key = first_key.beginning_of_week(ReportsKit.configuration.first_day_of_week) if granularity == 'week'
73
89
  keys = keys.sort
74
90
  last_key = (dimension.last_key || keys.last).to_date
75
- last_key = last_key.beginning_of_week(ReportsKit.configuration.first_day_of_week) if granularity == 'week'
76
- last_key ||= Date.today.beginning_of_week(ReportsKit.configuration.first_day_of_week) if granularity == 'week'
91
+ if granularity == 'week'
92
+ first_key = first_key.beginning_of_week(ReportsKit.configuration.first_day_of_week)
93
+ last_key = last_key.beginning_of_week(ReportsKit.configuration.first_day_of_week)
94
+ elsif granularity == 'month'
95
+ first_key = first_key.beginning_of_month
96
+ last_key = last_key.beginning_of_month
97
+ end
77
98
 
78
99
  date = first_key
79
100
  populated_keys = []
80
- interval = granularity == 'week' ? 1.week : 1.day
101
+ interval = case granularity
102
+ when 'day' then 1.day
103
+ when 'month' then 1.month
104
+ else 1.week
105
+ end
81
106
  loop do
82
107
  populated_keys << date
83
108
  break if date >= last_key
@@ -111,9 +136,10 @@ module ReportsKit
111
136
 
112
137
  def self.dimension_to_dimension_ids_dimension_instances(dimension, dimension_ids)
113
138
  return nil unless dimension.instance_class
114
- dimension_instances = dimension.instance_class.where(id: dimension_ids.uniq)
139
+ primary_key = dimension.instance_class.primary_key
140
+ dimension_instances = dimension.instance_class.where(primary_key => dimension_ids.uniq)
115
141
  dimension_ids_dimension_instances = dimension_instances.map do |dimension_instance|
116
- [dimension_instance.id, dimension_instance]
142
+ [dimension_instance.send(primary_key), dimension_instance]
117
143
  end
118
144
  Hash[dimension_ids_dimension_instances]
119
145
  end
@@ -2,7 +2,7 @@ module ReportsKit
2
2
  module Reports
3
3
  class DimensionWithSeries
4
4
  DEFAULT_GRANULARITY = 'week'
5
- VALID_GRANULARITIES = %w(day week).freeze
5
+ VALID_GRANULARITIES = %w(day week month).freeze
6
6
  ADAPTER_NAMES_CLASSES = {
7
7
  'mysql2' => Adapters::Mysql,
8
8
  'postgresql' => Adapters::Postgresql
@@ -52,7 +52,11 @@ module ReportsKit
52
52
  elsif configured_by_association?
53
53
  inferred_settings_from_association[:column]
54
54
  elsif configured_by_column? && configured_by_time?
55
- granularity == 'day' ? day_expression : week_expression
55
+ case granularity
56
+ when 'day' then day_expression
57
+ when 'month' then month_expression
58
+ else week_expression
59
+ end
56
60
  elsif configured_by_column?
57
61
  column_expression
58
62
  else
@@ -131,6 +135,10 @@ module ReportsKit
131
135
  def week_expression
132
136
  adapter.truncate_to_week(column_expression)
133
137
  end
138
+
139
+ def month_expression
140
+ adapter.truncate_to_month(column_expression)
141
+ end
134
142
  end
135
143
  end
136
144
  end
@@ -17,13 +17,7 @@ module ReportsKit
17
17
  end
18
18
 
19
19
  def start_at_end_at
20
- @start_at_end_at ||= begin
21
- return unless valid?
22
- start_string, end_string = value.split(SEPARATOR)
23
- start_at = ReportsKit::Reports::Data::Utils.parse_date_string(start_string)
24
- end_at = ReportsKit::Reports::Data::Utils.parse_date_string(end_string)
25
- adjust_range_to_dimension(start_at, end_at)
26
- end
20
+ @start_at_end_at ||= valid? ? adjust_range_to_dimension(*Reports::Data::Utils.parse_date_range(value, type: Array)) : nil
27
21
  end
28
22
 
29
23
  def start_at
@@ -41,6 +35,10 @@ module ReportsKit
41
35
  start_at.beginning_of_week(ReportsKit.configuration.first_day_of_week),
42
36
  end_at.end_of_week(ReportsKit.configuration.first_day_of_week)
43
37
  ] if primary_dimension.granularity == 'week'
38
+ return [
39
+ start_at.beginning_of_month,
40
+ end_at.end_of_month
41
+ ] if primary_dimension.granularity == 'month'
44
42
  [start_at, end_at]
45
43
  end
46
44
 
@@ -0,0 +1,29 @@
1
+ module ReportsKit
2
+ module Reports
3
+ class GenerateAutocompleteMethodResults
4
+ attr_accessor :filter_key, :params, :properties
5
+
6
+ def initialize(filter_key, properties, params)
7
+ self.filter_key = filter_key
8
+ self.params = params
9
+ self.properties = properties
10
+ end
11
+
12
+ def perform
13
+ return unless properties[:ui_filters]
14
+ klass, method_name = ReportsKit::Utils.string_to_class_method(autocomplete_method, 'autocomplete_method')
15
+ klass.public_send(method_name, params, properties)
16
+ end
17
+
18
+ private
19
+
20
+ def filter_hash
21
+ properties[:ui_filters].find { |filter_params| filter_params.is_a?(Hash) && filter_params[:key] == filter_key }
22
+ end
23
+
24
+ def autocomplete_method
25
+ filter_hash[:autocomplete_method]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,10 +1,11 @@
1
1
  module ReportsKit
2
2
  module Reports
3
3
  class GenerateAutocompleteResults
4
- attr_accessor :params, :filter_key, :filter, :context_params, :context_record
4
+ attr_accessor :params, :properties, :filter_key, :filter, :context_params, :context_record
5
5
 
6
6
  def initialize(params, properties, context_record: nil)
7
7
  self.params = params
8
+ self.properties = properties
8
9
  self.context_params = params[:context_params]
9
10
  self.filter_key = params[:key]
10
11
  self.filter = Reports::PropertiesToFilter.new(properties, context_record: context_record).perform(filter_key)
@@ -12,6 +13,8 @@ module ReportsKit
12
13
  end
13
14
 
14
15
  def perform
16
+ autocomplete_method_results = Reports::GenerateAutocompleteMethodResults.new(filter_key, properties, params).perform
17
+ return autocomplete_method_results if autocomplete_method_results
15
18
  raise ArgumentError.new("Could not find a model for filter_key: '#{filter_key}'") unless model
16
19
  return autocomplete_results_method.call(params: params, context_record: context_record, relation: relation) if autocomplete_results_method
17
20
  results = filter.apply_contextual_filters(relation, context_params)
@@ -0,0 +1,11 @@
1
+ module ReportsKit
2
+ class Utils
3
+ def self.string_to_class_method(string, string_identifer)
4
+ class_name, method_name = string.split('.')
5
+ raise ArgumentError.new("The #{string_identifer} value should be a class method with a format of MyClass.my_method") unless class_name && method_name
6
+ klass = class_name.constantize
7
+ raise ArgumentError.new("The #{string_identifer} class (#{class_name}) does not respond to a method named \"#{method_name}\"") unless klass.respond_to?(method_name)
8
+ [klass, method_name]
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module ReportsKit
2
- VERSION = '0.5.0'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency 'rspec', '~> 3'
21
21
  s.add_development_dependency 'database_cleaner', '~> 1'
22
22
  s.add_development_dependency 'factory_girl', '~> 4'
23
+ s.add_development_dependency 'groupdate', '~> 3'
23
24
  s.add_development_dependency 'pg', '>= 0.15'
24
25
  s.add_development_dependency 'pry', '~> 0'
25
26
  s.add_development_dependency 'pry-byebug', '~> 1'
@@ -242,3 +242,13 @@
242
242
  - key: opened_at
243
243
  - key: repo
244
244
  order: count desc
245
+ - data_method: ExampleDataMethods.issues_by_opened_at
246
+ - data_method: ExampleDataMethods.issues_by_opened_at_and_repo
247
+ - data_method: ExampleDataMethods.issues_by_opened_at_with_filters
248
+ - data_method: ExampleDataMethods.issues_by_opened_at_with_filters
249
+ ui_filters:
250
+ state: open
251
+ - data_method: ExampleDataMethods.issues_by_opened_at_with_filters
252
+ ui_filters:
253
+ state: open
254
+ format: table
@@ -1064,3 +1064,153 @@
1064
1064
  :xPadding: 8
1065
1065
  :yPadding: 7
1066
1066
  :type: bar
1067
+ - :chart_data:
1068
+ :labels:
1069
+ - Dec 13, '09
1070
+ - Dec 20, '09
1071
+ - Dec 27, '09
1072
+ :datasets:
1073
+ - :data:
1074
+ - 1
1075
+ - 0
1076
+ - 1
1077
+ :backgroundColor: "#1f77b4"
1078
+ :borderColor: "#1f77b4"
1079
+ :options:
1080
+ :scales:
1081
+ :xAxes:
1082
+ - :gridLines:
1083
+ :display: false
1084
+ :barPercentage: 0.9
1085
+ :categoryPercentage: 0.9
1086
+ :yAxes:
1087
+ - :ticks:
1088
+ :beginAtZero: true
1089
+ :legend:
1090
+ :labels:
1091
+ :usePointStyle: true
1092
+ :maintainAspectRatio: false
1093
+ :tooltips:
1094
+ :xPadding: 8
1095
+ :yPadding: 7
1096
+ :type: bar
1097
+ - :chart_data:
1098
+ :labels:
1099
+ - Dec 13, '09
1100
+ - Dec 20, '09
1101
+ - Dec 27, '09
1102
+ :datasets:
1103
+ - :label: foo/bar1
1104
+ :data:
1105
+ - 1
1106
+ - 0
1107
+ - 1
1108
+ :backgroundColor: "#1f77b4"
1109
+ :borderColor: "#1f77b4"
1110
+ :options:
1111
+ :scales:
1112
+ :xAxes:
1113
+ - :gridLines:
1114
+ :display: false
1115
+ :barPercentage: 0.9
1116
+ :categoryPercentage: 0.9
1117
+ :yAxes:
1118
+ - :ticks:
1119
+ :beginAtZero: true
1120
+ :legend:
1121
+ :labels:
1122
+ :usePointStyle: true
1123
+ :maintainAspectRatio: false
1124
+ :tooltips:
1125
+ :xPadding: 8
1126
+ :yPadding: 7
1127
+ :type: bar
1128
+ - :chart_data:
1129
+ :labels:
1130
+ - Dec 13, '09
1131
+ - Dec 20, '09
1132
+ - Dec 27, '09
1133
+ :datasets:
1134
+ - :data:
1135
+ - 1
1136
+ - 0
1137
+ - 1
1138
+ :backgroundColor: "#1f77b4"
1139
+ :borderColor: "#1f77b4"
1140
+ :options:
1141
+ :scales:
1142
+ :xAxes:
1143
+ - :gridLines:
1144
+ :display: false
1145
+ :barPercentage: 0.9
1146
+ :categoryPercentage: 0.9
1147
+ :yAxes:
1148
+ - :ticks:
1149
+ :beginAtZero: true
1150
+ :legend:
1151
+ :labels:
1152
+ :usePointStyle: true
1153
+ :maintainAspectRatio: false
1154
+ :tooltips:
1155
+ :xPadding: 8
1156
+ :yPadding: 7
1157
+ :type: bar
1158
+ - :chart_data:
1159
+ :labels:
1160
+ - Dec 13, '09
1161
+ :datasets:
1162
+ - :data:
1163
+ - 1
1164
+ :backgroundColor: "#1f77b4"
1165
+ :borderColor: "#1f77b4"
1166
+ :options:
1167
+ :scales:
1168
+ :xAxes:
1169
+ - :gridLines:
1170
+ :display: false
1171
+ :barPercentage: 0.9
1172
+ :categoryPercentage: 0.9
1173
+ :yAxes:
1174
+ - :ticks:
1175
+ :beginAtZero: true
1176
+ :legend:
1177
+ :labels:
1178
+ :usePointStyle: true
1179
+ :maintainAspectRatio: false
1180
+ :tooltips:
1181
+ :xPadding: 8
1182
+ :yPadding: 7
1183
+ :type: bar
1184
+ - :chart_data:
1185
+ :labels:
1186
+ - Date
1187
+ - Dec 13, '09
1188
+ :datasets:
1189
+ - :data:
1190
+ - Issue count
1191
+ - 1
1192
+ :backgroundColor: "#1f77b4"
1193
+ :borderColor: "#1f77b4"
1194
+ :options:
1195
+ :scales:
1196
+ :xAxes:
1197
+ - :gridLines:
1198
+ :display: false
1199
+ :barPercentage: 0.9
1200
+ :categoryPercentage: 0.9
1201
+ :yAxes:
1202
+ - :ticks:
1203
+ :beginAtZero: true
1204
+ :legend:
1205
+ :labels:
1206
+ :usePointStyle: true
1207
+ :maintainAspectRatio: false
1208
+ :tooltips:
1209
+ :xPadding: 8
1210
+ :yPadding: 7
1211
+ :type: table
1212
+ :table_data:
1213
+ - - Date
1214
+ - Issue count
1215
+ - - Dec 13, '09
1216
+ - 1
@@ -274,6 +274,36 @@ describe ReportsKit::Reports::Data::Generate do
274
274
  })
275
275
  end
276
276
  end
277
+
278
+ context 'with month granularity' do
279
+ let(:properties) do
280
+ {
281
+ measure: 'issue',
282
+ dimensions: [{ key: 'opened_at', granularity: 'month' }]
283
+ }
284
+ end
285
+ let!(:issues) do
286
+ [
287
+ create(:issue, repo: repo, opened_at: now - 2.days),
288
+ create(:issue, repo: repo, opened_at: now)
289
+ ]
290
+ end
291
+
292
+ it 'returns the data' do
293
+ expect(chart_data).to eq({
294
+ labels: [
295
+ ReportsKit::Reports::Data::Utils.format_display_time(issues.first.opened_at.beginning_of_month),
296
+ ReportsKit::Reports::Data::Utils.format_display_time(issues.last.opened_at.beginning_of_month)
297
+ ],
298
+ datasets: [
299
+ {
300
+ label: 'Issues',
301
+ data: [1, 1]
302
+ }
303
+ ]
304
+ })
305
+ end
306
+ end
277
307
  end
278
308
 
279
309
  context 'with an association dimension' do
@@ -23,7 +23,7 @@ describe ReportsKit::Reports::GenerateAutocompleteResults do
23
23
  end
24
24
 
25
25
  it 'returns the results' do
26
- expect(subject).to eq([
26
+ expect(subject).to match_array([
27
27
  { id: repo.id, text: repo.to_s },
28
28
  { id: repo2.id, text: repo2.to_s }
29
29
  ])
@@ -42,7 +42,7 @@ describe ReportsKit::Reports::GenerateAutocompleteResults do
42
42
  end
43
43
 
44
44
  it 'returns the results' do
45
- expect(subject).to eq([
45
+ expect(subject).to match_array([
46
46
  { id: repo.id, text: repo.to_s }
47
47
  ])
48
48
  end
@@ -59,7 +59,7 @@ describe ReportsKit::Reports::GenerateAutocompleteResults do
59
59
  end
60
60
 
61
61
  it 'returns the results' do
62
- expect(subject).to eq([
62
+ expect(subject).to match_array([
63
63
  { id: repo.id, text: repo.to_s },
64
64
  { id: repo2.id, text: repo2.to_s }
65
65
  ])
@@ -1,6 +1,7 @@
1
1
  require 'reports_kit'
2
2
 
3
3
  require 'database_cleaner'
4
+ require 'groupdate'
4
5
  require 'pry'
5
6
  require 'pry-byebug'
6
7
  require 'timecop'
@@ -35,6 +36,7 @@ Dir.glob("#{directory}/support/models/**/*.rb") { |file| require file }
35
36
  Dir.glob("#{directory}/factories/*.rb") { |file| require file }
36
37
 
37
38
  require 'support/config'
39
+ require 'support/example_data_methods'
38
40
  require 'support/schema'
39
41
 
40
42
  RSpec.configure do |config|
@@ -0,0 +1,25 @@
1
+ class ExampleDataMethods
2
+ def self.issues_by_opened_at(properties)
3
+ Issue.group_by_week(:opened_at).count.map { |date, count| [format_date(date), count] }
4
+ end
5
+
6
+ def self.issues_by_opened_at_and_repo(properties)
7
+ Issue.group_by_week(:opened_at).joins(:repo).group('repos.full_name').count.map do |(date, name), count|
8
+ [[format_date(date), name], count]
9
+ end
10
+ end
11
+
12
+ def self.issues_by_opened_at_with_filters(properties)
13
+ format = properties[:format]
14
+ ui_filters = properties[:ui_filters]
15
+ issues = Issue.group_by_week(:opened_at)
16
+ issues = issues.where(state: ui_filters[:state]) if ui_filters.try(:[], :state).present?
17
+ dates_issue_counts = issues.count.map { |date, count| [format_date(date), count] }
18
+ return dates_issue_counts unless format == 'table'
19
+ [['Date', 'Issue count']] + dates_issue_counts
20
+ end
21
+
22
+ def self.format_date(date)
23
+ date.strftime('%b %-d, \'%y')
24
+ end
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reports_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Benner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-18 00:00:00.000000000 Z
11
+ date: 2018-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: groupdate
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: pg
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -226,6 +240,7 @@ files:
226
240
  - lib/reports_kit/reports/data/aggregate_composite.rb
227
241
  - lib/reports_kit/reports/data/aggregate_one_dimension.rb
228
242
  - lib/reports_kit/reports/data/aggregate_two_dimensions.rb
243
+ - lib/reports_kit/reports/data/chart_data_for_data_method.rb
229
244
  - lib/reports_kit/reports/data/chart_options.rb
230
245
  - lib/reports_kit/reports/data/format_one_dimension.rb
231
246
  - lib/reports_kit/reports/data/format_table.rb
@@ -246,6 +261,7 @@ files:
246
261
  - lib/reports_kit/reports/filter_types/records.rb
247
262
  - lib/reports_kit/reports/filter_types/string.rb
248
263
  - lib/reports_kit/reports/filter_with_series.rb
264
+ - lib/reports_kit/reports/generate_autocomplete_method_results.rb
249
265
  - lib/reports_kit/reports/generate_autocomplete_results.rb
250
266
  - lib/reports_kit/reports/inferrable_configuration.rb
251
267
  - lib/reports_kit/reports/model_settings.rb
@@ -253,6 +269,7 @@ files:
253
269
  - lib/reports_kit/reports/properties_to_filter.rb
254
270
  - lib/reports_kit/reports/series.rb
255
271
  - lib/reports_kit/reports_controller.rb
272
+ - lib/reports_kit/utils.rb
256
273
  - lib/reports_kit/value.rb
257
274
  - lib/reports_kit/version.rb
258
275
  - reports_kit.gemspec
@@ -274,6 +291,7 @@ files:
274
291
  - spec/reports_kit/reports/generate_autocomplete_results_spec.rb
275
292
  - spec/spec_helper.rb
276
293
  - spec/support/config.rb
294
+ - spec/support/example_data_methods.rb
277
295
  - spec/support/factory_girl.rb
278
296
  - spec/support/helpers.rb
279
297
  - spec/support/models/issue.rb