ajax-datatables-rails 0.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +8 -0
  3. data/.github/workflows/ci.yml +128 -0
  4. data/.gitignore +23 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +58 -0
  7. data/Appraisals +28 -0
  8. data/CHANGELOG.md +102 -7
  9. data/Gemfile +4 -1
  10. data/Guardfile +16 -0
  11. data/LICENSE +17 -18
  12. data/README.md +595 -404
  13. data/Rakefile +4 -2
  14. data/ajax-datatables-rails.gemspec +41 -25
  15. data/appraisal.yml +56 -0
  16. data/bin/_guard-core +29 -0
  17. data/bin/appraisal +29 -0
  18. data/bin/bundle +114 -0
  19. data/bin/guard +29 -0
  20. data/bin/rackup +27 -0
  21. data/bin/rake +29 -0
  22. data/bin/rspec +29 -0
  23. data/bin/rubocop +29 -0
  24. data/config.ru +7 -0
  25. data/doc/migrate.md +97 -0
  26. data/doc/webpack.md +55 -0
  27. data/gemfiles/rails_5.2.8.gemfile +21 -0
  28. data/gemfiles/rails_6.0.6.gemfile +21 -0
  29. data/gemfiles/rails_6.1.7.gemfile +21 -0
  30. data/gemfiles/rails_7.0.4.gemfile +21 -0
  31. data/lib/ajax-datatables-rails/active_record.rb +7 -0
  32. data/lib/ajax-datatables-rails/base.rb +114 -149
  33. data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +68 -0
  34. data/lib/ajax-datatables-rails/datatable/column/order.rb +29 -0
  35. data/lib/ajax-datatables-rails/datatable/column/search.rb +125 -0
  36. data/lib/ajax-datatables-rails/datatable/column.rb +123 -0
  37. data/lib/ajax-datatables-rails/datatable/datatable.rb +91 -0
  38. data/lib/ajax-datatables-rails/datatable/simple_order.rb +59 -0
  39. data/lib/ajax-datatables-rails/datatable/simple_search.rb +23 -0
  40. data/lib/ajax-datatables-rails/datatable.rb +6 -0
  41. data/lib/ajax-datatables-rails/error.rb +9 -0
  42. data/lib/ajax-datatables-rails/orm/active_record.rb +60 -0
  43. data/lib/ajax-datatables-rails/orm.rb +6 -0
  44. data/lib/ajax-datatables-rails/version.rb +15 -1
  45. data/lib/ajax-datatables-rails.rb +11 -7
  46. data/lib/generators/rails/datatable_generator.rb +11 -22
  47. data/lib/generators/rails/templates/datatable.rb +13 -15
  48. data/spec/ajax-datatables-rails/base_spec.rb +223 -0
  49. data/spec/ajax-datatables-rails/datatable/column_spec.rb +222 -0
  50. data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +127 -0
  51. data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +62 -0
  52. data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +19 -0
  53. data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +639 -0
  54. data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +67 -0
  55. data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +80 -0
  56. data/spec/dummy/app/assets/config/manifest.js +0 -0
  57. data/spec/dummy/config/database.yml +25 -0
  58. data/spec/dummy/config/routes.rb +5 -0
  59. data/spec/dummy/config/storage.yml +3 -0
  60. data/spec/dummy/db/schema.rb +13 -0
  61. data/spec/dummy/log/.gitignore +1 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/factories/user.rb +11 -0
  64. data/spec/install_oracle.sh +18 -0
  65. data/spec/spec_helper.rb +85 -6
  66. data/spec/support/datatables/complex_datatable.rb +33 -0
  67. data/spec/support/datatables/complex_datatable_array.rb +16 -0
  68. data/spec/support/datatables/datatable_cond_date.rb +7 -0
  69. data/spec/support/datatables/datatable_cond_numeric.rb +53 -0
  70. data/spec/support/datatables/datatable_cond_proc.rb +13 -0
  71. data/spec/support/datatables/datatable_cond_string.rb +43 -0
  72. data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
  73. data/spec/support/datatables/datatable_custom_column.rb +17 -0
  74. data/spec/support/datatables/datatable_order_nulls_last.rb +7 -0
  75. data/spec/support/helpers/params.rb +80 -0
  76. data/spec/support/models/user.rb +7 -0
  77. metadata +249 -48
  78. data/lib/ajax-datatables-rails/config.rb +0 -25
  79. data/lib/ajax-datatables-rails/extensions/kaminari.rb +0 -12
  80. data/lib/ajax-datatables-rails/extensions/simple_paginator.rb +0 -12
  81. data/lib/ajax-datatables-rails/extensions/will_paginate.rb +0 -12
  82. data/lib/ajax-datatables-rails/models.rb +0 -6
  83. data/lib/generators/datatable/config_generator.rb +0 -17
  84. data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -7
  85. data/spec/ajax-datatables-rails/ajax_datatables_rails_spec.rb +0 -351
  86. data/spec/ajax-datatables-rails/kaminari_spec.rb +0 -35
  87. data/spec/ajax-datatables-rails/models_spec.rb +0 -10
  88. data/spec/ajax-datatables-rails/simple_paginator_spec.rb +0 -32
  89. data/spec/ajax-datatables-rails/will_paginate_spec.rb +0 -28
  90. data/spec/schema.rb +0 -35
  91. data/spec/test_models.rb +0 -21
