ransack 1.5.1 → 1.6.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +47 -3
  3. data/CHANGELOG.md +106 -18
  4. data/CONTRIBUTING.md +56 -23
  5. data/Gemfile +16 -5
  6. data/README.md +114 -38
  7. data/Rakefile +30 -2
  8. data/lib/ransack.rb +9 -0
  9. data/lib/ransack/adapters/active_record/3.0/compat.rb +11 -8
  10. data/lib/ransack/adapters/active_record/3.0/context.rb +14 -22
  11. data/lib/ransack/adapters/active_record/3.1/context.rb +14 -22
  12. data/lib/ransack/adapters/active_record/context.rb +36 -31
  13. data/lib/ransack/adapters/active_record/ransack/constants.rb +113 -0
  14. data/lib/ransack/adapters/active_record/ransack/context.rb +64 -0
  15. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +48 -0
  16. data/lib/ransack/adapters/active_record/ransack/translate.rb +12 -0
  17. data/lib/ransack/adapters/active_record/ransack/visitor.rb +24 -0
  18. data/lib/ransack/adapters/mongoid.rb +13 -0
  19. data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
  20. data/lib/ransack/adapters/mongoid/attributes/attribute.rb +37 -0
  21. data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +17 -0
  22. data/lib/ransack/adapters/mongoid/attributes/predications.rb +141 -0
  23. data/lib/ransack/adapters/mongoid/base.rb +126 -0
  24. data/lib/ransack/adapters/mongoid/context.rb +208 -0
  25. data/lib/ransack/adapters/mongoid/inquiry_hash.rb +23 -0
  26. data/lib/ransack/adapters/mongoid/ransack/constants.rb +88 -0
  27. data/lib/ransack/adapters/mongoid/ransack/context.rb +60 -0
  28. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +27 -0
  29. data/lib/ransack/adapters/mongoid/ransack/translate.rb +13 -0
  30. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +24 -0
  31. data/lib/ransack/adapters/mongoid/table.rb +35 -0
  32. data/lib/ransack/configuration.rb +22 -4
  33. data/lib/ransack/constants.rb +26 -120
  34. data/lib/ransack/context.rb +32 -60
  35. data/lib/ransack/helpers/form_builder.rb +50 -36
  36. data/lib/ransack/helpers/form_helper.rb +148 -104
  37. data/lib/ransack/naming.rb +11 -11
  38. data/lib/ransack/nodes.rb +2 -0
  39. data/lib/ransack/nodes/bindable.rb +12 -4
  40. data/lib/ransack/nodes/condition.rb +5 -22
  41. data/lib/ransack/nodes/grouping.rb +9 -10
  42. data/lib/ransack/nodes/sort.rb +3 -2
  43. data/lib/ransack/nodes/value.rb +1 -2
  44. data/lib/ransack/predicate.rb +3 -3
  45. data/lib/ransack/search.rb +46 -13
  46. data/lib/ransack/translate.rb +8 -8
  47. data/lib/ransack/version.rb +1 -1
  48. data/lib/ransack/visitor.rb +4 -16
  49. data/ransack.gemspec +1 -0
  50. data/spec/mongoid/adapters/mongoid/base_spec.rb +276 -0
  51. data/spec/mongoid/adapters/mongoid/context_spec.rb +56 -0
  52. data/spec/mongoid/configuration_spec.rb +66 -0
  53. data/spec/mongoid/dependencies_spec.rb +8 -0
  54. data/spec/mongoid/helpers/ransack_helper.rb +11 -0
  55. data/spec/mongoid/nodes/condition_spec.rb +34 -0
  56. data/spec/mongoid/nodes/grouping_spec.rb +13 -0
  57. data/spec/mongoid/predicate_spec.rb +155 -0
  58. data/spec/mongoid/search_spec.rb +446 -0
  59. data/spec/mongoid/support/mongoid.yml +6 -0
  60. data/spec/mongoid/support/schema.rb +128 -0
  61. data/spec/mongoid/translate_spec.rb +14 -0
  62. data/spec/mongoid_spec_helper.rb +59 -0
  63. data/spec/ransack/adapters/active_record/base_spec.rb +68 -35
  64. data/spec/ransack/dependencies_spec.rb +3 -1
  65. data/spec/ransack/helpers/form_builder_spec.rb +6 -6
  66. data/spec/ransack/helpers/form_helper_spec.rb +114 -47
  67. data/spec/ransack/nodes/condition_spec.rb +2 -2
  68. data/spec/ransack/search_spec.rb +2 -6
  69. data/spec/ransack/translate_spec.rb +1 -1
  70. data/spec/spec_helper.rb +2 -3
  71. data/spec/support/schema.rb +9 -0
  72. metadata +49 -4
