reports_kit 0.2.0 → 0.3.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.
- 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
data/docs/display_options.md
CHANGED
@@ -11,10 +11,9 @@ You can use any `type` value supported by Chart.js, including `bar`, `line`, `ho
|
|
11
11
|
Here's an example of a horizontal bar chart:
|
12
12
|
|
13
13
|
```yaml
|
14
|
-
measure:
|
15
|
-
|
16
|
-
|
17
|
-
- carrier
|
14
|
+
measure: flight
|
15
|
+
dimensions:
|
16
|
+
- carrier
|
18
17
|
chart:
|
19
18
|
type: horizontalBar
|
20
19
|
options:
|
@@ -37,11 +36,10 @@ You can use any `options` that are supported by Chart.js.
|
|
37
36
|
Here's an example of a chart with Chart.js options:
|
38
37
|
|
39
38
|
```yaml
|
40
|
-
measure:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
- carrier
|
39
|
+
measure: flight
|
40
|
+
dimensions:
|
41
|
+
- origin_market
|
42
|
+
- carrier
|
45
43
|
chart:
|
46
44
|
type: horizontalBar
|
47
45
|
options:
|
@@ -66,12 +64,11 @@ You can use any `datasets` options that are supported by Chart.js.
|
|
66
64
|
Here's an example of a chart with `datasets` options:
|
67
65
|
|
68
66
|
```yaml
|
69
|
-
measure:
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
limit: 3
|
67
|
+
measure: flight
|
68
|
+
dimensions:
|
69
|
+
- flight_at
|
70
|
+
- key: carrier
|
71
|
+
limit: 3
|
75
72
|
chart:
|
76
73
|
type: line
|
77
74
|
datasets:
|
data/docs/filters.md
CHANGED
@@ -7,13 +7,12 @@ A filter is like a SQL `WHERE`: it filters the results to only include results t
|
|
7
7
|
For example, if the `Flight` model has a `delay` column that's an integer, the chart below will show only flights that have a delay of greater than 15 minutes:
|
8
8
|
|
9
9
|
```yaml
|
10
|
-
measure:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
value: 15
|
10
|
+
measure: flight
|
11
|
+
filters:
|
12
|
+
- key: delay
|
13
|
+
criteria:
|
14
|
+
operator: '>'
|
15
|
+
value: 15
|
17
16
|
dimensions:
|
18
17
|
- carrier
|
19
18
|
```
|
@@ -22,13 +21,12 @@ dimensions:
|
|
22
21
|
You can also create form controls that the user can use to filter the chart:
|
23
22
|
|
24
23
|
```yaml
|
25
|
-
measure:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
- flight_at
|
24
|
+
measure: flight
|
25
|
+
filters:
|
26
|
+
- carrier
|
27
|
+
- carrier_name
|
28
|
+
- is_on_time
|
29
|
+
- flight_at
|
32
30
|
dimensions:
|
33
31
|
- flight_at
|
34
32
|
- carrier
|
@@ -55,12 +53,11 @@ In `app/views/my_view.html.haml`, you can use ReportsKit's form helpers to creat
|
|
55
53
|
Boolean filters can be used on any `boolean` columns, or you can define your own boolean filter (see [Custom Filters](#custom-filters)).
|
56
54
|
|
57
55
|
```yaml
|
58
|
-
measure:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
value: true
|
56
|
+
measure: flight
|
57
|
+
filters:
|
58
|
+
- key: is_on_time
|
59
|
+
criteria:
|
60
|
+
value: true
|
64
61
|
dimensions:
|
65
62
|
- carrier
|
66
63
|
```
|
@@ -71,30 +68,30 @@ dimensions:
|
|
71
68
|
Datetime filters can be used on any `datetime` or `timestamp` columns, or you can define your own datetime filter (see [Custom Filters](#custom-filters)).
|
72
69
|
|
73
70
|
```yaml
|
74
|
-
measure:
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
value: Oct 1, 2016 - Jan 1, 2017
|
71
|
+
measure: flight
|
72
|
+
filters:
|
73
|
+
- key: flight_at
|
74
|
+
criteria:
|
75
|
+
operator: between
|
76
|
+
value: -3M - now
|
81
77
|
dimensions:
|
82
78
|
- carrier
|
83
79
|
```
|
84
80
|
[<img src="images/flights_with_configured_datetime.png?raw=true" width="500" />](images/flights_with_configured_datetime.png?raw=true)
|
85
81
|
|
82
|
+
The `value` in the example above is shorthand for relative time; it represents the time range of `(3.months.ago..Time.zone.now)`. To see the other supported time durations (e.g. `w` for week, `d` for day), see [RelativeTime](https://github.com/tombenner/reports_kit/blob/master/lib/reports_kit/relative_time.rb).
|
83
|
+
|
86
84
|
##### Number
|
87
85
|
|
88
86
|
Number filters can be used on any `integer`, `float`, or `decimal` columns, or you can define your own number filter (see [Custom Filters](#custom-filters)).
|
89
87
|
|
90
88
|
```yaml
|
91
|
-
measure:
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
value: 15
|
89
|
+
measure: flight
|
90
|
+
filters:
|
91
|
+
- key: delay
|
92
|
+
criteria:
|
93
|
+
operator: '>'
|
94
|
+
value: 15
|
98
95
|
dimensions:
|
99
96
|
- carrier
|
100
97
|
```
|
@@ -105,13 +102,12 @@ dimensions:
|
|
105
102
|
String filters can be used on any `string` or `text` columns, or you can define your own number filter (see [Custom Filters](#custom-filters)).
|
106
103
|
|
107
104
|
```yaml
|
108
|
-
measure:
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
value: airlines
|
105
|
+
measure: flight
|
106
|
+
filters:
|
107
|
+
- key: carrier_name
|
108
|
+
criteria:
|
109
|
+
operator: contains
|
110
|
+
value: airlines
|
115
111
|
dimensions:
|
116
112
|
- carrier
|
117
113
|
```
|
@@ -134,12 +130,11 @@ end
|
|
134
130
|
We can then use the `was_delayed` filter:
|
135
131
|
|
136
132
|
```yaml
|
137
|
-
measure:
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
value: true
|
133
|
+
measure: flight
|
134
|
+
filters:
|
135
|
+
- key: was_delayed
|
136
|
+
criteria:
|
137
|
+
value: true
|
143
138
|
dimensions:
|
144
139
|
- carrier
|
145
140
|
```
|
@@ -154,10 +149,9 @@ Most charting libraries don't provide interactive form controls, but ReportsKit
|
|
154
149
|
Check boxes can be used with filters that have a `boolean` type.
|
155
150
|
|
156
151
|
```yaml
|
157
|
-
measure:
|
158
|
-
|
159
|
-
|
160
|
-
- is_on_time
|
152
|
+
measure: flight
|
153
|
+
filters:
|
154
|
+
- is_on_time
|
161
155
|
dimensions:
|
162
156
|
- flight_at
|
163
157
|
- carrier
|
@@ -176,10 +170,9 @@ dimensions:
|
|
176
170
|
Date ranges can be used with filters that have a `datetime` type.
|
177
171
|
|
178
172
|
```yaml
|
179
|
-
measure:
|
180
|
-
|
181
|
-
|
182
|
-
- flight_at
|
173
|
+
measure: flight
|
174
|
+
filters:
|
175
|
+
- flight_at
|
183
176
|
dimensions:
|
184
177
|
- flight_at
|
185
178
|
- carrier
|
@@ -193,10 +186,9 @@ dimensions:
|
|
193
186
|
##### Multi-Autocomplete
|
194
187
|
|
195
188
|
```yaml
|
196
|
-
measure:
|
197
|
-
|
198
|
-
|
199
|
-
- carrier
|
189
|
+
measure: flight
|
190
|
+
filters:
|
191
|
+
- carrier
|
200
192
|
dimensions:
|
201
193
|
- flight_at
|
202
194
|
- carrier
|
@@ -210,10 +202,9 @@ dimensions:
|
|
210
202
|
##### String Filter
|
211
203
|
|
212
204
|
```yaml
|
213
|
-
measure:
|
214
|
-
|
215
|
-
|
216
|
-
- carrier_name
|
205
|
+
measure: flight
|
206
|
+
filters:
|
207
|
+
- carrier_name
|
217
208
|
dimensions:
|
218
209
|
- flight_at
|
219
210
|
- carrier
|
data/docs/measures.md
CHANGED
@@ -5,9 +5,8 @@ The measure is what is being counted (or aggregated in another way). You can use
|
|
5
5
|
For example, say we have a `Flight` model with a `flight_at` datetime column. We can chart the number of flights over time:
|
6
6
|
|
7
7
|
```yaml
|
8
|
-
measure:
|
9
|
-
|
10
|
-
|
11
|
-
- flight_at
|
8
|
+
measure: flight
|
9
|
+
dimensions:
|
10
|
+
- flight_at
|
12
11
|
```
|
13
12
|
[<img src="images/flights_by_flight_at.png?raw=true" width="500" />](images/flights_by_flight_at.png?raw=true)
|
data/lib/reports_kit.rb
CHANGED
@@ -4,6 +4,7 @@ require 'reports_kit/base_controller'
|
|
4
4
|
require 'reports_kit/cache'
|
5
5
|
require 'reports_kit/configuration'
|
6
6
|
require 'reports_kit/engine'
|
7
|
+
require 'reports_kit/entity'
|
7
8
|
require 'reports_kit/helper'
|
8
9
|
require 'reports_kit/model'
|
9
10
|
require 'reports_kit/model_configuration'
|
@@ -12,24 +13,25 @@ require 'reports_kit/relative_time'
|
|
12
13
|
require 'reports_kit/report_builder'
|
13
14
|
require 'reports_kit/resources_controller'
|
14
15
|
require 'reports_kit/reports_controller'
|
16
|
+
require 'reports_kit/value'
|
15
17
|
require 'reports_kit/version'
|
16
18
|
|
17
19
|
require 'reports_kit/reports/adapters/mysql'
|
18
20
|
require 'reports_kit/reports/adapters/postgresql'
|
19
21
|
|
22
|
+
require 'reports_kit/reports/data/add_table_aggregations'
|
23
|
+
require 'reports_kit/reports/data/aggregate_composite'
|
24
|
+
require 'reports_kit/reports/data/aggregate_one_dimension'
|
25
|
+
require 'reports_kit/reports/data/aggregate_two_dimensions'
|
20
26
|
require 'reports_kit/reports/data/chart_options'
|
21
|
-
require 'reports_kit/reports/data/composite_aggregation'
|
22
|
-
require 'reports_kit/reports/data/entity'
|
23
27
|
require 'reports_kit/reports/data/format_one_dimension'
|
28
|
+
require 'reports_kit/reports/data/format_table'
|
24
29
|
require 'reports_kit/reports/data/format_two_dimensions'
|
25
30
|
require 'reports_kit/reports/data/generate'
|
26
31
|
require 'reports_kit/reports/data/generate_for_properties'
|
27
|
-
require 'reports_kit/reports/data/one_dimension'
|
28
32
|
require 'reports_kit/reports/data/populate_one_dimension'
|
29
33
|
require 'reports_kit/reports/data/populate_two_dimensions'
|
30
|
-
require 'reports_kit/reports/data/two_dimensions'
|
31
34
|
require 'reports_kit/reports/data/utils'
|
32
|
-
require 'reports_kit/reports/data/value'
|
33
35
|
|
34
36
|
require 'reports_kit/reports/filter_types/base'
|
35
37
|
require 'reports_kit/reports/filter_types/boolean'
|
@@ -38,15 +40,15 @@ require 'reports_kit/reports/filter_types/number'
|
|
38
40
|
require 'reports_kit/reports/filter_types/records'
|
39
41
|
require 'reports_kit/reports/filter_types/string'
|
40
42
|
|
41
|
-
require 'reports_kit/reports/
|
42
|
-
require 'reports_kit/reports/
|
43
|
+
require 'reports_kit/reports/abstract_series'
|
44
|
+
require 'reports_kit/reports/composite_series'
|
43
45
|
require 'reports_kit/reports/dimension'
|
44
|
-
require 'reports_kit/reports/
|
46
|
+
require 'reports_kit/reports/dimension_with_series'
|
45
47
|
require 'reports_kit/reports/filter'
|
46
|
-
require 'reports_kit/reports/
|
48
|
+
require 'reports_kit/reports/filter_with_series'
|
47
49
|
require 'reports_kit/reports/generate_autocomplete_results'
|
48
50
|
require 'reports_kit/reports/inferrable_configuration'
|
49
|
-
require 'reports_kit/reports/
|
51
|
+
require 'reports_kit/reports/series'
|
50
52
|
|
51
53
|
module ReportsKit
|
52
54
|
def self.configure
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ReportsKit
|
2
2
|
class BaseController < ActionController::Base
|
3
|
-
|
4
|
-
|
3
|
+
# This is intentionally public to allow external code to access it
|
5
4
|
def context_record
|
6
5
|
context_record_method = ReportsKit.configuration.context_record_method
|
7
6
|
return unless context_record_method
|
@@ -1,22 +1,37 @@
|
|
1
1
|
module ReportsKit
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :cache_duration, :cache_store,
|
4
|
-
:
|
3
|
+
attr_accessor :cache_duration, :cache_store, :context_record_method, :custom_methods, :default_dimension_limit,
|
4
|
+
:default_properties, :first_day_of_week, :properties_method, :report_filename_method, :use_concurrent_queries
|
5
|
+
|
6
|
+
DEFAULT_PROPERTIES_METHOD = lambda do |env|
|
7
|
+
path = Rails.root.join('config', 'reports_kit', 'reports', "#{report_key}.yml")
|
8
|
+
YAML.load_file(path)
|
9
|
+
end
|
5
10
|
|
6
11
|
def initialize
|
7
12
|
self.cache_duration = 5.minutes
|
8
13
|
self.cache_store = nil
|
9
|
-
self.context_params_method = nil
|
10
14
|
self.context_record_method = nil
|
11
15
|
self.custom_methods = {}
|
16
|
+
self.default_dimension_limit = 30
|
17
|
+
self.default_properties = nil
|
12
18
|
self.first_day_of_week = :sunday
|
19
|
+
self.properties_method = DEFAULT_PROPERTIES_METHOD
|
20
|
+
self.report_filename_method = nil
|
21
|
+
self.use_concurrent_queries = false
|
13
22
|
end
|
14
23
|
|
15
24
|
def custom_method(method_name)
|
16
25
|
return if method_name.blank?
|
17
|
-
method =
|
26
|
+
method = evaluated_custom_methods[method_name.to_sym]
|
18
27
|
raise ArgumentError.new("A method named '#{method_name}' is not defined") unless method
|
19
28
|
method
|
20
29
|
end
|
30
|
+
|
31
|
+
def evaluated_custom_methods
|
32
|
+
return custom_methods if custom_methods.is_a?(Hash)
|
33
|
+
return custom_methods.call if custom_methods.is_a?(Proc)
|
34
|
+
raise ArgumentError.new("Invalid type for custom_methods configuration: #{custom_methods.class}")
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
data/lib/reports_kit/helper.rb
CHANGED
@@ -5,15 +5,16 @@ module ReportsKit
|
|
5
5
|
'export_xls' => :export_xls_element
|
6
6
|
}
|
7
7
|
|
8
|
-
def render_report(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
def render_report(report_params, context_params: {}, actions: %w(export_csv export_xls), js_report_class: 'Report', &block)
|
9
|
+
report_params = { key: report_params } if report_params.is_a?(String)
|
10
|
+
additional_params = { context_params: context_params, report_params: report_params }
|
11
|
+
params.merge!(additional_params)
|
12
|
+
properties = instance_eval(&ReportsKit.configuration.properties_method)
|
13
|
+
properties = properties.deep_symbolize_keys
|
14
14
|
builder = ReportsKit::ReportBuilder.new(properties, additional_params: additional_params)
|
15
15
|
path = reports_kit.reports_kit_reports_path({ format: 'json' }.merge(additional_params))
|
16
|
-
|
16
|
+
data = { properties: properties.slice(:format), path: path, report_class: js_report_class }
|
17
|
+
content_tag :div, nil, class: 'reports_kit_report form-inline', data: data do
|
17
18
|
elements = []
|
18
19
|
if block_given?
|
19
20
|
elements << form_tag(path, method: 'get', class: 'reports_kit_report_form') do
|
@@ -21,7 +22,7 @@ module ReportsKit
|
|
21
22
|
end
|
22
23
|
end
|
23
24
|
elements << content_tag(:div, nil, class: 'reports_kit_visualization')
|
24
|
-
action_elements =
|
25
|
+
action_elements = generate_action_elements(actions, additional_params)
|
25
26
|
if action_elements
|
26
27
|
elements << content_tag(:div, nil, class: 'reports_kit_actions') do
|
27
28
|
action_elements.map { |element| concat(element) }
|
@@ -33,25 +34,20 @@ module ReportsKit
|
|
33
34
|
|
34
35
|
private
|
35
36
|
|
36
|
-
def
|
37
|
-
|
38
|
-
context_params_method = ReportsKit.configuration.context_params_method
|
39
|
-
return {} unless context_params_method
|
40
|
-
context_params = instance_eval(&context_params_method)
|
41
|
-
{ context_params: context_params }
|
42
|
-
end
|
37
|
+
def report_key
|
38
|
+
params[:report_params][:key]
|
43
39
|
end
|
44
40
|
|
45
|
-
def
|
46
|
-
return if
|
47
|
-
|
41
|
+
def generate_action_elements(actions, additional_params)
|
42
|
+
return if actions.blank?
|
43
|
+
actions.map do |action|
|
48
44
|
element_method = ACTION_KEYS_METHODS[action]
|
49
45
|
raise ArgumentError.new("Invalid action: #{action}") unless element_method
|
50
|
-
send(element_method)
|
46
|
+
send(element_method, additional_params)
|
51
47
|
end
|
52
48
|
end
|
53
49
|
|
54
|
-
def export_csv_element
|
50
|
+
def export_csv_element(additional_params)
|
55
51
|
data = {
|
56
52
|
role: 'reports_kit_export_button',
|
57
53
|
path: reports_kit.reports_kit_reports_path({ format: 'csv' }.merge(additional_params))
|
@@ -59,7 +55,7 @@ module ReportsKit
|
|
59
55
|
link_to('Download CSV', '#', class: 'btn btn-primary', data: data)
|
60
56
|
end
|
61
57
|
|
62
|
-
def export_xls_element
|
58
|
+
def export_xls_element(additional_params)
|
63
59
|
data = {
|
64
60
|
role: 'reports_kit_export_button',
|
65
61
|
path: reports_kit.reports_kit_reports_path({ format: 'xls' }.merge(additional_params))
|
@@ -9,7 +9,7 @@ module ReportsKit
|
|
9
9
|
self.autocomplete_scopes = []
|
10
10
|
end
|
11
11
|
|
12
|
-
def aggregation(key, expression, properties={})
|
12
|
+
def aggregation(key, expression, properties = {})
|
13
13
|
aggregations << { key: key.to_s, expression: expression }.merge(properties).symbolize_keys
|
14
14
|
end
|
15
15
|
|