@@ -0,0 +1,21 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/n-rodriguez/appraisal.git", branch: "wip/combustion"
6
+ gem "rails", "6.1.7"
7
+
8
+ install_if -> { ENV["DB_ADAPTER"] == "sqlite3" } do
9
+ gem "sqlite3", "~> 1.4.0"
10
+ end
11
+
12
+ install_if -> { ENV["DB_ADAPTER"] == "mysql2" } do
13
+ gem "mysql2"
14
+ end
15
+
16
+ install_if -> { ENV["DB_ADAPTER"] == "oracle_enhanced" } do
17
+ gem "activerecord-oracle_enhanced-adapter", "~> 6.1.0"
18
+ gem "ruby-oci8"
19
+ end
20
+
21
+ gemspec path: "../"
@@ -0,0 +1,21 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/n-rodriguez/appraisal.git", branch: "wip/combustion"
6
+ gem "rails", "7.0.4"
7
+
8
+ install_if -> { ENV["DB_ADAPTER"] == "sqlite3" } do
9
+ gem "sqlite3", "~> 1.4.0"
10
+ end
11
+
12
+ install_if -> { ENV["DB_ADAPTER"] == "mysql2" } do
13
+ gem "mysql2"
14
+ end
15
+
16
+ install_if -> { ENV["DB_ADAPTER"] == "oracle_enhanced" } do
17
+ gem "activerecord-oracle_enhanced-adapter", "~> 7.0.0"
18
+ gem "ruby-oci8"
19
+ end
20
+
21
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ class ActiveRecord < AjaxDatatablesRails::Base
5
+ include AjaxDatatablesRails::ORM::ActiveRecord
6
+ end
7
+ end
@@ -1,214 +1,179 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AjaxDatatablesRails
2
4
  class Base
3
- extend Forwardable
4
- class MethodNotImplementedError < StandardError; end
5
5
 
6
- attr_reader :view, :options, :sortable_columns, :searchable_columns
7
- def_delegator :@view, :params, :params
6
+ class << self
7
+ def rails_52?
8
+ Rails.gem_version >= Gem::Version.new('5.2') && Rails.gem_version <= Gem::Version.new('6.0')
9
+ end
8
10
 
9
- def initialize(view, options = {})
10
- @view = view
11
- @options = options
12
- load_paginator
13
- end
11
+ def rails_60?
12
+ Rails.gem_version >= Gem::Version.new('6.0') && Rails.gem_version <= Gem::Version.new('6.1')
13
+ end
14
14
 