data/Rakefile CHANGED
@@ -1,13 +1,29 @@
1
1
  require 'bundler'
2
2
  require 'rspec/core/rake_task'
3
+ require 'active_record'
3
4
 
4
5
  Bundler::GemHelper.install_tasks
5
6
 
6
7
  RSpec::Core::RakeTask.new(:spec) do |rspec|
8
+ ENV['SPEC'] = 'spec/ransack/**/*_spec.rb'
9
+ if ActiveRecord::VERSION::MAJOR >= 4 || RUBY_VERSION < '2.2'
10
+ # Raises `invalid option: --backtrace` with Rails 3.x on Ruby 2.2
11
+ rspec.rspec_opts = ['--backtrace']
12
+ end
13
+ end
14
+
15
+ RSpec::Core::RakeTask.new(:mongoid) do |rspec|
16
+ ENV['SPEC'] = 'spec/mongoid/**/*_spec.rb'
7
17
  rspec.rspec_opts = ['--backtrace']
8
18
  end
9
19
 
10
- task :default => :spec
20
+ task :default do
21
+ if ENV['DB'] =~ /mongodb/
22
+ Rake::Task["mongoid"].invoke
23
+ else
24
+ Rake::Task["spec"].invoke
25
+ end
26
+ end
11
27
 
12
28
  desc "Open an irb session with Ransack and the sample data used in specs"
13
29
  task :console do
@@ -16,4 +32,16 @@ task :console do
16
32
  require 'console'
17
33
  ARGV.clear
18
34
  IRB.start
19
- end
35
+ end
36
+
37
+ desc "Open an irb session with Ransack, Mongoid and the sample data used in specs"
38
+ task :mongoid_console do
39
+ require 'irb'
40
+ require 'irb/completion'
41
+ require 'pry'
42
+ require 'mongoid'
43
+ require File.expand_path('../lib/ransack.rb', __FILE__)
44
+ require File.expand_path('../spec/mongoid/support/schema.rb', __FILE__)
45
+ ARGV.clear
46
+ Pry.start
47
+ end
@@ -2,6 +2,12 @@ require 'active_support/core_ext'
2
2
 
3
3
  require 'ransack/configuration'
4
4
 
5
+ if defined?(::Mongoid)
6
+ require 'ransack/adapters/mongoid/ransack/constants'
7
+ else
8
+ require 'ransack/adapters/active_record/ransack/constants'
9
+ end
10
+
5
11
  module Ransack
6
12
  extend Configuration
7
13
 
@@ -19,9 +25,12 @@ Ransack.configure do |config|
19
25
  end
20
26
 
21
27
  require 'ransack/translate'
28
+ require 'ransack/adapters/active_record/ransack/translate' if defined?(::ActiveRecord::Base)
29
+ require 'ransack/adapters/mongoid/ransack/translate' if defined?(::Mongoid)
22
30
  require 'ransack/search'
23
31
  require 'ransack/ransacker'
24
32
  require 'ransack/adapters/active_record' if defined?(::ActiveRecord::Base)
33
+ require 'ransack/adapters/mongoid' if defined?(::Mongoid)
25
34
  require 'ransack/helpers'
26
35
  require 'action_controller'
27
36
 
@@ -16,9 +16,12 @@ end
16
16
 
17
17
  class ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase
18
18
  def table
