ransack 1.7.0 → 2.4.1

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 (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)