ransack 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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