19
- Arel::Table.new(table_name, :as => aliased_table_name,
20
- :engine => active_record.arel_engine,
21
- :columns => active_record.columns)
19
+ Arel::Table.new(
20
+ table_name,
21
+ :as => aliased_table_name,
22
+ :engine => active_record.arel_engine,
23
+ :columns => active_record.columns
24
+ )
22
25
  end
23
26
  end
24
27
 
@@ -120,9 +123,9 @@ module Arel
120
123
  def column_cache
121
124
  @column_cache ||= Hash.new do |hash, key|
122
125
  hash[key] = Hash[
123
- @engine.connection.columns(key, "#{key} Columns").map do |c|
124
- [c.name, c]
125
- end
126
+ @engine.connection
127
+ .columns(key, "#{key} Columns")
128
+ .map { |c| [c.name, c] }
126
129
  ]
127
130
  end
128
131
  end
@@ -144,7 +147,7 @@ module Arel
144
147
  end
145
148
 
146
149
  def visit_Arel_Nodes_And o
147
- o.children.map { |x| visit x }.join(' AND '.freeze)
150
+ o.children.map { |x| visit x }.join(Ransack::Constants::SPACED_AND)
148
151
  end
149
152
 
150
153
  def visit_Arel_Nodes_Not o
@@ -173,4 +176,4 @@ module Arel
173
176
  end
174
177
  end
175
178
 
176
- end
179
+ end
@@ -30,10 +30,8 @@ module Ransack
30
30
  .reorder(viz.accept(search.sorts))
31
31
  end
32
32
  if opts[:distinct]
33
- relation.select(
34
- Ransack::Constants::DISTINCT + @klass.quoted_table_name +
35
- '.*'.freeze
36
- )
33
+ relation.select(Constants::DISTINCT + @klass.quoted_table_name +
34
+ Constants::DOT_ASTERIX)
37
35
  else
38
36
  relation
39
37
  end
@@ -50,11 +48,11 @@ module Ransack
50
48
  while !found_assoc && remainder.unshift(segments.pop) &&
51
49
  segments.size > 0 do
52
50
  assoc, poly_class = unpolymorphize_association(
53
- segments.join(Ransack::Constants::UNDERSCORE)
51
+ segments.join(Constants::UNDERSCORE)
54
52
  )
55
53
  if found_assoc = get_association(assoc, klass)
56
54
  exists = attribute_method?(
57
- remainder.join(Ransack::Constants::UNDERSCORE),
55
+ remainder.join(Constants::UNDERSCORE),
58
56
  poly_class || found_assoc.klass
59
57
  )
60
58
  end
@@ -104,14 +102,14 @@ module Ransack
104
102
  while remainder.unshift(segments.pop) && segments.size > 0 &&
105
103
  !found_assoc do
106
104
  assoc, klass = unpolymorphize_association(
107
- segments.join(Ransack::Constants::UNDERSCORE)
105
+ segments.join(Constants::UNDERSCORE)
108
106
  )
109
107
  if found_assoc = get_association(assoc, parent)
110
108
  join = build_or_find_association(
111
109
  found_assoc.name, parent, klass
112
110
  )
113
111
  parent, attr_name = get_parent_and_attribute_name(
114
- remainder.join(Ransack::Constants::UNDERSCORE), join
112
+ remainder.join(Constants::UNDERSCORE), join
115
113
  )
116
114
  end
117
115
  end
@@ -137,31 +135,25 @@ module Ransack
137
135
  buckets = relation.joins_values.group_by do |join|
138
136
  case join
139
137
  when String
140
- Ransack::Constants::STRING_JOIN
138
+ Constants::STRING_JOIN
141
139
  when Hash, Symbol, Array
142
- Ransack::Constants::ASSOCIATION_JOIN
140
+ Constants::ASSOCIATION_JOIN
143
141
  when ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
144
- Ransack::Constants::STASHED_JOIN
142
+ Constants::STASHED_JOIN
145
143
  when Arel::Nodes::Join
146
- Ransack::Constants::JOIN_NODE
144
+ Constants::JOIN_NODE
147
145
  else