15
- def config
16
- @config ||= AjaxDatatablesRails.config
15
+ def default_db_adapter
16
+ if rails_52?
17
+ ::ActiveRecord::Base.configurations.dig(Rails.env, 'adapter').downcase.to_sym
18
+ elsif rails_60?
19
+ ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first.config['adapter'].downcase.to_sym
20
+ else
21
+ ::ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first.adapter.downcase.to_sym
22
+ end
23
+ end
17
24
  end
18
25
 
19
- def sortable_columns
20
- @sortable_columns ||= []
21
- end
26
+ class_attribute :db_adapter, default: default_db_adapter
27
+ class_attribute :nulls_last, default: false
22
28
 
23
- def searchable_columns
24
- @searchable_columns ||= []
25
- end
29
+ attr_reader :params, :options, :datatable
26
30
 
27
- def data
28
- fail(
29
- MethodNotImplementedError,
30
- 'Please implement this method in your class.'
31
- )
32
- end
31
+ GLOBAL_SEARCH_DELIMITER = ' '
33
32
 
34
- def get_raw_records
35
- fail(
36
- MethodNotImplementedError,
37
- 'Please implement this method in your class.'
38
- )
33
+ def initialize(params, options = {})
34
+ @params = params
35
+ @options = options
36
+ @datatable = Datatable::Datatable.new(self)
39
37
  end
40
38
 
41
- def as_json(options = {})
42
- {
43
- :draw => params[:draw].to_i,
44
- :recordsTotal => get_raw_records.count(:all),
45
- :recordsFiltered => filter_records(get_raw_records).count(:all),
46
- :data => data
47
- }
39
+ # User defined methods
40
+ def view_columns
41
+ raise(NotImplementedError, view_columns_error_text)
48
42
  end
49
43
 
50
- def self.deprecated(message, caller = Kernel.caller[1])
51
- warning = caller + ": " + message
52
-
53
- if(respond_to?(:logger) && logger.present?)
54
- logger.warn(warning)
55
- else
56
- warn(warning)
57
- end
44
+ def get_raw_records
45
+ raise(NotImplementedError, raw_records_error_text)
58
46
  end
59
47
 
60
- private
61
-
62
- def records
63
- @records ||= fetch_records
48
+ def data
49
+ raise(NotImplementedError, data_error_text)
64
50
  end
65
51
 
52
+ # ORM defined methods
66
53
  def fetch_records
67
- records = get_raw_records
68
- records = sort_records(records) if params[:order].present?
69
- records = filter_records(records) if params[:search].present?
70
- records = paginate_records(records) unless params[:length].present? && params[:length] == '-1'
71
- records
54
+ get_raw_records
55
+ end
56
+
57
+ def filter_records(records)
58
+ raise(NotImplementedError)
72
59
  end
73
60
 
74
61
  def sort_records(records)
75
- sort_by = []
76
- params[:order].each_value do |item|
77
- sort_by << "#{sort_column(item)} #{sort_direction(item)}"
78
- end
79
- records.order(sort_by.join(", "))
62
+ raise(NotImplementedError)
80
63
  end
81
64
 
82
65
  def paginate_records(records)
83
- fail(
84
- MethodNotImplementedError,
85
- 'Please mixin a pagination extension.'
86
- )
66
+ raise(NotImplementedError)
87
67
  end
88
68
 
89
- def filter_records(records)
90
- records = simple_search(records)
91
- records = composite_search(records)
92
- records
69
+ # User overides
70
+ def additional_data
71
+ {}
93
72
  end
94
73
 
95
- def simple_search(records)
96
- return records unless (params[:search].present? && params[:search][:value].present?)
97
- conditions = build_conditions_for(params[:search][:value])
98
- records = records.where(conditions) if conditions
99
- records
74
+ # JSON structure sent to jQuery DataTables
75
+ def as_json(*)
76
+ {
77
+ recordsTotal: records_total_count,
78
+ recordsFiltered: records_filtered_count,
79
+ data: sanitize_data(data),
80
+ }.merge(additional_data)
100
81
  end
101
82
 
102
- def composite_search(records)
103
- conditions = aggregate_query
104
- records = records.where(conditions) if conditions
105
- records
83
+ # User helper methods
84
+ def column_id(name)
85
+ view_columns.keys.index(name.to_sym)
106
86
  end
