ransack 1.7.0 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/SECURITY.md +12 -0
  4. data/.github/workflows/test.yml +120 -0
  5. data/.gitignore +3 -0
  6. data/CHANGELOG.md +463 -27
  7. data/CONTRIBUTING.md +52 -22
  8. data/Gemfile +24 -24
  9. data/README.md +453 -126
  10. data/Rakefile +6 -25
  11. data/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +24 -0
  12. data/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +79 -0
  13. data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
  14. data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
  15. data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
  16. data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
  17. data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
  18. data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
  19. data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
  20. data/lib/polyamorous/join.rb +70 -0
  21. data/lib/polyamorous/polyamorous.rb +24 -0
  22. data/lib/polyamorous/swapping_reflection_class.rb +11 -0
  23. data/lib/polyamorous/tree_node.rb +7 -0
  24. data/lib/ransack/adapters/active_record/base.rb +27 -2
  25. data/lib/ransack/adapters/active_record/context.rb +213 -139
  26. data/lib/ransack/adapters/active_record/ransack/constants.rb +70 -55
  27. data/lib/ransack/adapters/active_record/ransack/context.rb +10 -18
  28. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +42 -32
  29. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -5
  30. data/lib/ransack/adapters/active_record/ransack/visitor.rb +23 -0
  31. data/lib/ransack/adapters/active_record.rb +11 -10
  32. data/lib/ransack/adapters.rb +45 -23
  33. data/lib/ransack/configuration.rb +107 -4
  34. data/lib/ransack/constants.rb +13 -26
  35. data/lib/ransack/context.rb +45 -33
  36. data/lib/ransack/helpers/form_builder.rb +21 -12
  37. data/lib/ransack/helpers/form_helper.rb +75 -70
  38. data/lib/ransack/locale/ar.yml +70 -0
  39. data/lib/ransack/locale/az.yml +70 -0
  40. data/lib/ransack/locale/bg.yml +70 -0
  41. data/lib/ransack/locale/ca.yml +70 -0
  42. data/lib/ransack/locale/da.yml +70 -0
  43. data/lib/ransack/locale/el.yml +70 -0
  44. data/lib/ransack/locale/es.yml +22 -22
  45. data/lib/ransack/locale/fa.yml +70 -0
  46. data/lib/ransack/locale/fi.yml +71 -0
  47. data/lib/ransack/locale/id.yml +70 -0
  48. data/lib/ransack/locale/it.yml +70 -0
  49. data/lib/ransack/locale/ja.yml +70 -0
  50. data/lib/ransack/locale/nl.yml +4 -4
  51. data/lib/ransack/locale/pt-BR.yml +70 -0
  52. data/lib/ransack/locale/ru.yml +70 -0
  53. data/lib/ransack/locale/sk.yml +70 -0
  54. data/lib/ransack/locale/tr.yml +70 -0
  55. data/lib/ransack/locale/{zh.yml → zh-CN.yml} +13 -13
  56. data/lib/ransack/locale/zh-TW.yml +70 -0
  57. data/lib/ransack/nodes/attribute.rb +5 -2
  58. data/lib/ransack/nodes/bindable.rb +18 -6
  59. data/lib/ransack/nodes/condition.rb +85 -28
  60. data/lib/ransack/nodes/grouping.rb +17 -11
  61. data/lib/ransack/nodes/sort.rb +9 -5
  62. data/lib/ransack/nodes/value.rb +74 -68
  63. data/lib/ransack/nodes.rb +1 -1
  64. data/lib/ransack/predicate.rb +17 -20
  65. data/lib/ransack/search.rb +17 -8
  66. data/lib/ransack/translate.rb +115 -115
  67. data/lib/ransack/version.rb +1 -1
  68. data/lib/ransack/visitor.rb +1 -12
  69. data/lib/ransack.rb +9 -9
  70. data/logo/ransack-h.png +0 -0
  71. data/logo/ransack-h.svg +34 -0
  72. data/logo/ransack-v.png +0 -0
  73. data/logo/ransack-v.svg +34 -0
  74. data/logo/ransack.png +0 -0
  75. data/logo/ransack.svg +21 -0
  76. data/ransack.gemspec +7 -24
  77. data/spec/console.rb +4 -0
  78. data/spec/helpers/polyamorous_helper.rb +19 -0
  79. data/spec/polyamorous/join_association_spec.rb +35 -0
  80. data/spec/polyamorous/join_dependency_spec.rb +97 -0
  81. data/spec/polyamorous/join_spec.rb +19 -0
  82. data/spec/ransack/adapters/active_record/base_spec.rb +370 -75
  83. data/spec/ransack/adapters/active_record/context_spec.rb +72 -34
  84. data/spec/ransack/configuration_spec.rb +97 -14
  85. data/spec/ransack/helpers/form_builder_spec.rb +2 -11
  86. data/spec/ransack/helpers/form_helper_spec.rb +481 -113
  87. data/spec/ransack/nodes/condition_spec.rb +24 -0
  88. data/spec/ransack/nodes/grouping_spec.rb +56 -0
  89. data/spec/ransack/predicate_spec.rb +79 -5
  90. data/spec/ransack/search_spec.rb +207 -81
  91. data/spec/spec_helper.rb +8 -0
  92. data/spec/support/schema.rb +100 -42
  93. metadata +57 -184
  94. data/.travis.yml +0 -69
  95. data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -179
  96. data/lib/ransack/adapters/active_record/3.0/context.rb +0 -201
  97. data/lib/ransack/adapters/active_record/3.1/context.rb +0 -215
  98. data/lib/ransack/adapters/active_record/3.2/context.rb +0 -44
  99. data/lib/ransack/adapters/active_record/compat.rb +0 -14
  100. data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
  101. data/lib/ransack/adapters/mongoid/attributes/attribute.rb +0 -37
  102. data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +0 -17
  103. data/lib/ransack/adapters/mongoid/attributes/predications.rb +0 -141
  104. data/lib/ransack/adapters/mongoid/base.rb +0 -130
  105. data/lib/ransack/adapters/mongoid/context.rb +0 -208
  106. data/lib/ransack/adapters/mongoid/inquiry_hash.rb +0 -23
  107. data/lib/ransack/adapters/mongoid/ransack/constants.rb +0 -88
  108. data/lib/ransack/adapters/mongoid/ransack/context.rb +0 -60
  109. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +0 -27
  110. data/lib/ransack/adapters/mongoid/ransack/translate.rb +0 -13
  111. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +0 -24
  112. data/lib/ransack/adapters/mongoid/table.rb +0 -35
  113. data/lib/ransack/adapters/mongoid.rb +0 -13
  114. data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -276
  115. data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
  116. data/spec/mongoid/configuration_spec.rb +0 -102
  117. data/spec/mongoid/dependencies_spec.rb +0 -8
  118. data/spec/mongoid/helpers/ransack_helper.rb +0 -11
  119. data/spec/mongoid/nodes/condition_spec.rb +0 -34
  120. data/spec/mongoid/nodes/grouping_spec.rb +0 -13
  121. data/spec/mongoid/predicate_spec.rb +0 -155
  122. data/spec/mongoid/search_spec.rb +0 -446
  123. data/spec/mongoid/support/mongoid.yml +0 -6
  124. data/spec/mongoid/support/schema.rb +0 -128
  125. data/spec/mongoid/translate_spec.rb +0 -14
  126. data/spec/mongoid_spec_helper.rb +0 -59
  127. data/spec/ransack/dependencies_spec.rb +0 -12