148
146
  raise 'unknown class: %s' % join.class.name
149
147
  end
150
148
  end
151
149
 
152
- association_joins =
153
- buckets[Ransack::Constants::ASSOCIATION_JOIN] || []
150
+ association_joins = buckets[Constants::ASSOCIATION_JOIN] || []
154
151
 
155
- stashed_association_joins =
156
- buckets[Ransack::Constants::STASHED_JOIN] || []
152
+ stashed_association_joins = buckets[Constants::STASHED_JOIN] || []
157
153
 
158
- join_nodes =
159
- buckets[Ransack::Constants::JOIN_NODE] || []
154
+ join_nodes = buckets[Constants::JOIN_NODE] || []
160
155
 
161
- string_joins =
162
- (buckets[Ransack::Constants::STRING_JOIN] || [])
163
- .map { |x| x.strip }
164
- .uniq
156
+ string_joins = (buckets[Constants::STRING_JOIN] || []).map(&:strip).uniq
165
157
 
166
158
  join_list = relation.send :custom_join_sql, (string_joins + join_nodes)
167
159
 
@@ -29,10 +29,8 @@ module Ransack
29
29
  .reorder(viz.accept(search.sorts))
30
30
  end
31
31
  if opts[:distinct]
32
- relation.select(
33
- Ransack::Constants::DISTINCT + @klass.quoted_table_name +
34
- '.*'.freeze
35
- )
32
+ relation.select(Constants::DISTINCT + @klass.quoted_table_name +
33
+ Constants::DOT_ASTERIX)
36
34
  else
37
35
  relation
38
36
  end
@@ -49,11 +47,11 @@ module Ransack
49
47
  while !found_assoc && remainder.unshift(segments.pop) &&
50
48
  segments.size > 0 do
51
49
  assoc, poly_class = unpolymorphize_association(
52
- segments.join(Ransack::Constants::UNDERSCORE)
50
+ segments.join(Constants::UNDERSCORE)
53
51
  )
54
52
  if found_assoc = get_association(assoc, klass)
55
53
  exists = attribute_method?(
56
- remainder.join(Ransack::Constants::UNDERSCORE),
54
+ remainder.join(Constants::UNDERSCORE),
57
55
  poly_class || found_assoc.klass
58
56
  )
59
57
  end
@@ -116,14 +114,14 @@ module Ransack
116
114
  while remainder.unshift(segments.pop) && segments.size > 0 &&
117
115
  !found_assoc do
118
116
  assoc, klass = unpolymorphize_association(
119
- segments.join(Ransack::Constants::UNDERSCORE)
117
+ segments.join(Constants::UNDERSCORE)
120
118
  )
121
119
  if found_assoc = get_association(assoc, parent)
122
120
  join = build_or_find_association(
123
121
  found_assoc.name, parent, klass
124
122
  )
125
123
  parent, attr_name = get_parent_and_attribute_name(
126
- remainder.join(Ransack::Constants::UNDERSCORE), join
124
+ remainder.join(Constants::UNDERSCORE), join
127
125
  )
128
126
  end
129
127
  end
@@ -150,31 +148,25 @@ module Ransack
150
148
  buckets = relation.joins_values.group_by do |join|
151
149
  case join
152
150
  when String
153
- Ransack::Constants::STRING_JOIN
151
+ Constants::STRING_JOIN
154
152
  when Hash, Symbol, Array
155
- Ransack::Constants::ASSOCIATION_JOIN
153
+ Constants::ASSOCIATION_JOIN
156
154
  when ::ActiveRecord::Associations::JoinDependency::JoinAssociation
157
- Ransack::Constants::STASHED_JOIN
155
+ Constants::STASHED_JOIN
158
156
  when Arel::Nodes::Join
159
- Ransack::Constants::JOIN_NODE
157
+ Constants::JOIN_NODE
160
158
  else
161
159
  raise 'unknown class: %s' % join.class.name
162
160
  end
163
161
  end
164
162
 