107
87
 
108
- def build_conditions_for(query)
109
- search_for = query.split(' ')
110
- criteria = search_for.inject([]) do |criteria, atom|
111
- criteria << searchable_columns.map { |col| search_condition(col, atom) }.reduce(:or)
112
- end.reduce(:and)
113
- criteria
88
+ def column_data(column)
89
+ id = column_id(column)
90
+ params.dig('columns', id.to_s, 'search', 'value')
114
91
  end
115
92
 
116
- def search_condition(column, value)
117
- if column[0] == column.downcase[0]
118
- ::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
119
- return deprecated_search_condition(column, value)
120
- else
121
- return new_search_condition(column, value)
122
- end
123
- end
93
+ private
124
94
 
125
- def new_search_condition(column, value)
126
- model, column = column.split('.')
127
- model = model.constantize
128
- casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
129
- casted_column.matches("%#{value}%")
95
+ # helper methods
96
+ def connected_columns
97
+ @connected_columns ||= begin
98
+ view_columns.keys.map do |field_name|
99
+ datatable.column_by(:data, field_name.to_s)
100
+ end.compact
101
+ end
130
102
  end
131
103
 
132
- def deprecated_search_condition(column, value)
133
- model, column = column.split('.')
134
- model = model.singularize.titleize.gsub( / /, '' ).constantize
135
-
136
- casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
137
- casted_column.matches("%#{value}%")
104
+ def searchable_columns
105
+ @searchable_columns ||= begin
106
+ connected_columns.select(&:searchable?)
107
+ end
138
108
  end
139
109
 
140
- def aggregate_query
141
- conditions = searchable_columns.each_with_index.map do |column, index|
142
- value = params[:columns]["#{index}"][:search][:value] if params[:columns]
143
- search_condition(column, value) unless value.blank?
110
+ def search_columns
111
+ @search_columns ||= begin
112
+ searchable_columns.select(&:searched?)
144
113
  end
145
- conditions.compact.reduce(:and)
146
114
  end
147
115
 
148
- def typecast
149
- case config.db_adapter
150
- when :oracle then 'VARCHAR2(4000)'
151
- when :pg then 'VARCHAR'
152
- when :mysql2 then 'CHAR'
153
- when :sqlite3 then 'TEXT'
116
+ def sanitize_data(data)
117
+ data.map do |record|
118
+ if record.is_a?(Array)
119
+ record.map { |td| ERB::Util.html_escape(td) }
120
+ else
121
+ record.update(record) { |_, v| ERB::Util.html_escape(v) }
122
+ end
154
123
  end
155
124
  end
156
125
 
157
- def offset
158
- (page - 1) * per_page
126
+ # called from within #data
127
+ def records
128
+ @records ||= retrieve_records
159
129
  end
160
130
 
161
- def page
162
- (params[:start].to_i / per_page) + 1
131
+ def retrieve_records
132
+ records = fetch_records
133
+ records = filter_records(records)
134
+ records = sort_records(records) if datatable.orderable?
135
+ records = paginate_records(records) if datatable.paginate?
136
+ records
163
137
  end
164
138
 
165
- def per_page
166
- params.fetch(:length, 10).to_i
139
+ def records_total_count
140
+ fetch_records.count(:all)
167
141
  end
168
142
 
169
- def sort_column(item)
170
- new_sort_column(item)
171
- rescue
172
- ::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
173
- deprecated_sort_column(item)
143
+ def records_filtered_count
144
+ filter_records(fetch_records).count(:all)
174
145
  end
175
146
 
176
- def deprecated_sort_column(item)
177
- sortable_columns[sortable_displayed_columns.index(item[:column])]
147
+ def global_search_delimiter
148
+ GLOBAL_SEARCH_DELIMITER
178
149
  end
179
150
 
180
- def new_sort_column(item)
181
- model, column = sortable_columns[sortable_displayed_columns.index(item[:column])].split('.')
182
- col = [model.constantize.table_name, column].join('.')
183
- end
151
+ def raw_records_error_text
152
+ <<-ERROR
184
153
 