@@ -4,6 +4,21 @@ module Ransack
4
4
  module Nodes
5
5
  describe Condition do
6
6
 
7
+ context 'with an alias' do
8
+ subject {
9
+ Condition.extract(
10
+ Context.for(Person), 'term_start', Person.first(2).map(&:name)
11
+ )
12
+ }
13
+
14
+ specify { expect(subject.combinator).to eq 'or' }
15
+ specify { expect(subject.predicate.name).to eq 'start' }
16
+
17
+ it 'converts the alias to the correct attributes' do
18
+ expect(subject.attributes.map(&:name)).to eq(['name', 'email'])
19
+ end
20
+ end
21
+
7
22
  context 'with multiple values and an _any predicate' do
8
23
  subject {
9
24
  Condition.extract(
@@ -14,6 +29,15 @@ module Ransack
14
29
  specify { expect(subject.values.size).to eq(2) }
15
30
  end
16
31
 
32
+ describe '#negative?' do
33
+ let(:context) { Context.for(Person) }
34
+ let(:eq) { Condition.extract(context, 'name_eq', 'A') }
35
+ let(:not_eq) { Condition.extract(context, 'name_not_eq', 'A') }
36
+
37
+ specify { expect(not_eq.negative?).to be true }
38
+ specify { expect(eq.negative?).to be false }
39
+ end
40
+
17
41
  context 'with an invalid predicate' do
18
42
  subject {
19
43
  Condition.extract(
@@ -50,6 +50,62 @@ module Ransack
50
50
  end
51
51
  end
52
52
 
53
+ describe '#conditions=' do
54
+ context 'when conditions are identical' do
55
+ let(:conditions) do
56
+ {
57
+ '0' => {
58
+ 'a' => { '0'=> { 'name' => 'name', 'ransacker_args' => '' } },
59
+ 'p' => 'cont',
60
+ 'v' => { '0' => { 'value' => 'John' } }
61
+ },
62
+ '1' => {
63
+ 'a' => { '0' => { 'name' => 'name', 'ransacker_args' => '' } },
64
+ 'p' => 'cont',
65
+ 'v' => { '0' => { 'value' => 'John' } }
66
+ }
67
+ }
68
+ end
69
+ before { subject.conditions = conditions }
70
+
71
+ it 'expect duplicates to be removed' do
72
+ expect(subject.conditions.count).to eq 1
73
+ end
74
+ end
75
+
76
+ context 'when conditions differ only by ransacker_args' do
77
+ let(:conditions) do
78
+ {
79
+ '0' => {
80
+ 'a' => {
81
+ '0' => {
82
+ 'name' => 'with_arguments',
83
+ 'ransacker_args' => [1,2]
84
+ }
85
+ },
86
+ 'p' => 'eq',
87
+ 'v' => { '0' => { 'value' => '10' } }
88
+ },
89
+ '1' => {
90
+ 'a' => {
91
+ '0' => {
92
+ 'name' => 'with_arguments',
93
+ 'ransacker_args' => [3,4]
94
+ }
95
+ },
96
+ 'p' => 'eq',
97
+ 'v' => { '0' => { 'value' => '10' } }
98
+ }
99
+ }
100
+ end
101
+ before { subject.conditions = conditions }
102
+
103
+ it 'expect them to be parsed as different and not as duplicates' do
104
+ expect(subject.conditions.count).to eq 2
105
+ end
106
+ end
107
+ end
108
+
53
109
  end
54
110
  end
55
111
  end
@@ -16,7 +16,7 @@ module Ransack
16
16
  expect { subject.result }.to_not raise_error
17
17
  end
18
18
 
19
- it "escapes '%', '.' and '\\\\' in value" do
19
+ it "escapes '%', '.', '_' and '\\\\' in value" do
20
20
  subject.send(:"#{method}=", '%._\\')
21
21
  expect(subject.result.to_sql).to match(regexp)
22
22
  end
@@ -124,9 +124,9 @@ module Ransack
124
124
  describe 'cont' do
125
125
  it_has_behavior 'wildcard escaping', :name_cont,
126
126
  (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
127
- /"people"."name" ILIKE '%\\%\\._\\\\%'/
127
+ /"people"."name" ILIKE '%\\%\\.\\_\\\\%'/
128
128
  elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
129
- /`people`.`name` LIKE '%\\\\%\\\\._\\\\\\\\%'/
129
+ /`people`.`name` LIKE '%\\\\%.\\\\_\\\\\\\\%'/
130
130
  else
131
131
  /"people"."name" LIKE '%%._\\%'/
132
132
  end) do
@@ -143,9 +143,9 @@ module Ransack
143
143
  describe 'not_cont' do
144
144
  it_has_behavior 'wildcard escaping', :name_not_cont,
145
145
  (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
146
- /"people"."name" NOT ILIKE '%\\%\\._\\\\%'/
146
+ /"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/
147
147
  elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
148
- /`people`.`name` NOT LIKE '%\\\\%\\\\._\\\\\\\\%'/
148
+ /`people`.`name` NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/
149
149
  else
150
150
  /"people"."name" NOT LIKE '%%._\\%'/
151
151
  end) do
@@ -159,6 +159,44 @@ module Ransack
159
159
  end
160
160
  end
161
161
 
162
+ describe 'i_cont' do
163
+ it_has_behavior 'wildcard escaping', :name_i_cont,
164
+ (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
165
+ /"people"."name" ILIKE '%\\%\\.\\_\\\\%'/
166
+ elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
167
+ /LOWER\(`people`.`name`\) LIKE '%\\\\%.\\\\_\\\\\\\\%'/
168
+ else
169
+ /LOWER\("people"."name"\) LIKE '%%._\\%'/
170
+ end) do
171
+ subject { @s }
172
+ end
173
+
174
+ it 'generates a LIKE query with LOWER(column) and value surrounded by %' do
175
+ @s.name_i_cont = 'Ric'
176
+ field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
177
+ expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? I?LIKE '%ric%'/
178
+ end
179
+ end
180
+
181
+ describe 'not_i_cont' do
182
+ it_has_behavior 'wildcard escaping', :name_not_i_cont,
183
+ (if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
184
+ /"people"."name" NOT ILIKE '%\\%\\.\\_\\\\%'/
185
+ elsif ActiveRecord::Base.connection.adapter_name == "Mysql2"
186
+ /LOWER\(`people`.`name`\) NOT LIKE '%\\\\%.\\\\_\\\\\\\\%'/
187
+ else
188
+ /LOWER\("people"."name"\) NOT LIKE '%%._\\%'/
189
+ end) do
190
+ subject { @s }
191
+ end
192
+
193
+ it 'generates a NOT LIKE query with LOWER(column) and value surrounded by %' do
194
+ @s.name_not_i_cont = 'Ric'
195
+ field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
196
+ expect(@s.result.to_sql).to match /[LOWER\(]?#{field}\)? NOT I?LIKE '%ric%'/
197
+ end
198
+ end
199
+
162
200
  describe 'start' do
163
201
  it 'generates a LIKE query with value followed by %' do
164
202
  @s.name_start = 'Er'
@@ -329,6 +367,28 @@ module Ransack
329
367
  field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
330
368
  expect(@s.result.to_sql).to match /#{field} IS NULL/
331
369
  end
370
+
371
+ describe 'with association qeury' do
372
+ it 'generates a value IS NOT NULL query' do
373
+ @s.comments_id_not_null = true
374
+ sql = @s.result.to_sql
375
+ parent_field = "#{quote_table_name("people")}.#{quote_column_name("id")}"
376
+ expect(sql).to match /#{parent_field} IN/
377
+ field = "#{quote_table_name("comments")}.#{quote_column_name("id")}"
378
+ expect(sql).to match /#{field} IS NOT NULL/
379
+ expect(sql).not_to match /AND NOT/
380
+ end
381
+
382
+ it 'generates a value IS NULL query when assigned false' do
383
+ @s.comments_id_not_null = false
384
+ sql = @s.result.to_sql
385
+ parent_field = "#{quote_table_name("people")}.#{quote_column_name("id")}"
386
+ expect(sql).to match /#{parent_field} NOT IN/
387
+ field = "#{quote_table_name("comments")}.#{quote_column_name("id")}"
388
+ expect(sql).to match /#{field} IS NULL/
389
+ expect(sql).to match /AND NOT/
390
+ end
391
+ end
332
392
  end
333
393
 
334
394
  describe 'present' do
@@ -359,6 +419,20 @@ module Ransack
359
419
  end
360
420
  end
361
421
 
422
+ context "defining custom predicates" do
423
+ describe "with 'not_in' arel predicate" do
424
+ before do
425
+ Ransack.configure {|c| c.add_predicate "not_in_csv", arel_predicate: "not_in", formatter: proc { |v| v.split(",") } }
426
+ end
427
+
428
+ it 'generates a value IS NOT NULL query' do
429
+ @s.name_not_in_csv = ["a", "b"]
430
+ field = "#{quote_table_name("people")}.#{quote_column_name("name")}"
431
+ expect(@s.result.to_sql).to match /#{field} NOT IN \('a', 'b'\)/
432
+ end
433
+ end
434
+ end
435
+
362
436
  private
363
437
 
364
438
  def test_boolean_equality_for(boolean_value)