165
- association_joins =
166
- buckets[Ransack::Constants::ASSOCIATION_JOIN] || []
163
+ association_joins = buckets[Constants::ASSOCIATION_JOIN] || []
167
164
 
168
- stashed_association_joins =
169
- buckets[Ransack::Constants::STASHED_JOIN] || []
165
+ stashed_association_joins = buckets[Constants::STASHED_JOIN] || []
170
166
 
171
- join_nodes =
172
- buckets[Ransack::Constants::JOIN_NODE] || []
167
+ join_nodes = buckets[Constants::JOIN_NODE] || []
173
168
 
174
- string_joins =
175
- (buckets[Ransack::Constants::STRING_JOIN] || [])
176
- .map { |x| x.strip }
177
- .uniq
169
+ string_joins = (buckets[Constants::STRING_JOIN] || []).map(&:strip).uniq
178
170
 
179
171
  join_list = relation.send :custom_join_ast,
180
172
  relation.table.from(relation.table), string_joins
@@ -22,12 +22,13 @@ module Ransack
22
22
 
23
23
  def type_for(attr)
24
24
  return nil unless attr && attr.valid?
25
- name = attr.arel_attribute.name.to_s
26
- table = attr.arel_attribute.relation.table_name
27
-
28
- schema_cache = @engine.connection.schema_cache
29
- raise "No table named #{table} exists" unless schema_cache.table_exists?(table)
30
- schema_cache.columns_hash(table)[name].type
25
+ name = attr.arel_attribute.name.to_s
26
+ table = attr.arel_attribute.relation.table_name
27
+ connection = attr.klass.connection
28
+ unless connection.table_exists?(table)
29
+ raise "No table named #{table} exists"
30
+ end
31
+ connection.schema_cache.columns_hash(table)[name].type
31
32
  end
32
33
 
33
34
  def evaluate(search, opts = {})
@@ -49,11 +50,11 @@ module Ransack
49
50
  while !found_assoc && remainder.unshift(segments.pop) &&
50
51
  segments.size > 0 do
51
52
  assoc, poly_class = unpolymorphize_association(
52
- segments.join(Ransack::Constants::UNDERSCORE)
53
+ segments.join(Constants::UNDERSCORE)
53
54
  )
54
55
  if found_assoc = get_association(assoc, klass)
55
56
  exists = attribute_method?(
56
- remainder.join(Ransack::Constants::UNDERSCORE),
57
+ remainder.join(Constants::UNDERSCORE),
57
58
  poly_class || found_assoc.klass
58
59
  )
59
60
  end
@@ -78,7 +79,7 @@ module Ransack
78
79
  end
79
80
  end
80
81
 
81
- if ::ActiveRecord::VERSION::STRING >= '4.1'.freeze
82
+ if ::ActiveRecord::VERSION::STRING >= Constants::RAILS_4_1
82
83
 
83
84
  def join_associations
84
85
  raise NotImplementedError,
@@ -93,7 +94,12 @@ module Ransack
93
94
  # JoinDependency to track table aliases.
94
95
  #
95
96
  def join_sources
96
- base = Arel::SelectManager.new(@object.engine, @object.table)
97
+ base =
98
+ if ::ActiveRecord::VERSION::MAJOR >= 5
99
+ Arel::SelectManager.new(@object.engine)
100
+ else
101
+ Arel::SelectManager.new(@object.engine, @object.table)
102
+ end
97
103
  joins = @join_dependency.join_constraints(@object.joins_values)
98
104
  joins.each do |aliased_join|
99
105
  base.from(aliased_join)
@@ -133,20 +139,20 @@ module Ransack
133
139
 
134
140
  if ransackable_attribute?(str, klassify(parent))
135
141
  attr_name = str
136
- elsif (segments = str.split(Ransack::Constants::UNDERSCORE)).size > 1
142
+ elsif (segments = str.split(Constants::UNDERSCORE)).size > 1
137
143
  remainder = []
138
144
  found_assoc = nil
139
145
  while remainder.unshift(segments.pop) && segments.size > 0 &&
140
146
  !found_assoc do