185
- def sort_direction(item)
186
- options = %w(desc asc)
187
- options.include?(item[:dir]) ? item[:dir].upcase : 'ASC'
154
+ You should implement this method in your class and specify
155
+ how records are going to be retrieved from the database.
156
+ ERROR
188
157
  end
189
158
 
190
- def sortable_displayed_columns
191
- @sortable_displayed_columns ||= generate_sortable_displayed_columns
192
- end
159
+ def data_error_text
160
+ <<-ERROR
193
161
 
194
- def generate_sortable_displayed_columns
195
- @sortable_displayed_columns = []
196
- params[:columns].each_value do |column|
197
- @sortable_displayed_columns << column[:data] if column[:orderable] == 'true'
198
- end
199
- @sortable_displayed_columns
162
+ You should implement this method in your class and return an array
163
+ of arrays, or an array of hashes, as defined in the jQuery.dataTables
164
+ plugin documentation.
165
+ ERROR
200
166
  end
201
167
 
202
- def load_paginator
203
- case config.paginator
204
- when :kaminari
205
- extend Extensions::Kaminari
206
- when :will_paginate
207
- extend Extensions::WillPaginate
208
- else
209
- extend Extensions::SimplePaginator
210
- end
211
- self
168
+ def view_columns_error_text
169
+ <<-ERROR
170
+
171
+ You should implement this method in your class and return an array
172
+ of database columns based on the columns displayed in the HTML view.
173
+ These columns should be represented in the ModelName.column_name,
174
+ or aliased_join_table.column_name notation.
175
+ ERROR
212
176
  end
177
+
213
178
  end
214
179
  end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ module Datatable
