ransack 1.7.0 → 2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/test.yml +120 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +463 -27
- data/CONTRIBUTING.md +52 -22
- data/Gemfile +24 -24
- data/README.md +453 -126
- data/Rakefile +6 -25
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +24 -0
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +79 -0
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/join.rb +70 -0
- data/lib/polyamorous/polyamorous.rb +24 -0
- data/lib/polyamorous/swapping_reflection_class.rb +11 -0
- data/lib/polyamorous/tree_node.rb +7 -0
- data/lib/ransack/adapters/active_record/base.rb +27 -2
- data/lib/ransack/adapters/active_record/context.rb +213 -139
- data/lib/ransack/adapters/active_record/ransack/constants.rb +70 -55
- data/lib/ransack/adapters/active_record/ransack/context.rb +10 -18
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +42 -32
- data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -5
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +23 -0
- data/lib/ransack/adapters/active_record.rb +11 -10
- data/lib/ransack/adapters.rb +45 -23
- data/lib/ransack/configuration.rb +107 -4
- data/lib/ransack/constants.rb +13 -26
- data/lib/ransack/context.rb +45 -33
- data/lib/ransack/helpers/form_builder.rb +21 -12
- data/lib/ransack/helpers/form_helper.rb +75 -70
- data/lib/ransack/locale/ar.yml +70 -0
- data/lib/ransack/locale/az.yml +70 -0
- data/lib/ransack/locale/bg.yml +70 -0
- data/lib/ransack/locale/ca.yml +70 -0
- data/lib/ransack/locale/da.yml +70 -0
- data/lib/ransack/locale/el.yml +70 -0
- data/lib/ransack/locale/es.yml +22 -22
- data/lib/ransack/locale/fa.yml +70 -0
- data/lib/ransack/locale/fi.yml +71 -0
- data/lib/ransack/locale/id.yml +70 -0
- data/lib/ransack/locale/it.yml +70 -0
- data/lib/ransack/locale/ja.yml +70 -0
- data/lib/ransack/locale/nl.yml +4 -4
- data/lib/ransack/locale/pt-BR.yml +70 -0
- data/lib/ransack/locale/ru.yml +70 -0
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/tr.yml +70 -0
- data/lib/ransack/locale/{zh.yml → zh-CN.yml} +13 -13
- data/lib/ransack/locale/zh-TW.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +5 -2
- data/lib/ransack/nodes/bindable.rb +18 -6
- data/lib/ransack/nodes/condition.rb +85 -28
- data/lib/ransack/nodes/grouping.rb +17 -11
- data/lib/ransack/nodes/sort.rb +9 -5
- data/lib/ransack/nodes/value.rb +74 -68
- data/lib/ransack/nodes.rb +1 -1
- data/lib/ransack/predicate.rb +17 -20
- data/lib/ransack/search.rb +17 -8
- data/lib/ransack/translate.rb +115 -115
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +1 -12
- data/lib/ransack.rb +9 -9
- data/logo/ransack-h.png +0 -0
- data/logo/ransack-h.svg +34 -0
- data/logo/ransack-v.png +0 -0
- data/logo/ransack-v.svg +34 -0
- data/logo/ransack.png +0 -0
- data/logo/ransack.svg +21 -0
- data/ransack.gemspec +7 -24
- data/spec/console.rb +4 -0
- data/spec/helpers/polyamorous_helper.rb +19 -0
- data/spec/polyamorous/join_association_spec.rb +35 -0
- data/spec/polyamorous/join_dependency_spec.rb +97 -0
- data/spec/polyamorous/join_spec.rb +19 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +370 -75
- data/spec/ransack/adapters/active_record/context_spec.rb +72 -34
- data/spec/ransack/configuration_spec.rb +97 -14
- data/spec/ransack/helpers/form_builder_spec.rb +2 -11
- data/spec/ransack/helpers/form_helper_spec.rb +481 -113
- data/spec/ransack/nodes/condition_spec.rb +24 -0
- data/spec/ransack/nodes/grouping_spec.rb +56 -0
- data/spec/ransack/predicate_spec.rb +79 -5
- data/spec/ransack/search_spec.rb +207 -81
- data/spec/spec_helper.rb +8 -0
- data/spec/support/schema.rb +100 -42
- metadata +57 -184
- data/.travis.yml +0 -69
- data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -179
- data/lib/ransack/adapters/active_record/3.0/context.rb +0 -201
- data/lib/ransack/adapters/active_record/3.1/context.rb +0 -215
- data/lib/ransack/adapters/active_record/3.2/context.rb +0 -44
- data/lib/ransack/adapters/active_record/compat.rb +0 -14
- data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
- data/lib/ransack/adapters/mongoid/attributes/attribute.rb +0 -37
- data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +0 -17
- data/lib/ransack/adapters/mongoid/attributes/predications.rb +0 -141
- data/lib/ransack/adapters/mongoid/base.rb +0 -130
- data/lib/ransack/adapters/mongoid/context.rb +0 -208
- data/lib/ransack/adapters/mongoid/inquiry_hash.rb +0 -23
- data/lib/ransack/adapters/mongoid/ransack/constants.rb +0 -88
- data/lib/ransack/adapters/mongoid/ransack/context.rb +0 -60
- data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +0 -27
- data/lib/ransack/adapters/mongoid/ransack/translate.rb +0 -13
- data/lib/ransack/adapters/mongoid/ransack/visitor.rb +0 -24
- data/lib/ransack/adapters/mongoid/table.rb +0 -35
- data/lib/ransack/adapters/mongoid.rb +0 -13
- data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -276
- data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
- data/spec/mongoid/configuration_spec.rb +0 -102
- data/spec/mongoid/dependencies_spec.rb +0 -8
- data/spec/mongoid/helpers/ransack_helper.rb +0 -11
- data/spec/mongoid/nodes/condition_spec.rb +0 -34
- data/spec/mongoid/nodes/grouping_spec.rb +0 -13
- data/spec/mongoid/predicate_spec.rb +0 -155
- data/spec/mongoid/search_spec.rb +0 -446
- data/spec/mongoid/support/mongoid.yml +0 -6
- data/spec/mongoid/support/schema.rb +0 -128
- data/spec/mongoid/translate_spec.rb +0 -14
- data/spec/mongoid_spec_helper.rb +0 -59
- data/spec/ransack/dependencies_spec.rb +0 -12
data/spec/ransack/search_spec.rb
CHANGED
@@ -20,6 +20,12 @@ module Ransack
|
|
20
20
|
Search.new(Person, name_eq: 'foobar')
|
21
21
|
end
|
22
22
|
|
23
|
+
it 'strip leading & trailing whitespace before building' do
|
24
|
+
expect_any_instance_of(Search).to receive(:build)
|
25
|
+
.with({ 'name_eq' => 'foobar' })
|
26
|
+
Search.new(Person, name_eq: ' foobar ')
|
27
|
+
end
|
28
|
+
|
23
29
|
it 'removes empty suffixed conditions before building' do
|
24
30
|
expect_any_instance_of(Search).to receive(:build).with({})
|
25
31
|
Search.new(Person, name_eq_any: [''])
|
@@ -43,16 +49,16 @@ module Ransack
|
|
43
49
|
|
44
50
|
it 'accepts a context option' do
|
45
51
|
shared_context = Context.for(Person)
|
46
|
-
|
47
|
-
|
48
|
-
expect(
|
52
|
+
s1 = Search.new(Person, { name_eq: 'A' }, context: shared_context)
|
53
|
+
s2 = Search.new(Person, { name_eq: 'B' }, context: shared_context)
|
54
|
+
expect(s1.context).to be s2.context
|
49
55
|
end
|
50
56
|
end
|
51
57
|
|
52
58
|
describe '#build' do
|
53
59
|
it 'creates conditions for top-level attributes' do
|
54
|
-
|
55
|
-
condition =
|
60
|
+
s = Search.new(Person, name_eq: 'Ernie')
|
61
|
+
condition = s.base[:name_eq]
|
56
62
|
expect(condition).to be_a Nodes::Condition
|
57
63
|
expect(condition.predicate.name).to eq 'eq'
|
58
64
|
expect(condition.attributes.first.name).to eq 'name'
|
@@ -60,8 +66,8 @@ module Ransack
|
|
60
66
|
end
|
61
67
|
|
62
68
|
it 'creates conditions for association attributes' do
|
63
|
-
|
64
|
-
condition =
|
69
|
+
s = Search.new(Person, children_name_eq: 'Ernie')
|
70
|
+
condition = s.base[:children_name_eq]
|
65
71
|
expect(condition).to be_a Nodes::Condition
|
66
72
|
expect(condition.predicate.name).to eq 'eq'
|
67
73
|
expect(condition.attributes.first.name).to eq 'children_name'
|
@@ -69,8 +75,8 @@ module Ransack
|
|
69
75
|
end
|
70
76
|
|
71
77
|
it 'creates conditions for polymorphic belongs_to association attributes' do
|
72
|
-
|
73
|
-
condition =
|
78
|
+
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie')
|
79
|
+
condition = s.base[:notable_of_Person_type_name_eq]
|
74
80
|
expect(condition).to be_a Nodes::Condition
|
75
81
|
expect(condition.predicate.name).to eq 'eq'
|
76
82
|
expect(condition.attributes.first.name)
|
@@ -80,9 +86,9 @@ module Ransack
|
|
80
86
|
|
81
87
|
it 'creates conditions for multiple polymorphic belongs_to association
|
82
88
|
attributes' do
|
83
|
-
|
89
|
+
s = Search.new(Note,
|
84
90
|
notable_of_Person_type_name_or_notable_of_Article_type_title_eq: 'Ernie')
|
85
|
-
condition =
|
91
|
+
condition = s.
|
86
92
|
base[:notable_of_Person_type_name_or_notable_of_Article_type_title_eq]
|
87
93
|
expect(condition).to be_a Nodes::Condition
|
88
94
|
expect(condition.predicate.name).to eq 'eq'
|
@@ -93,15 +99,62 @@ module Ransack
|
|
93
99
|
expect(condition.value).to eq 'Ernie'
|
94
100
|
end
|
95
101
|
|
102
|
+
it 'creates conditions for aliased attributes',
|
103
|
+
if: Ransack::SUPPORTS_ATTRIBUTE_ALIAS do
|
104
|
+
s = Search.new(Person, full_name_eq: 'Ernie')
|
105
|
+
condition = s.base[:full_name_eq]
|
106
|
+
expect(condition).to be_a Nodes::Condition
|
107
|
+
expect(condition.predicate.name).to eq 'eq'
|
108
|
+
expect(condition.attributes.first.name).to eq 'full_name'
|
109
|
+
expect(condition.value).to eq 'Ernie'
|
110
|
+
end
|
111
|
+
|
96
112
|
it 'preserves default scope and conditions for associations' do
|
97
|
-
|
98
|
-
expect(
|
99
|
-
expect(
|
113
|
+
s = Search.new(Person, published_articles_title_eq: 'Test')
|
114
|
+
expect(s.result.to_sql).to include 'default_scope'
|
115
|
+
expect(s.result.to_sql).to include 'published'
|
116
|
+
end
|
117
|
+
|
118
|
+
# The failure/oversight in Ransack::Nodes::Condition#arel_predicate or deeper is beyond my understanding of the structures
|
119
|
+
it 'preserves (inverts) default scope and conditions for negative subqueries' do
|
120
|
+
# the positive case (published_articles_title_eq) is
|
121
|
+
# SELECT "people".* FROM "people"
|
122
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
123
|
+
# AND "articles"."published" = 't'
|
124
|
+
# AND ('default_scope' = 'default_scope')
|
125
|
+
# WHERE "articles"."title" = 'Test' ORDER BY "people"."id" DESC
|
126
|
+
#
|
127
|
+
# negative case was
|
128
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
129
|
+
# SELECT "articles"."person_id" FROM "articles"
|
130
|
+
# WHERE "articles"."person_id" = "people"."id"
|
131
|
+
# AND NOT ("articles"."title" != 'Test')
|
132
|
+
# ) ORDER BY "people"."id" DESC
|
133
|
+
#
|
134
|
+
# Should have been like
|
135
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
136
|
+
# SELECT "articles"."person_id" FROM "articles"
|
137
|
+
# WHERE "articles"."person_id" = "people"."id"
|
138
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
139
|
+
# ) ORDER BY "people"."id" DESC
|
140
|
+
#
|
141
|
+
# With tenanting (eg default_scope with column reference), NOT IN should be like
|
142
|
+
# SELECT "people".* FROM "people" WHERE "people"."tenant_id" = 'tenant_id' AND "people"."id" NOT IN (
|
143
|
+
# SELECT "articles"."person_id" FROM "articles"
|
144
|
+
# WHERE "articles"."person_id" = "people"."id"
|
145
|
+
# AND "articles"."tenant_id" = 'tenant_id'
|
146
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
147
|
+
# ) ORDER BY "people"."id" DESC
|
148
|
+
|
149
|
+
pending("spec should pass, but I do not know how/where to fix lib code")
|
150
|
+
s = Search.new(Person, published_articles_title_not_eq: 'Test')
|
151
|
+
expect(s.result.to_sql).to include 'default_scope'
|
152
|
+
expect(s.result.to_sql).to include 'published'
|
100
153
|
end
|
101
154
|
|
102
155
|
it 'discards empty conditions' do
|
103
|
-
|
104
|
-
condition =
|
156
|
+
s = Search.new(Person, children_name_eq: '')
|
157
|
+
condition = s.base[:children_name_eq]
|
105
158
|
expect(condition).to be_nil
|
106
159
|
end
|
107
160
|
|
@@ -111,13 +164,13 @@ module Ransack
|
|
111
164
|
end
|
112
165
|
|
113
166
|
it 'accepts arrays of groupings' do
|
114
|
-
|
167
|
+
s = Search.new(Person,
|
115
168
|
g: [
|
116
169
|
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
117
170
|
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' },
|
118
171
|
]
|
119
172
|
)
|
120
|
-
ors =
|
173
|
+
ors = s.groupings
|
121
174
|
expect(ors.size).to eq(2)
|
122
175
|
or1, or2 = ors
|
123
176
|
expect(or1).to be_a Nodes::Grouping
|
@@ -126,14 +179,14 @@ module Ransack
|
|
126
179
|
expect(or2.combinator).to eq 'or'
|
127
180
|
end
|
128
181
|
|
129
|
-
it 'accepts
|
130
|
-
|
182
|
+
it 'accepts attributes hashes for groupings' do
|
183
|
+
s = Search.new(Person,
|
131
184
|
g: {
|
132
185
|
'0' => { m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
133
186
|
'1' => { m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' },
|
134
187
|
}
|
135
188
|
)
|
136
|
-
ors =
|
189
|
+
ors = s.groupings
|
137
190
|
expect(ors.size).to eq(2)
|
138
191
|
or1, or2 = ors
|
139
192
|
expect(or1).to be_a Nodes::Grouping
|
@@ -142,8 +195,8 @@ module Ransack
|
|
142
195
|
expect(or2.combinator).to eq 'or'
|
143
196
|
end
|
144
197
|
|
145
|
-
it 'accepts
|
146
|
-
|
198
|
+
it 'accepts attributes hashes for conditions' do
|
199
|
+
s = Search.new(Person,
|
147
200
|
c: {
|
148
201
|
'0' => { a: ['name'], p: 'eq', v: ['Ernie'] },
|
149
202
|
'1' => {
|
@@ -152,7 +205,7 @@ module Ransack
|
|
152
205
|
}
|
153
206
|
}
|
154
207
|
)
|
155
|
-
conditions =
|
208
|
+
conditions = s.base.conditions
|
156
209
|
expect(conditions.size).to eq(2)
|
157
210
|
expect(conditions.map { |c| c.class })
|
158
211
|
.to eq [Nodes::Condition, Nodes::Condition]
|
@@ -163,8 +216,8 @@ module Ransack
|
|
163
216
|
config.add_predicate 'ary_pred', wants_array: true
|
164
217
|
end
|
165
218
|
|
166
|
-
|
167
|
-
condition =
|
219
|
+
s = Search.new(Person, name_ary_pred: ['Ernie', 'Bert'])
|
220
|
+
condition = s.base[:name_ary_pred]
|
168
221
|
expect(condition).to be_a Nodes::Condition
|
169
222
|
expect(condition.predicate.name).to eq 'ary_pred'
|
170
223
|
expect(condition.attributes.first.name).to eq 'name'
|
@@ -172,14 +225,14 @@ module Ransack
|
|
172
225
|
end
|
173
226
|
|
174
227
|
it 'does not evaluate the query on #inspect' do
|
175
|
-
|
176
|
-
expect(
|
228
|
+
s = Search.new(Person, children_id_in: [1, 2, 3])
|
229
|
+
expect(s.inspect).not_to match /ActiveRecord/
|
177
230
|
end
|
178
231
|
|
179
232
|
context 'with an invalid condition' do
|
180
233
|
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
|
181
234
|
|
182
|
-
context 'when ignore_unknown_conditions is false' do
|
235
|
+
context 'when ignore_unknown_conditions configuration option is false' do
|
183
236
|
before do
|
184
237
|
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
185
238
|
end
|
@@ -187,13 +240,39 @@ module Ransack
|
|
187
240
|
specify { expect { subject }.to raise_error ArgumentError }
|
188
241
|
end
|
189
242
|
|
190
|
-
context 'when ignore_unknown_conditions is true' do
|
243
|
+
context 'when ignore_unknown_conditions configuration option is true' do
|
191
244
|
before do
|
192
245
|
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
193
246
|
end
|
194
247
|
|
195
248
|
specify { expect { subject }.not_to raise_error }
|
196
249
|
end
|
250
|
+
|
251
|
+
subject(:with_ignore_unknown_conditions_false) {
|
252
|
+
Search.new(Person,
|
253
|
+
{ unknown_attr_eq: 'Ernie' },
|
254
|
+
{ ignore_unknown_conditions: false }
|
255
|
+
)
|
256
|
+
}
|
257
|
+
|
258
|
+
subject(:with_ignore_unknown_conditions_true) {
|
259
|
+
Search.new(Person,
|
260
|
+
{ unknown_attr_eq: 'Ernie' },
|
261
|
+
{ ignore_unknown_conditions: true }
|
262
|
+
)
|
263
|
+
}
|
264
|
+
|
265
|
+
context 'when ignore_unknown_conditions search parameter is absent' do
|
266
|
+
specify { expect { subject }.not_to raise_error }
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'when ignore_unknown_conditions search parameter is false' do
|
270
|
+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
|
271
|
+
end
|
272
|
+
|
273
|
+
context 'when ignore_unknown_conditions search parameter is true' do
|
274
|
+
specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error }
|
275
|
+
end
|
197
276
|
end
|
198
277
|
|
199
278
|
it 'does not modify the parameters' do
|
@@ -210,62 +289,86 @@ module Ransack
|
|
210
289
|
let(:children_people_name_field) {
|
211
290
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
212
291
|
}
|
292
|
+
let(:notable_type_field) {
|
293
|
+
"#{quote_table_name("notes")}.#{quote_column_name("notable_type")}"
|
294
|
+
}
|
213
295
|
it 'evaluates conditions contextually' do
|
214
|
-
|
215
|
-
expect(
|
216
|
-
expect(
|
296
|
+
s = Search.new(Person, children_name_eq: 'Ernie')
|
297
|
+
expect(s.result).to be_an ActiveRecord::Relation
|
298
|
+
expect(s.result.to_sql).to match /#{
|
217
299
|
children_people_name_field} = 'Ernie'/
|
218
300
|
end
|
219
301
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
.
|
243
|
-
|
244
|
-
|
302
|
+
it 'use appropriate table alias' do
|
303
|
+
skip "Rails 6 regressed here, but it's fixed in 6-0-stable since https://github.com/rails/rails/commit/f9ba52477ca288e7effa5f6794ae3df3f4e982bc" if ENV["RAILS"] == "v6.0.3"
|
304
|
+
|
305
|
+
s = Search.new(Person, {
|
306
|
+
name_eq: "person_name_query",
|
307
|
+
articles_title_eq: "person_article_title_query",
|
308
|
+
parent_name_eq: "parent_name_query",
|
309
|
+
parent_articles_title_eq: 'parents_article_title_query'
|
310
|
+
}).result
|
311
|
+
|
312
|
+
real_query = remove_quotes_and_backticks(s.to_sql)
|
313
|
+
|
314
|
+
expect(real_query)
|
315
|
+
.to match(%r{LEFT OUTER JOIN articles ON (\('default_scope' = 'default_scope'\) AND )?articles.person_id = people.id})
|
316
|
+
expect(real_query)
|
317
|
+
.to match(%r{LEFT OUTER JOIN articles articles_people ON (\('default_scope' = 'default_scope'\) AND )?articles_people.person_id = parents_people.id})
|
318
|
+
|
319
|
+
expect(real_query)
|
320
|
+
.to include "people.name = 'person_name_query'"
|
321
|
+
expect(real_query)
|
322
|
+
.to include "articles.title = 'person_article_title_query'"
|
323
|
+
expect(real_query)
|
324
|
+
.to include "parents_people.name = 'parent_name_query'"
|
325
|
+
expect(real_query)
|
326
|
+
.to include "articles_people.title = 'parents_article_title_query'"
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'evaluates conditions for multiple `belongs_to` associations to the same table contextually' do
|
330
|
+
s = Search.new(
|
331
|
+
Recommendation,
|
332
|
+
person_name_eq: 'Ernie',
|
333
|
+
target_person_parent_name_eq: 'Test'
|
334
|
+
).result
|
335
|
+
expect(s).to be_an ActiveRecord::Relation
|
336
|
+
real_query = remove_quotes_and_backticks(s.to_sql)
|
337
|
+
expected_query = <<-SQL
|
338
|
+
SELECT recommendations.* FROM recommendations
|
339
|
+
LEFT OUTER JOIN people ON people.id = recommendations.person_id
|
340
|
+
LEFT OUTER JOIN people target_people_recommendations
|
341
|
+
ON target_people_recommendations.id = recommendations.target_person_id
|
342
|
+
LEFT OUTER JOIN people parents_people
|
343
|
+
ON parents_people.id = target_people_recommendations.parent_id
|
344
|
+
WHERE (people.name = 'Ernie' AND parents_people.name = 'Test')
|
345
|
+
SQL
|
346
|
+
.squish
|
347
|
+
expect(real_query).to eq expected_query
|
245
348
|
end
|
246
349
|
|
247
350
|
it 'evaluates compound conditions contextually' do
|
248
|
-
|
249
|
-
expect(
|
250
|
-
expect(
|
351
|
+
s = Search.new(Person, children_name_or_name_eq: 'Ernie').result
|
352
|
+
expect(s).to be_an ActiveRecord::Relation
|
353
|
+
expect(s.to_sql).to match /#{children_people_name_field
|
251
354
|
} = 'Ernie' OR #{people_name_field} = 'Ernie'/
|
252
355
|
end
|
253
356
|
|
254
357
|
it 'evaluates polymorphic belongs_to association conditions contextually' do
|
255
|
-
|
256
|
-
.
|
257
|
-
expect(
|
258
|
-
expect(
|
358
|
+
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie').result
|
359
|
+
expect(s).to be_an ActiveRecord::Relation
|
360
|
+
expect(s.to_sql).to match /#{people_name_field} = 'Ernie'/
|
361
|
+
expect(s.to_sql).to match /#{notable_type_field} = 'Person'/
|
259
362
|
end
|
260
363
|
|
261
364
|
it 'evaluates nested conditions' do
|
262
|
-
|
365
|
+
s = Search.new(Person, children_name_eq: 'Ernie',
|
263
366
|
g: [
|
264
367
|
{ m: 'or', name_eq: 'Ernie', children_children_name_eq: 'Ernie' }
|
265
368
|
]
|
266
369
|
).result
|
267
|
-
expect(
|
268
|
-
first, last =
|
370
|
+
expect(s).to be_an ActiveRecord::Relation
|
371
|
+
first, last = s.to_sql.split(/ AND /)
|
269
372
|
expect(first).to match /#{children_people_name_field} = 'Ernie'/
|
270
373
|
expect(last).to match /#{
|
271
374
|
people_name_field} = 'Ernie' OR #{
|
@@ -274,14 +377,14 @@ module Ransack
|
|
274
377
|
end
|
275
378
|
|
276
379
|
it 'evaluates arrays of groupings' do
|
277
|
-
|
380
|
+
s = Search.new(Person,
|
278
381
|
g: [
|
279
382
|
{ m: 'or', name_eq: 'Ernie', children_name_eq: 'Ernie' },
|
280
383
|
{ m: 'or', name_eq: 'Bert', children_name_eq: 'Bert' }
|
281
384
|
]
|
282
385
|
).result
|
283
|
-
expect(
|
284
|
-
first, last =
|
386
|
+
expect(s).to be_an ActiveRecord::Relation
|
387
|
+
first, last = s.to_sql.split(/ AND /)
|
285
388
|
expect(first).to match /#{people_name_field} = 'Ernie' OR #{
|
286
389
|
children_people_name_field} = 'Ernie'/
|
287
390
|
expect(last).to match /#{people_name_field} = 'Bert' OR #{
|
@@ -289,22 +392,24 @@ module Ransack
|
|
289
392
|
end
|
290
393
|
|
291
394
|
it 'returns distinct records when passed distinct: true' do
|
292
|
-
|
395
|
+
s = Search.new(Person,
|
293
396
|
g: [
|
294
397
|
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
295
398
|
]
|
296
399
|
)
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
all_or_load, uniq_or_distinct = :load, :distinct
|
301
|
-
end
|
302
|
-
expect(search.result.send(all_or_load).size)
|
400
|
+
|
401
|
+
all_or_load, uniq_or_distinct = :load, :distinct
|
402
|
+
expect(s.result.send(all_or_load).size)
|
303
403
|
.to eq(9000)
|
304
|
-
expect(
|
404
|
+
expect(s.result(distinct: true).size)
|
305
405
|
.to eq(10)
|
306
|
-
expect(
|
307
|
-
.to eq
|
406
|
+
expect(s.result.send(all_or_load).send(uniq_or_distinct))
|
407
|
+
.to eq s.result(distinct: true).send(all_or_load)
|
408
|
+
end
|
409
|
+
|
410
|
+
it 'evaluates joins with belongs_to join' do
|
411
|
+
s = Person.joins(:parent).ransack(parent_name_eq: 'Ernie').result(distinct: true)
|
412
|
+
expect(s).to be_an ActiveRecord::Relation
|
308
413
|
end
|
309
414
|
|
310
415
|
private
|
@@ -428,6 +533,27 @@ module Ransack
|
|
428
533
|
@s.sorts = 'id asc'
|
429
534
|
expect(@s.result.first.id).to eq 1
|
430
535
|
end
|
536
|
+
|
537
|
+
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
538
|
+
default = Ransack.options.clone
|
539
|
+
|
540
|
+
s = Search.new(Person, s: 'name asc')
|
541
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC"
|
542
|
+
|
543
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
544
|
+
s = Search.new(Person, s: 'name asc')
|
545
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS FIRST"
|
546
|
+
s = Search.new(Person, s: 'name desc')
|
547
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS LAST"
|
548
|
+
|
549
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
550
|
+
s = Search.new(Person, s: 'name asc')
|
551
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS LAST"
|
552
|
+
s = Search.new(Person, s: 'name desc')
|
553
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS FIRST"
|
554
|
+
|
555
|
+
Ransack.options = default
|
556
|
+
end
|
431
557
|
end
|
432
558
|
|
433
559
|
describe '#method_missing' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'machinist/active_record'
|
2
|
+
require 'polyamorous/polyamorous.rb'
|
2
3
|
require 'sham'
|
3
4
|
require 'faker'
|
4
5
|
require 'ransack'
|
6
|
+
require 'action_controller'
|
7
|
+
require 'ransack/helpers'
|
5
8
|
require 'pry'
|
9
|
+
require 'simplecov'
|
10
|
+
require 'byebug'
|
6
11
|
|
12
|
+
SimpleCov.start
|
7
13
|
I18n.enforce_available_locales = false
|
8
14
|
Time.zone = 'Eastern Time (US & Canada)'
|
9
15
|
I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'support', '*.yml')]
|
@@ -35,12 +41,14 @@ RSpec.configure do |config|
|
|
35
41
|
line = '=' * message.length
|
36
42
|
puts line, message, line
|
37
43
|
Schema.create
|
44
|
+
SubDB::Schema.create
|
38
45
|
end
|
39
46
|
|
40
47
|
config.before(:all) { Sham.reset(:before_all) }
|
41
48
|
config.before(:each) { Sham.reset(:before_each) }
|
42
49
|
|
43
50
|
config.include RansackHelper
|
51
|
+
config.include PolyamorousHelper
|
44
52
|
end
|
45
53
|
|
46
54
|
RSpec::Matchers.define :be_like do |expected|
|