141
147
  assoc, klass = unpolymorphize_association(
142
- segments.join(Ransack::Constants::UNDERSCORE)
148
+ segments.join(Constants::UNDERSCORE)
143
149
  )
144
150
  if found_assoc = get_association(assoc, parent)
145
151
  join = build_or_find_association(
146
152
  found_assoc.name, parent, klass
147
153
  )
148
154
  parent, attr_name = get_parent_and_attribute_name(
149
- remainder.join(Ransack::Constants::UNDERSCORE), join
155
+ remainder.join(Constants::UNDERSCORE), join
150
156
  )
151
157
  end
152
158
  end
@@ -175,34 +181,33 @@ module Ransack
175
181
  buckets = relation.joins_values.group_by do |join|
176
182
  case join
177
183
  when String
178
- Ransack::Constants::STRING_JOIN
184
+ Constants::STRING_JOIN
179
185
  when Hash, Symbol, Array
180
- Ransack::Constants::ASSOCIATION_JOIN
186
+ Constants::ASSOCIATION_JOIN
181
187
  when JoinDependency, JoinDependency::JoinAssociation
182
- Ransack::Constants::STASHED_JOIN
188
+ Constants::STASHED_JOIN
183
189
  when Arel::Nodes::Join
184
- Ransack::Constants::JOIN_NODE
190
+ Constants::JOIN_NODE
185
191
  else
186
192
  raise 'unknown class: %s' % join.class.name
187
193
  end
188
194
  end
189
195
 
190
- association_joins =
191
- buckets[Ransack::Constants::ASSOCIATION_JOIN] || []
196
+ association_joins = buckets[Constants::ASSOCIATION_JOIN] || []
192
197
 
193
- stashed_association_joins =
194
- buckets[Ransack::Constants::STASHED_JOIN] || []
198
+ stashed_association_joins = buckets[Constants::STASHED_JOIN] || []
195
199
 
196
- join_nodes =
197
- buckets[Ransack::Constants::JOIN_NODE] || []
200
+ join_nodes = buckets[Constants::JOIN_NODE] || []
198
201
 
199
- string_joins =
200
- (buckets[Ransack::Constants::STRING_JOIN] || [])
201
- .map { |x| x.strip }
202
- .uniq
202
+ string_joins = (buckets[Constants::STRING_JOIN] || []).map(&:strip).uniq
203
203
 
204
- join_list = relation.send :custom_join_ast,
205
- relation.table.from(relation.table), string_joins
204
+ join_list =
205
+ if ::ActiveRecord::VERSION::MAJOR >= 5
206
+ relation.send :custom_join_ast, relation.table.from, string_joins
207
+ else
208
+ relation.send :custom_join_ast,
209
+ relation.table.from(relation.table), string_joins
210
+ end
206
211
 