5
+ class Column
6
+ module DateFilter
7
+
8
+ RANGE_DELIMITER = '-'
9
+
10
+ class DateRange
11
+ attr_reader :begin, :end
12
+
13
+ def initialize(date_start, date_end)
14
+ @begin = date_start
15
+ @end = date_end
16
+ end
17
+
18
+ def exclude_end?
19
+ false
20
+ end
21
+ end
22
+
23
+ # Add delimiter option to handle range search
24
+ def delimiter
25
+ @delimiter ||= @view_column.fetch(:delimiter, RANGE_DELIMITER)
26
+ end
27
+
28
+ # A range value is in form '<range_start><delimiter><range_end>'
29
+ # This returns <range_start>
30
+ def range_start
31
+ @range_start ||= formatted_value.split(delimiter)[0]
32
+ end
33
+
34
+ # A range value is in form '<range_start><delimiter><range_end>'
35
+ # This returns <range_end>
36
+ def range_end
37
+ @range_end ||= formatted_value.split(delimiter)[1]
38
+ end
39
+
40
+ def empty_range_search?
41
+ (formatted_value == delimiter) || (range_start.blank? && range_end.blank?)
42
+ end
43
+
44
+ # Do a range search
45
+ def date_range_search
46
+ return nil if empty_range_search?
47
+
48
+ table[field].between(DateRange.new(range_start_casted, range_end_casted))
49
+ end
50
+
51
+ private
52
+
53
+ def range_start_casted
54
+ range_start.blank? ? parse_date('01/01/1970') : parse_date(range_start)
55
+ end
56
+
57
+ def range_end_casted
58
+ range_end.blank? ? parse_date('9999-12-31 23:59:59') : parse_date("#{range_end} 23:59:59")
59
+ end
60
+
61
+ def parse_date(date)
62
+ Time.zone ? Time.zone.parse(date) : Time.parse(date)
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ module Datatable
5
+ class Column
6
+ module Order
7
+
8
+ def orderable?
9
+ @view_column.fetch(:orderable, true)
10
+ end
11
+
12
+ # Add sort_field option to allow overriding of sort field
13
+ def sort_field
14
+ @view_column.fetch(:sort_field, field)
15
+ end
16
+
17
+ def sort_query
18
+ custom_field? ? source : "#{table.name}.#{sort_field}"
19
+ end
20
+
21
+ # Add option to sort null values last
22
+ def nulls_last?
23
+ @view_column.fetch(:nulls_last, false)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AjaxDatatablesRails
4
+ module Datatable
5
+ class Column
6
+ module Search
7
+
8
+ SMALLEST_PQ_INTEGER = -2_147_483_648
9
+ LARGEST_PQ_INTEGER = 2_147_483_647
10
+ NOT_NULL_VALUE = '!NULL'
11
+ EMPTY_VALUE = ''
12
+
13
+ def searchable?
14
+ @view_column.fetch(:searchable, true)
15
+ end
16
+
17
+ def cond
18
+ @view_column.fetch(:cond, :like)
19
+ end
20
+
21
+ def filter
22
+ @view_column[:cond].call(self, formatted_value)
23
+ end
24
+
25
+ def search
26
+ @search ||= SimpleSearch.new(options[:search])
27
+ end
28
+
29
+ def searched?
30
+ search.value.present?
31
+ end
32
+
33
+ def search_query
34
+ search.regexp? ? regex_search : non_regex_search
35
+ end
36
+
37
+ # Add use_regex option to allow bypassing of regex search
38
+ def use_regex?
39
+ @view_column.fetch(:use_regex, true)
40
+ end
41
+
42
+ private
43
+
44
+ # Using multi-select filters in JQuery Datatable auto-enables regex_search.
45
+ # Unfortunately regex_search doesn't work when filtering on primary keys with integer.
46
+ # It generates this kind of query : AND ("regions"."id" ~ '2|3') which throws an error :
47
+ # operator doesn't exist : integer ~ unknown
48
+ # The solution is to bypass regex_search and use non_regex_search with :in operator
49
+ def regex_search
50
+ if use_regex?
51
+ ::Arel::Nodes::Regexp.new((custom_field? ? field : table[field]), ::Arel::Nodes.build_quoted(formatted_value))
52
+ else
53
+ non_regex_search
54
+ end
55
+ end
56
+
57
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
58
+ def non_regex_search
59
+ case cond
60
+ when Proc
61
+ filter
62
+ when :eq, :not_eq, :lt, :gt, :lteq, :gteq, :in
63
+ searchable_integer? ? raw_search(cond) : empty_search
64
+ when :start_with
65
+ text_search("#{formatted_value}%")
66
+ when :end_with
67
+ text_search("%#{formatted_value}")
68
+ when :like
69
+ text_search("%#{formatted_value}%")
70
+ when :string_eq
71
+ raw_search(:eq)
72
+ when :string_in
73
+ raw_search(:in)
74
+ when :null_value
75
+ null_value_search
76
+ when :date_range
77
+ date_range_search
78
+ end
79
+ end
80
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
81
+
82
+ def null_value_search
83
+ if formatted_value == NOT_NULL_VALUE
84
+ table[field].not_eq(nil)
85
+ else
86
+ table[field].eq(nil)
87
+ end
88
+ end
89
+
90
+ def raw_search(cond)
91
+ table[field].send(cond, formatted_value) unless custom_field?
92
+ end
93
+
94
+ def text_search(value)
95
+ casted_column.matches(value) unless custom_field?
96
+ end
97
+
98
+ def empty_search
99
+ casted_column.matches(EMPTY_VALUE)
100
+ end
101
+
102
+ def searchable_integer?
103
+ if formatted_value.is_a?(Array)
104
+ valids = formatted_value.map { |v| integer?(v) && !out_of_range?(v) }
105
+ !valids.include?(false)
106
+ else
107
+ integer?(formatted_value) && !out_of_range?(formatted_value)
108
+ end
109
+ end
110
+
111
+ def out_of_range?(search_value)
112
+ Integer(search_value) > LARGEST_PQ_INTEGER || Integer(search_value) < SMALLEST_PQ_INTEGER
113
+ end
114
+
115
+ def integer?(string)
116
+ Integer(string)
117
+ true
118
+ rescue ArgumentError
119
+ false
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+ end