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,33 +2,51 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module Data
|
4
4
|
class PopulateOneDimension
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :sparse_serieses_dimension_keys_values, :context_record, :properties
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
self.
|
7
|
+
def initialize(sparse_serieses_dimension_keys_values, context_record: nil, properties: nil)
|
8
|
+
self.sparse_serieses_dimension_keys_values = sparse_serieses_dimension_keys_values
|
9
|
+
self.context_record = context_record
|
10
|
+
self.properties = properties
|
9
11
|
end
|
10
12
|
|
11
13
|
def perform
|
12
|
-
return
|
13
|
-
|
14
|
+
return sparse_serieses_dimension_keys_values if sparse_serieses_dimension_keys_values.length == 1
|
15
|
+
serieses_dimension_keys_values
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
+
def serieses_dimension_keys_values
|
21
|
+
serieses_dimension_keys_values = sparse_serieses_dimension_keys_values.map do |series, dimension_keys_values|
|
20
22
|
dimension_keys.each do |key|
|
21
23
|
dimension_keys_values[key] ||= 0
|
22
24
|
end
|
23
|
-
[
|
25
|
+
[series, dimension_keys_values]
|
24
26
|
end
|
25
|
-
Hash[
|
27
|
+
Hash[serieses_dimension_keys_values]
|
26
28
|
end
|
27
29
|
|
28
30
|
def dimension_keys
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
dimension_keys_from_edit_dimension_keys_method || dimension_keys_from_results
|
32
|
+
end
|
33
|
+
|
34
|
+
def dimension_keys_from_edit_dimension_keys_method
|
35
|
+
return unless edit_dimension_keys_method
|
36
|
+
edit_dimension_keys_method.call(dimension_keys: dimension_keys_from_results, properties: properties, context_record: context_record)
|
37
|
+
end
|
38
|
+
|
39
|
+
def dimension_keys_from_results
|
40
|
+
@dimension_keys_from_results ||= begin
|
41
|
+
sparse_serieses_dimension_keys_values.map do |series, dimension_keys_values|
|
42
|
+
dimension_keys_values.keys
|
43
|
+
end.reduce(&:+).uniq
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def edit_dimension_keys_method
|
48
|
+
return unless properties
|
49
|
+
ReportsKit.configuration.custom_method(properties[:report_options].try(:[], :edit_dimension_keys_method))
|
32
50
|
end
|
33
51
|
end
|
34
52
|
end
|
@@ -2,25 +2,25 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module Data
|
4
4
|
class PopulateTwoDimensions
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :serieses, :dimension, :second_dimension, :sparse_serieses_dimension_keys_values
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
self.
|
9
|
-
self.dimension =
|
10
|
-
self.second_dimension =
|
11
|
-
self.
|
7
|
+
def initialize(sparse_serieses_dimension_keys_values)
|
8
|
+
self.serieses = sparse_serieses_dimension_keys_values.keys
|
9
|
+
self.dimension = serieses.first.dimensions[0]
|
10
|
+
self.second_dimension = serieses.first.dimensions[1]
|
11
|
+
self.sparse_serieses_dimension_keys_values = sparse_serieses_dimension_keys_values
|
12
12
|
end
|
13
13
|
|
14
14
|
def perform
|
15
|
-
|
15
|
+
serieses_populated_dimension_keys_values
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
-
def
|
21
|
-
|
20
|
+
def serieses_populated_dimension_keys_values
|
21
|
+
serieses_dimension_keys_values = {}
|
22
22
|
secondary_keys_sums = Hash.new(0)
|
23
|
-
|
23
|
+
serieses_populated_primary_keys_secondary_keys_values.each do |series, primary_keys_secondary_keys_values|
|
24
24
|
primary_keys_secondary_keys_values.each do |primary_key, secondary_keys_values|
|
25
25
|
secondary_keys_values.each do |secondary_key, value|
|
26
26
|
secondary_keys_sums[secondary_key] += value
|
@@ -28,55 +28,55 @@ module ReportsKit
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
sorted_secondary_keys = secondary_keys_sums.sort_by(&:last).reverse.map(&:first)
|
31
|
-
|
32
|
-
|
31
|
+
serieses_populated_primary_keys_secondary_keys_values.each do |series, primary_key_secondary_keys_values|
|
32
|
+
serieses_dimension_keys_values[series] = {}
|
33
33
|
primary_key_secondary_keys_values.each do |primary_key, secondary_keys_values|
|
34
34
|
secondary_keys_values = secondary_keys_values.sort_by { |key, _| sorted_secondary_keys.index(key) }
|
35
35
|
secondary_keys_values.each do |secondary_key, value|
|
36
36
|
dimension_key = [primary_key, secondary_key]
|
37
|
-
|
37
|
+
serieses_dimension_keys_values[series][dimension_key] = value
|
38
38
|
secondary_keys_sums[secondary_key] += value
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
serieses_dimension_keys_values
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
45
|
+
def serieses_populated_primary_keys_secondary_keys_values
|
46
46
|
@populated_dimension_keys_values ||= begin
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
serieses_populated_primary_keys_secondary_keys_values = {}
|
48
|
+
serieses.each do |series|
|
49
|
+
serieses_populated_primary_keys_secondary_keys_values[series] = {}
|
50
50
|
primary_keys.each do |primary_key|
|
51
|
-
|
51
|
+
serieses_populated_primary_keys_secondary_keys_values[series][primary_key] = {}
|
52
52
|
secondary_keys.each do |secondary_key|
|
53
|
-
value =
|
54
|
-
|
53
|
+
value = serieses_primary_keys_secondary_keys_values[series][primary_key].try(:[], secondary_key) || 0
|
54
|
+
serieses_populated_primary_keys_secondary_keys_values[series][primary_key][secondary_key] = value
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
serieses_populated_primary_keys_secondary_keys_values
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
def
|
63
|
-
@
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
def serieses_primary_keys_secondary_keys_values
|
63
|
+
@serieses_primary_keys_secondary_keys_values ||= begin
|
64
|
+
serieses_primary_keys_secondary_keys_values = {}
|
65
|
+
sparse_serieses_dimension_keys_values.each do |series, dimension_keys_values|
|
66
|
+
serieses_primary_keys_secondary_keys_values[series] = {}
|
67
67
|
dimension_keys_values.each do |(primary_key, secondary_key), value|
|
68
68
|
primary_key = primary_key.to_date if primary_key.is_a?(Time)
|
69
69
|
secondary_key = secondary_key.to_date if secondary_key.is_a?(Time)
|
70
|
-
|
71
|
-
|
70
|
+
serieses_primary_keys_secondary_keys_values[series][primary_key] ||= {}
|
71
|
+
serieses_primary_keys_secondary_keys_values[series][primary_key][secondary_key] = value
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
serieses_primary_keys_secondary_keys_values
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
78
|
def dimension_keys
|
79
|
-
@dimension_keys ||=
|
79
|
+
@dimension_keys ||= sparse_serieses_dimension_keys_values.values.map(&:keys).reduce(&:+).uniq
|
80
80
|
end
|
81
81
|
|
82
82
|
def primary_keys
|
@@ -2,14 +2,18 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module Data
|
4
4
|
class Utils
|
5
|
-
def self.format_display_time(time)
|
6
|
-
time.strftime('%b %-d, \'%y')
|
7
|
-
end
|
8
|
-
|
9
5
|
def self.format_configuration_time(time)
|
10
6
|
time.strftime('%b %-d, %Y')
|
11
7
|
end
|
12
8
|
|
9
|
+
def self.format_csv_time(time)
|
10
|
+
time.strftime('%Y-%m-%d')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.format_display_time(time)
|
14
|
+
time.strftime('%b %-d, \'%y')
|
15
|
+
end
|
16
|
+
|
13
17
|
def self.format_time_value(value)
|
14
18
|
time = RelativeTime.parse(value, prevent_exceptions: true)
|
15
19
|
return value unless time
|
@@ -22,17 +26,19 @@ module ReportsKit
|
|
22
26
|
number.round(Generate::ROUND_PRECISION)
|
23
27
|
end
|
24
28
|
|
29
|
+
def self.quote_column_name(string)
|
30
|
+
ActiveRecord::Base.connection.quote_column_name(string)
|
31
|
+
end
|
32
|
+
|
25
33
|
def self.parse_date_string(string)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
RelativeTime.parse(string)
|
30
|
-
end
|
34
|
+
Date.parse(string)
|
35
|
+
rescue ArgumentError
|
36
|
+
RelativeTime.parse(string)
|
31
37
|
end
|
32
38
|
|
33
39
|
def self.populate_sparse_hash(hash, dimension:)
|
34
40
|
keys = hash.keys
|
35
|
-
is_nested = dimension.
|
41
|
+
is_nested = dimension.series.has_two_dimensions?
|
36
42
|
if is_nested
|
37
43
|
keys_values = arrays_values_to_nested_hash(hash)
|
38
44
|
keys = keys_values.keys
|
@@ -67,11 +73,7 @@ module ReportsKit
|
|
67
73
|
keys = keys.sort
|
68
74
|
last_key = (dimension.last_key || keys.last).to_date
|
69
75
|
last_key = last_key.beginning_of_week(ReportsKit.configuration.first_day_of_week) if granularity == 'week'
|
70
|
-
|
71
|
-
if granularity == 'week'
|
72
|
-
beginning_of_current_week = Date.today.beginning_of_week(ReportsKit.configuration.first_day_of_week)
|
73
|
-
last_key = [beginning_of_current_week, last_key].compact.max
|
74
|
-
end
|
76
|
+
last_key ||= Date.today.beginning_of_week(ReportsKit.configuration.first_day_of_week) if granularity == 'week'
|
75
77
|
|
76
78
|
date = first_key
|
77
79
|
populated_keys = []
|
@@ -145,8 +147,8 @@ module ReportsKit
|
|
145
147
|
Value.new(raw_value, formatted_value)
|
146
148
|
end
|
147
149
|
|
148
|
-
def self.normalize_filters(
|
149
|
-
|
150
|
+
def self.normalize_filters(series_properties, ui_filters)
|
151
|
+
series_properties[:filters] = series_properties[:filters].map do |filter_properties|
|
150
152
|
filter_properties = { key: filter_properties } if filter_properties.is_a?(String)
|
151
153
|
key = filter_properties[:key]
|
152
154
|
ui_key = filter_properties[:ui_key]
|
@@ -158,18 +160,20 @@ module ReportsKit
|
|
158
160
|
end
|
159
161
|
filter_properties
|
160
162
|
end
|
161
|
-
|
163
|
+
series_properties
|
162
164
|
end
|
163
165
|
|
164
166
|
def self.normalize_properties(properties, ui_filters: nil)
|
167
|
+
can_have_nesting = properties[:composite_operator].present? || properties[:series].is_a?(Array)
|
165
168
|
ui_filters ||= properties[:ui_filters]
|
166
169
|
properties = properties.dup
|
167
|
-
properties[:
|
168
|
-
|
169
|
-
properties
|
170
|
-
|
171
|
-
|
172
|
-
|
170
|
+
properties[:series] ||= properties.slice(*Series::VALID_KEYS).presence
|
171
|
+
properties[:series] = [properties[:series]] if properties[:series].is_a?(Hash) && properties[:series].present?
|
172
|
+
return properties if ui_filters.blank? || properties[:series].blank?
|
173
|
+
properties[:series] = properties[:series].map do |series_properties|
|
174
|
+
series_properties = normalize_properties(series_properties, ui_filters: ui_filters) if can_have_nesting
|
175
|
+
next(series_properties) if series_properties[:filters].blank?
|
176
|
+
normalize_filters(series_properties, ui_filters)
|
173
177
|
end
|
174
178
|
properties
|
175
179
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ReportsKit
|
2
2
|
module Reports
|
3
|
-
class
|
4
|
-
DEFAULT_DIMENSION_INSTANCES_LIMIT = 30
|
3
|
+
class DimensionWithSeries
|
5
4
|
DEFAULT_GRANULARITY = 'week'
|
6
5
|
VALID_GRANULARITIES = %w(day week).freeze
|
7
6
|
ADAPTER_NAMES_CLASSES = {
|
@@ -9,16 +8,16 @@ module ReportsKit
|
|
9
8
|
'postgresql' => Adapters::Postgresql
|
10
9
|
}.freeze
|
11
10
|
|
12
|
-
attr_accessor :dimension, :
|
11
|
+
attr_accessor :dimension, :series, :configuration
|
13
12
|
|
14
|
-
delegate :key, :properties, :label, to: :dimension
|
13
|
+
delegate :key, :expression, :properties, :label, to: :dimension
|
15
14
|
delegate :configured_by_association?, :configured_by_column?, :configured_by_model?, :configured_by_time?,
|
16
15
|
:settings_from_model, :reflection, :instance_class, :model_class, :column_type,
|
17
16
|
to: :configuration
|
18
17
|
|
19
|
-
def initialize(dimension:,
|
18
|
+
def initialize(dimension:, series:)
|
20
19
|
self.dimension = dimension
|
21
|
-
self.
|
20
|
+
self.series = series
|
22
21
|
self.configuration = InferrableConfiguration.new(self, :dimensions)
|
23
22
|
missing_group_setting = settings && !settings.key?(:group)
|
24
23
|
raise ArgumentError.new("Dimension settings for dimension '#{key}' of #{model_class} must include :group") if missing_group_setting
|
@@ -84,7 +83,7 @@ module ReportsKit
|
|
84
83
|
if configured_by_time?
|
85
84
|
properties[:limit]
|
86
85
|
else
|
87
|
-
properties[:limit] ||
|
86
|
+
properties[:limit] || ReportsKit.configuration.default_dimension_limit
|
88
87
|
end
|
89
88
|
end
|
90
89
|
|
@@ -104,8 +103,8 @@ module ReportsKit
|
|
104
103
|
end
|
105
104
|
|
106
105
|
def datetime_filters
|
107
|
-
return [] unless
|
108
|
-
|
106
|
+
return [] unless series.filters.present?
|
107
|
+
series.filters.map(&:filter_type).select { |filter_type| filter_type.is_a?(FilterTypes::Datetime) }
|
109
108
|
end
|
110
109
|
|
111
110
|
def should_be_sorted_by_count?
|
@@ -2,11 +2,12 @@ module ReportsKit
|
|
2
2
|
module Reports
|
3
3
|
module FilterTypes
|
4
4
|
class Base
|
5
|
-
attr_accessor :settings, :properties
|
5
|
+
attr_accessor :settings, :properties, :primary_dimension
|
6
6
|
|
7
|
-
def initialize(settings, properties)
|
7
|
+
def initialize(settings, properties, primary_dimension:)
|
8
8
|
self.settings = settings || {}
|
9
9
|
self.properties = properties
|
10
|
+
self.primary_dimension = primary_dimension
|
10
11
|
end
|
11
12
|
|
12
13
|
def apply_filter(records)
|
@@ -39,7 +40,7 @@ module ReportsKit
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def column
|
42
|
-
settings[:column] || properties[:key]
|
43
|
+
settings[:column] || Data::Utils.quote_column_name(properties[:key])
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -20,13 +20,13 @@ module ReportsKit
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def boolean_value
|
23
|
-
case
|
23
|
+
case value
|
24
24
|
when true, 'true'
|
25
25
|
true
|
26
26
|
when false, 'false'
|
27
27
|
false
|
28
28
|
else
|
29
|
-
raise ArgumentError.new("Unsupported value: '#{
|
29
|
+
raise ArgumentError.new("Unsupported value: '#{value}'")
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -35,11 +35,11 @@ module ReportsKit
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def valid?
|
38
|
-
|
38
|
+
value.present?
|
39
39
|
end
|
40
40
|
|
41
41
|
def conditions
|
42
|
-
settings[:conditions] || properties[:key]
|
42
|
+
settings[:conditions] || Data::Utils.quote_column_name(properties[:key])
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -10,7 +10,7 @@ module ReportsKit
|
|
10
10
|
def apply_conditions(records)
|
11
11
|
case criteria[:operator]
|
12
12
|
when 'between'
|
13
|
-
records.where(
|
13
|
+
records.where.not(column => nil).where(column => start_at..end_at)
|
14
14
|
else
|
15
15
|
raise ArgumentError.new("Unsupported operator: '#{criteria[:operator]}'")
|
16
16
|
end
|
@@ -21,8 +21,8 @@ module ReportsKit
|
|
21
21
|
return unless valid?
|
22
22
|
start_string, end_string = value.split(SEPARATOR)
|
23
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
|
-
|
24
|
+
end_at = ReportsKit::Reports::Data::Utils.parse_date_string(end_string)
|
25
|
+
adjust_range_to_dimension(start_at, end_at)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -34,6 +34,16 @@ module ReportsKit
|
|
34
34
|
start_at_end_at.try(:[], 1)
|
35
35
|
end
|
36
36
|
|
37
|
+
def adjust_range_to_dimension(start_at, end_at)
|
38
|
+
return [start_at.beginning_of_day, end_at.end_of_day] unless primary_dimension.configured_by_time?
|
39
|
+
return [start_at.beginning_of_day, end_at.end_of_day] if primary_dimension.granularity == 'day'
|
40
|
+
return [
|
41
|
+
start_at.beginning_of_week(ReportsKit.configuration.first_day_of_week),
|
42
|
+
end_at.end_of_week(ReportsKit.configuration.first_day_of_week)
|
43
|
+
] if primary_dimension.granularity == 'week'
|
44
|
+
[start_at, end_at]
|
45
|
+
end
|
46
|
+
|
37
47
|
def valid?
|
38
48
|
value.present?
|
39
49
|
end
|
@@ -7,15 +7,15 @@ module ReportsKit
|
|
7
7
|
def apply_conditions(records)
|
8
8
|
case criteria[:operator]
|
9
9
|
when '>'
|
10
|
-
records.where(
|
10
|
+
records.where(column => (value.to_i...Float::INFINITY))
|
11
11
|
when '>='
|
12
|
-
records.where(
|
12
|
+
records.where(column => (value.to_i..Float::INFINITY))
|
13
13
|
when '<'
|
14
|
-
records.where(
|
14
|
+
records.where(column => (-Float::INFINITY...value.to_i))
|
15
15
|
when '<='
|
16
|
-
records.where(
|
16
|
+
records.where(column => (-Float::INFINITY..value.to_i))
|
17
17
|
when '='
|
18
|
-
records.where(
|
18
|
+
records.where(column => value.to_i)
|
19
19
|
else
|
20
20
|
raise ArgumentError.new("Unsupported operator: '#{criteria[:operator]}'")
|
21
21
|
end
|