207
212
  join_dependency = JoinDependency.new(
208
213
  relation.klass, association_joins, join_list
@@ -212,14 +217,14 @@ module Ransack
212
217
  join_dependency.alias_tracker.aliases[join.left.name.downcase] = 1
213
218
  end
214
219
 
215
- if ::ActiveRecord::VERSION::STRING >= '4.1'.freeze
220
+ if ::ActiveRecord::VERSION::STRING >= Constants::RAILS_4_1
216
221
  join_dependency
217
222
  else
218
223
  join_dependency.graft(*stashed_association_joins)
219
224
  end
220
225
  end
221
226
 
222
- if ::ActiveRecord::VERSION::STRING >= '4.1'.freeze
227
+ if ::ActiveRecord::VERSION::STRING >= Constants::RAILS_4_1
223
228
 
224
229
  def build_or_find_association(name, parent = @base, klass = nil)
225
230
  found_association = @join_dependency.join_root.children
@@ -0,0 +1,113 @@
1
+ module Ransack
2
+ module Constants
3
+ DISTINCT = 'DISTINCT '.freeze
4
+
5
+ DERIVED_PREDICATES = [
6
+ [CONT, {
7
+ :arel_predicate => 'matches'.freeze,
8
+ :formatter => proc { |v| "%#{escape_wildcards(v)}%" }
9
+ }
10
+ ],
11
+ ['not_cont'.freeze, {
12
+ :arel_predicate => 'does_not_match'.freeze,
13
+ :formatter => proc { |v| "%#{escape_wildcards(v)}%" }
14
+ }
15
+ ],
16
+ ['start'.freeze, {
17
+ :arel_predicate => 'matches'.freeze,
18
+ :formatter => proc { |v| "#{escape_wildcards(v)}%" }
19
+ }
20
+ ],
21
+ ['not_start'.freeze, {
22
+ :arel_predicate => 'does_not_match'.freeze,
23
+ :formatter => proc { |v| "#{escape_wildcards(v)}%" }
24
+ }
25
+ ],
26
+ ['end'.freeze, {
27
+ :arel_predicate => 'matches'.freeze,
28
+ :formatter => proc { |v| "%#{escape_wildcards(v)}" }
29
+ }
30
+ ],
31
+ ['not_end'.freeze, {
32
+ :arel_predicate => 'does_not_match'.freeze,
33
+ :formatter => proc { |v| "%#{escape_wildcards(v)}" }
34
+ }
35
+ ],
36
+ ['true'.freeze, {
37
+ :arel_predicate => proc { |v| v ? EQ : NOT_EQ },
38
+ :compounds => false,
39
+ :type => :boolean,
40
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
41
+ :formatter => proc { |v| true }
42
+ }
43
+ ],
44
+ ['not_true'.freeze, {
45
+ :arel_predicate => proc { |v| v ? NOT_EQ : EQ },
46
+ :compounds => false,
47
+ :type => :boolean,
48
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
49
+ :formatter => proc { |v| true }
50
+ }
51
+ ],
52
+ ['false'.freeze, {
53
+ :arel_predicate => proc { |v| v ? EQ : NOT_EQ },
54
+ :compounds => false,
55
+ :type => :boolean,
56
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
57
+ :formatter => proc { |v| false }
58
+ }
59
+ ],
60
+ ['not_false'.freeze, {
61
+ :arel_predicate => proc { |v| v ? NOT_EQ : EQ },
62
+ :compounds => false,
63
+ :type => :boolean,
64
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
65
+ :formatter => proc { |v| false }
66
+ }
67
+ ],
68
+ ['present'.freeze, {
69
+ :arel_predicate => proc { |v| v ? NOT_EQ_ALL : EQ_ANY },
70
+ :compounds => false,
71
+ :type => :boolean,
72
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
73
+ :formatter => proc { |v| [nil, EMPTY] }
74
+ }
75
+ ],
76
+ ['blank'.freeze, {
77
+ :arel_predicate => proc { |v| v ? EQ_ANY : NOT_EQ_ALL },
78
+ :compounds => false,
79
+ :type => :boolean,
80
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
81
+ :formatter => proc { |v| [nil, EMPTY] }
82
+ }
83
+ ],
84
+ ['null'.freeze, {
85
+ :arel_predicate => proc { |v| v ? EQ : NOT_EQ },
86
+ :compounds => false,
87
+ :type => :boolean,
88
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v)},
89
+ :formatter => proc { |v| nil }
90
+ }
91
+ ],
92
+ ['not_null'.freeze, {
93
+ :arel_predicate => proc { |v| v ? NOT_EQ : EQ },
94
+ :compounds => false,
95
+ :type => :boolean,
96
+ :validator => proc { |v| BOOLEAN_VALUES.include?(v) },
97
+ :formatter => proc { |v| nil } }
98
+ ]
99
+ ].freeze
100
+
101
+ module_function
102
+ # replace % \ to \% \\
103
+ def escape_wildcards(unescaped)
104
+ case ActiveRecord::Base.connection.adapter_name
105
+ when "Mysql2".freeze, "PostgreSQL".freeze
106
+ # Necessary for PostgreSQL and MySQL
107
+ unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1')
108
+ else
109
+ unescaped
110
+ end
111
+ end
112
+ end
113
+ end