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.
- checksums.yaml +5 -5
- data/.codeclimate.yml +8 -0
- data/.github/workflows/ci.yml +128 -0
- data/.gitignore +23 -0
- data/.rspec +1 -0
- data/.rubocop.yml +58 -0
- data/Appraisals +28 -0
- data/CHANGELOG.md +102 -7
- data/Gemfile +4 -1
- data/Guardfile +16 -0
- data/LICENSE +17 -18
- data/README.md +595 -404
- data/Rakefile +4 -2
- data/ajax-datatables-rails.gemspec +41 -25
- data/appraisal.yml +56 -0
- data/bin/_guard-core +29 -0
- data/bin/appraisal +29 -0
- data/bin/bundle +114 -0
- data/bin/guard +29 -0
- data/bin/rackup +27 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/config.ru +7 -0
- data/doc/migrate.md +97 -0
- data/doc/webpack.md +55 -0
- data/gemfiles/rails_5.2.8.gemfile +21 -0
- data/gemfiles/rails_6.0.6.gemfile +21 -0
- data/gemfiles/rails_6.1.7.gemfile +21 -0
- data/gemfiles/rails_7.0.4.gemfile +21 -0
- data/lib/ajax-datatables-rails/active_record.rb +7 -0
- data/lib/ajax-datatables-rails/base.rb +114 -149
- data/lib/ajax-datatables-rails/datatable/column/date_filter.rb +68 -0
- data/lib/ajax-datatables-rails/datatable/column/order.rb +29 -0
- data/lib/ajax-datatables-rails/datatable/column/search.rb +125 -0
- data/lib/ajax-datatables-rails/datatable/column.rb +123 -0
- data/lib/ajax-datatables-rails/datatable/datatable.rb +91 -0
- data/lib/ajax-datatables-rails/datatable/simple_order.rb +59 -0
- data/lib/ajax-datatables-rails/datatable/simple_search.rb +23 -0
- data/lib/ajax-datatables-rails/datatable.rb +6 -0
- data/lib/ajax-datatables-rails/error.rb +9 -0
- data/lib/ajax-datatables-rails/orm/active_record.rb +60 -0
- data/lib/ajax-datatables-rails/orm.rb +6 -0
- data/lib/ajax-datatables-rails/version.rb +15 -1
- data/lib/ajax-datatables-rails.rb +11 -7
- data/lib/generators/rails/datatable_generator.rb +11 -22
- data/lib/generators/rails/templates/datatable.rb +13 -15
- data/spec/ajax-datatables-rails/base_spec.rb +223 -0
- data/spec/ajax-datatables-rails/datatable/column_spec.rb +222 -0
- data/spec/ajax-datatables-rails/datatable/datatable_spec.rb +127 -0
- data/spec/ajax-datatables-rails/datatable/simple_order_spec.rb +62 -0
- data/spec/ajax-datatables-rails/datatable/simple_search_spec.rb +19 -0
- data/spec/ajax-datatables-rails/orm/active_record_filter_records_spec.rb +639 -0
- data/spec/ajax-datatables-rails/orm/active_record_paginate_records_spec.rb +67 -0
- data/spec/ajax-datatables-rails/orm/active_record_sort_records_spec.rb +80 -0
- data/spec/dummy/app/assets/config/manifest.js +0 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config/storage.yml +3 -0
- data/spec/dummy/db/schema.rb +13 -0
- data/spec/dummy/log/.gitignore +1 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/user.rb +11 -0
- data/spec/install_oracle.sh +18 -0
- data/spec/spec_helper.rb +85 -6
- data/spec/support/datatables/complex_datatable.rb +33 -0
- data/spec/support/datatables/complex_datatable_array.rb +16 -0
- data/spec/support/datatables/datatable_cond_date.rb +7 -0
- data/spec/support/datatables/datatable_cond_numeric.rb +53 -0
- data/spec/support/datatables/datatable_cond_proc.rb +13 -0
- data/spec/support/datatables/datatable_cond_string.rb +43 -0
- data/spec/support/datatables/datatable_cond_unknown.rb +7 -0
- data/spec/support/datatables/datatable_custom_column.rb +17 -0
- data/spec/support/datatables/datatable_order_nulls_last.rb +7 -0
- data/spec/support/helpers/params.rb +80 -0
- data/spec/support/models/user.rb +7 -0
- metadata +249 -48
- data/lib/ajax-datatables-rails/config.rb +0 -25
- data/lib/ajax-datatables-rails/extensions/kaminari.rb +0 -12
- data/lib/ajax-datatables-rails/extensions/simple_paginator.rb +0 -12
- data/lib/ajax-datatables-rails/extensions/will_paginate.rb +0 -12
- data/lib/ajax-datatables-rails/models.rb +0 -6
- data/lib/generators/datatable/config_generator.rb +0 -17
- data/lib/generators/datatable/templates/ajax_datatables_rails_config.rb +0 -7
- data/spec/ajax-datatables-rails/ajax_datatables_rails_spec.rb +0 -351
- data/spec/ajax-datatables-rails/kaminari_spec.rb +0 -35
- data/spec/ajax-datatables-rails/models_spec.rb +0 -10
- data/spec/ajax-datatables-rails/simple_paginator_spec.rb +0 -32
- data/spec/ajax-datatables-rails/will_paginate_spec.rb +0 -28
- data/spec/schema.rb +0 -35
- 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: "../"
|
@@ -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
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
20
|
-
|
21
|
-
end
|
26
|
+
class_attribute :db_adapter, default: default_db_adapter
|
27
|
+
class_attribute :nulls_last, default: false
|
22
28
|
|
23
|
-
|
24
|
-
@searchable_columns ||= []
|
25
|
-
end
|
29
|
+
attr_reader :params, :options, :datatable
|
26
30
|
|
27
|
-
|
28
|
-
fail(
|
29
|
-
MethodNotImplementedError,
|
30
|
-
'Please implement this method in your class.'
|
31
|
-
)
|
32
|
-
end
|
31
|
+
GLOBAL_SEARCH_DELIMITER = ' '
|
33
32
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
)
|
33
|
+
def initialize(params, options = {})
|
34
|
+
@params = params
|
35
|
+
@options = options
|
36
|
+
@datatable = Datatable::Datatable.new(self)
|
39
37
|
end
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
51
|
-
|
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
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
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
|
-
|
84
|
-
MethodNotImplementedError,
|
85
|
-
'Please mixin a pagination extension.'
|
86
|
-
)
|
66
|
+
raise(NotImplementedError)
|
87
67
|
end
|
88
68
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
records
|
69
|
+
# User overides
|
70
|
+
def additional_data
|
71
|
+
{}
|
93
72
|
end
|
94
73
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
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
|
109
|
-
|
110
|
-
|
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
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
133
|
-
|
134
|
-
|
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
|
141
|
-
|
142
|
-
|
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
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
158
|
-
|
126
|
+
# called from within #data
|
127
|
+
def records
|
128
|
+
@records ||= retrieve_records
|
159
129
|
end
|
160
130
|
|
161
|
-
def
|
162
|
-
|
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
|
166
|
-
|
139
|
+
def records_total_count
|
140
|
+
fetch_records.count(:all)
|
167
141
|
end
|
168
142
|
|
169
|
-
def
|
170
|
-
|
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
|
177
|
-
|
147
|
+
def global_search_delimiter
|
148
|
+
GLOBAL_SEARCH_DELIMITER
|
178
149
|
end
|
179
150
|
|
180
|
-
def
|
181
|
-
|
182
|
-
col = [model.constantize.table_name, column].join('.')
|
183
|
-
end
|
151
|
+
def raw_records_error_text
|
152
|
+
<<-ERROR
|
184
153
|
|
185
|
-
|
186
|
-
|
187
|
-
|
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
|
191
|
-
|
192
|
-
end
|
159
|
+
def data_error_text
|
160
|
+
<<-ERROR
|
193
161
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|