ransack 1.8.4 → 3.2.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.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/cronjob.yml +102 -0
- data/.github/workflows/deploy.yml +35 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test-deploy.yml +29 -0
- data/.github/workflows/test.yml +130 -0
- data/.gitignore +3 -0
- data/{lib/ransack/adapters/mongoid/3.2/.gitkeep → .nojekyll} +0 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +352 -0
- data/CONTRIBUTING.md +25 -13
- data/Gemfile +26 -27
- data/README.md +65 -815
- data/Rakefile +1 -22
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +71 -0
- data/docs/.gitignore +19 -0
- data/docs/.nojekyll +0 -0
- data/docs/babel.config.js +3 -0
- data/docs/blog/2022-03-27-ransack-3.0.0.md +20 -0
- data/docs/docs/getting-started/_category_.json +4 -0
- data/docs/docs/getting-started/advanced-mode.md +46 -0
- data/docs/docs/getting-started/configuration.md +47 -0
- data/docs/docs/getting-started/search-matches.md +67 -0
- data/docs/docs/getting-started/simple-mode.md +284 -0
- data/docs/docs/getting-started/sorting.md +79 -0
- data/docs/docs/getting-started/using-predicates.md +282 -0
- data/docs/docs/going-further/_category_.json +4 -0
- data/docs/docs/going-further/acts-as-taggable-on.md +114 -0
- data/docs/docs/going-further/associations.md +70 -0
- data/docs/docs/going-further/custom-predicates.md +52 -0
- data/docs/docs/going-further/documentation.md +43 -0
- data/docs/docs/going-further/exporting-to-csv.md +49 -0
- data/docs/docs/going-further/external-guides.md +57 -0
- data/docs/docs/going-further/form-customisation.md +63 -0
- data/docs/docs/going-further/i18n.md +53 -0
- data/docs/docs/going-further/img/create_release.png +0 -0
- data/docs/docs/going-further/merging-searches.md +41 -0
- data/docs/docs/going-further/other-notes.md +428 -0
- data/docs/docs/going-further/polymorphic-search.md +40 -0
- data/docs/docs/going-further/ransackers.md +331 -0
- data/docs/docs/going-further/release_process.md +36 -0
- data/docs/docs/going-further/saving-queries.md +82 -0
- data/docs/docs/going-further/searching-postgres.md +57 -0
- data/docs/docs/going-further/wiki-contributors.md +82 -0
- data/docs/docs/intro.md +99 -0
- data/docs/docusaurus.config.js +120 -0
- data/docs/package.json +38 -0
- data/docs/sidebars.js +31 -0
- data/docs/src/components/HomepageFeatures/index.js +64 -0
- data/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- data/docs/src/css/custom.css +39 -0
- data/docs/src/pages/index.module.css +23 -0
- data/docs/src/pages/markdown-page.md +7 -0
- data/docs/static/.nojekyll +0 -0
- data/docs/static/img/docusaurus.png +0 -0
- data/docs/static/img/favicon.ico +0 -0
- data/docs/static/img/logo.svg +1 -0
- data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
- data/docs/static/img/tutorial/localeDropdown.png +0 -0
- data/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- data/docs/static/img/undraw_docusaurus_react.svg +170 -0
- data/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- data/docs/static/logo/ransack-h.png +0 -0
- data/docs/static/logo/ransack-h.svg +34 -0
- data/docs/static/logo/ransack-v.png +0 -0
- data/docs/static/logo/ransack-v.svg +34 -0
- data/docs/static/logo/ransack.png +0 -0
- data/docs/static/logo/ransack.svg +21 -0
- data/docs/yarn.lock +8436 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +70 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +92 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.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/polyamorous.rb +1 -0
- data/lib/ransack/adapters/active_record/base.rb +14 -3
- data/lib/ransack/adapters/active_record/context.rb +140 -196
- data/lib/ransack/adapters/active_record/ransack/constants.rb +19 -4
- data/lib/ransack/adapters/active_record/ransack/context.rb +9 -19
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +7 -7
- 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 +0 -9
- data/lib/ransack/adapters.rb +2 -0
- data/lib/ransack/configuration.rb +52 -2
- data/lib/ransack/constants.rb +1 -5
- data/lib/ransack/context.rb +29 -24
- data/lib/ransack/helpers/form_builder.rb +12 -6
- data/lib/ransack/helpers/form_helper.rb +11 -3
- data/lib/ransack/helpers.rb +1 -1
- 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/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/nl.yml +4 -4
- data/lib/ransack/locale/ru.yml +70 -0
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/locale/tr.yml +70 -0
- data/lib/ransack/locale/zh-CN.yml +12 -12
- data/lib/ransack/nodes/attribute.rb +2 -2
- data/lib/ransack/nodes/condition.rb +7 -1
- data/lib/ransack/nodes/grouping.rb +3 -8
- data/lib/ransack/nodes/sort.rb +3 -3
- data/lib/ransack/nodes/value.rb +3 -3
- data/lib/ransack/predicate.rb +13 -20
- data/lib/ransack/search.rb +7 -4
- 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 +7 -5
- data/ransack.gemspec +9 -25
- data/spec/blueprints/articles.rb +1 -1
- data/spec/blueprints/comments.rb +1 -1
- data/spec/blueprints/notes.rb +1 -1
- data/spec/blueprints/tags.rb +1 -1
- data/spec/console.rb +5 -5
- data/spec/helpers/polyamorous_helper.rb +13 -0
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/spec/polyamorous/join_association_spec.rb +30 -0
- data/spec/polyamorous/join_dependency_spec.rb +81 -0
- data/spec/polyamorous/join_spec.rb +19 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +105 -11
- data/spec/ransack/adapters/active_record/context_spec.rb +63 -24
- data/spec/ransack/configuration_spec.rb +24 -0
- data/spec/ransack/helpers/form_builder_spec.rb +3 -15
- data/spec/ransack/helpers/form_helper_spec.rb +135 -168
- data/spec/ransack/nodes/condition_spec.rb +13 -0
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/nodes/value_spec.rb +115 -0
- data/spec/ransack/predicate_spec.rb +54 -2
- data/spec/ransack/search_spec.rb +266 -36
- data/spec/spec_helper.rb +14 -5
- data/spec/support/schema.rb +99 -21
- metadata +117 -187
- data/.travis.yml +0 -86
- data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -179
- data/lib/ransack/adapters/active_record/3.0/context.rb +0 -203
- data/lib/ransack/adapters/active_record/3.1/context.rb +0 -212
- 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/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 -134
- data/lib/ransack/adapters/mongoid/context.rb +0 -212
- 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 -15
- data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -314
- data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
- data/spec/mongoid/configuration_spec.rb +0 -162
- 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 -49
- data/spec/mongoid/nodes/grouping_spec.rb +0 -13
- data/spec/mongoid/predicate_spec.rb +0 -155
- data/spec/mongoid/search_spec.rb +0 -445
- data/spec/mongoid/support/mongoid.yml +0 -11
- data/spec/mongoid/support/schema.rb +0 -135
- data/spec/mongoid/translate_spec.rb +0 -14
- data/spec/mongoid_spec_helper.rb +0 -63
- data/spec/ransack/dependencies_spec.rb +0 -12
data/spec/ransack/search_spec.rb
CHANGED
|
@@ -20,6 +20,44 @@ module Ransack
|
|
|
20
20
|
Search.new(Person, name_eq: 'foobar')
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
context 'whitespace stripping' do
|
|
24
|
+
context 'when whitespace_strip option is true' do
|
|
25
|
+
before do
|
|
26
|
+
Ransack.configure { |c| c.strip_whitespace = true }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'strips leading & trailing whitespace before building' do
|
|
30
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
31
|
+
.with({ 'name_eq' => 'foobar' })
|
|
32
|
+
Search.new(Person, name_eq: ' foobar ')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when whitespace_strip option is false' do
|
|
37
|
+
before do
|
|
38
|
+
Ransack.configure { |c| c.strip_whitespace = false }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'doesn\'t strip leading & trailing whitespace before building' do
|
|
42
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
43
|
+
.with({ 'name_eq' => ' foobar ' })
|
|
44
|
+
Search.new(Person, name_eq: ' foobar ')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'strips leading & trailing whitespace when strip_whitespace search parameter is true' do
|
|
49
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
50
|
+
.with({ 'name_eq' => 'foobar' })
|
|
51
|
+
Search.new(Person, { name_eq: ' foobar ' }, { strip_whitespace: true })
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'doesn\'t strip leading & trailing whitespace when strip_whitespace search parameter is false' do
|
|
55
|
+
expect_any_instance_of(Search).to receive(:build)
|
|
56
|
+
.with({ 'name_eq' => ' foobar ' })
|
|
57
|
+
Search.new(Person, { name_eq: ' foobar ' }, { strip_whitespace: false })
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
23
61
|
it 'removes empty suffixed conditions before building' do
|
|
24
62
|
expect_any_instance_of(Search).to receive(:build).with({})
|
|
25
63
|
Search.new(Person, name_eq_any: [''])
|
|
@@ -109,6 +147,43 @@ module Ransack
|
|
|
109
147
|
expect(s.result.to_sql).to include 'published'
|
|
110
148
|
end
|
|
111
149
|
|
|
150
|
+
# The failure/oversight in Ransack::Nodes::Condition#arel_predicate or deeper is beyond my understanding of the structures
|
|
151
|
+
it 'preserves (inverts) default scope and conditions for negative subqueries' do
|
|
152
|
+
# the positive case (published_articles_title_eq) is
|
|
153
|
+
# SELECT "people".* FROM "people"
|
|
154
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
|
155
|
+
# AND "articles"."published" = 't'
|
|
156
|
+
# AND ('default_scope' = 'default_scope')
|
|
157
|
+
# WHERE "articles"."title" = 'Test' ORDER BY "people"."id" DESC
|
|
158
|
+
#
|
|
159
|
+
# negative case was
|
|
160
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
161
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
162
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
163
|
+
# AND NOT ("articles"."title" != 'Test')
|
|
164
|
+
# ) ORDER BY "people"."id" DESC
|
|
165
|
+
#
|
|
166
|
+
# Should have been like
|
|
167
|
+
# SELECT "people".* FROM "people" WHERE "people"."id" NOT IN (
|
|
168
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
169
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
170
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
171
|
+
# ) ORDER BY "people"."id" DESC
|
|
172
|
+
#
|
|
173
|
+
# With tenanting (eg default_scope with column reference), NOT IN should be like
|
|
174
|
+
# SELECT "people".* FROM "people" WHERE "people"."tenant_id" = 'tenant_id' AND "people"."id" NOT IN (
|
|
175
|
+
# SELECT "articles"."person_id" FROM "articles"
|
|
176
|
+
# WHERE "articles"."person_id" = "people"."id"
|
|
177
|
+
# AND "articles"."tenant_id" = 'tenant_id'
|
|
178
|
+
# AND "articles"."title" = 'Test' AND "articles"."published" = 't' AND ('default_scope' = 'default_scope')
|
|
179
|
+
# ) ORDER BY "people"."id" DESC
|
|
180
|
+
|
|
181
|
+
pending("spec should pass, but I do not know how/where to fix lib code")
|
|
182
|
+
s = Search.new(Person, published_articles_title_not_eq: 'Test')
|
|
183
|
+
expect(s.result.to_sql).to include 'default_scope'
|
|
184
|
+
expect(s.result.to_sql).to include 'published'
|
|
185
|
+
end
|
|
186
|
+
|
|
112
187
|
it 'discards empty conditions' do
|
|
113
188
|
s = Search.new(Person, children_name_eq: '')
|
|
114
189
|
condition = s.base[:children_name_eq]
|
|
@@ -189,7 +264,7 @@ module Ransack
|
|
|
189
264
|
context 'with an invalid condition' do
|
|
190
265
|
subject { Search.new(Person, unknown_attr_eq: 'Ernie') }
|
|
191
266
|
|
|
192
|
-
context 'when ignore_unknown_conditions is false' do
|
|
267
|
+
context 'when ignore_unknown_conditions configuration option is false' do
|
|
193
268
|
before do
|
|
194
269
|
Ransack.configure { |c| c.ignore_unknown_conditions = false }
|
|
195
270
|
end
|
|
@@ -197,13 +272,39 @@ module Ransack
|
|
|
197
272
|
specify { expect { subject }.to raise_error ArgumentError }
|
|
198
273
|
end
|
|
199
274
|
|
|
200
|
-
context 'when ignore_unknown_conditions is true' do
|
|
275
|
+
context 'when ignore_unknown_conditions configuration option is true' do
|
|
201
276
|
before do
|
|
202
277
|
Ransack.configure { |c| c.ignore_unknown_conditions = true }
|
|
203
278
|
end
|
|
204
279
|
|
|
205
280
|
specify { expect { subject }.not_to raise_error }
|
|
206
281
|
end
|
|
282
|
+
|
|
283
|
+
subject(:with_ignore_unknown_conditions_false) {
|
|
284
|
+
Search.new(Person,
|
|
285
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
286
|
+
{ ignore_unknown_conditions: false }
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
subject(:with_ignore_unknown_conditions_true) {
|
|
291
|
+
Search.new(Person,
|
|
292
|
+
{ unknown_attr_eq: 'Ernie' },
|
|
293
|
+
{ ignore_unknown_conditions: true }
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
context 'when ignore_unknown_conditions search parameter is absent' do
|
|
298
|
+
specify { expect { subject }.not_to raise_error }
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
context 'when ignore_unknown_conditions search parameter is false' do
|
|
302
|
+
specify { expect { with_ignore_unknown_conditions_false }.to raise_error ArgumentError }
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context 'when ignore_unknown_conditions search parameter is true' do
|
|
306
|
+
specify { expect { with_ignore_unknown_conditions_true }.not_to raise_error }
|
|
307
|
+
end
|
|
207
308
|
end
|
|
208
309
|
|
|
209
310
|
it 'does not modify the parameters' do
|
|
@@ -211,6 +312,29 @@ module Ransack
|
|
|
211
312
|
expect { Search.new(Person, params) }.not_to change { params }
|
|
212
313
|
end
|
|
213
314
|
|
|
315
|
+
context "ransackable_scope" do
|
|
316
|
+
around(:each) do |example|
|
|
317
|
+
Person.define_singleton_method(:name_eq) do |name|
|
|
318
|
+
self.where(name: name)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
begin
|
|
322
|
+
example.run
|
|
323
|
+
ensure
|
|
324
|
+
Person.singleton_class.undef_method :name_eq
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "is prioritized over base predicates" do
|
|
329
|
+
allow(Person).to receive(:ransackable_scopes)
|
|
330
|
+
.and_return(Person.ransackable_scopes + [:name_eq])
|
|
331
|
+
|
|
332
|
+
s = Search.new(Person, name_eq: "Johny")
|
|
333
|
+
expect(s.instance_variable_get(:@scope_args)["name_eq"]).to eq("Johny")
|
|
334
|
+
expect(s.base[:name_eq]).to be_nil
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
214
338
|
end
|
|
215
339
|
|
|
216
340
|
describe '#result' do
|
|
@@ -220,6 +344,9 @@ module Ransack
|
|
|
220
344
|
let(:children_people_name_field) {
|
|
221
345
|
"#{quote_table_name("children_people")}.#{quote_column_name("name")}"
|
|
222
346
|
}
|
|
347
|
+
let(:notable_type_field) {
|
|
348
|
+
"#{quote_table_name("notes")}.#{quote_column_name("notable_type")}"
|
|
349
|
+
}
|
|
223
350
|
it 'evaluates conditions contextually' do
|
|
224
351
|
s = Search.new(Person, children_name_eq: 'Ernie')
|
|
225
352
|
expect(s.result).to be_an ActiveRecord::Relation
|
|
@@ -227,13 +354,32 @@ module Ransack
|
|
|
227
354
|
children_people_name_field} = 'Ernie'/
|
|
228
355
|
end
|
|
229
356
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
357
|
+
it 'use appropriate table alias' do
|
|
358
|
+
s = Search.new(Person, {
|
|
359
|
+
name_eq: "person_name_query",
|
|
360
|
+
articles_title_eq: "person_article_title_query",
|
|
361
|
+
parent_name_eq: "parent_name_query",
|
|
362
|
+
parent_articles_title_eq: 'parents_article_title_query'
|
|
363
|
+
}).result
|
|
364
|
+
|
|
365
|
+
real_query = remove_quotes_and_backticks(s.to_sql)
|
|
366
|
+
|
|
367
|
+
expect(real_query)
|
|
368
|
+
.to match(%r{LEFT OUTER JOIN articles ON (\('default_scope' = 'default_scope'\) AND )?articles.person_id = people.id})
|
|
369
|
+
expect(real_query)
|
|
370
|
+
.to match(%r{LEFT OUTER JOIN articles articles_people ON (\('default_scope' = 'default_scope'\) AND )?articles_people.person_id = parents_people.id})
|
|
371
|
+
|
|
372
|
+
expect(real_query)
|
|
373
|
+
.to include "people.name = 'person_name_query'"
|
|
374
|
+
expect(real_query)
|
|
375
|
+
.to include "articles.title = 'person_article_title_query'"
|
|
376
|
+
expect(real_query)
|
|
377
|
+
.to include "parents_people.name = 'parent_name_query'"
|
|
378
|
+
expect(real_query)
|
|
379
|
+
.to include "articles_people.title = 'parents_article_title_query'"
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
it 'evaluates conditions for multiple `belongs_to` associations to the same table contextually' do
|
|
237
383
|
s = Search.new(
|
|
238
384
|
Recommendation,
|
|
239
385
|
person_name_eq: 'Ernie',
|
|
@@ -248,7 +394,7 @@ module Ransack
|
|
|
248
394
|
ON target_people_recommendations.id = recommendations.target_person_id
|
|
249
395
|
LEFT OUTER JOIN people parents_people
|
|
250
396
|
ON parents_people.id = target_people_recommendations.parent_id
|
|
251
|
-
WHERE (
|
|
397
|
+
WHERE (people.name = 'Ernie' AND parents_people.name = 'Test')
|
|
252
398
|
SQL
|
|
253
399
|
.squish
|
|
254
400
|
expect(real_query).to eq expected_query
|
|
@@ -265,6 +411,7 @@ module Ransack
|
|
|
265
411
|
s = Search.new(Note, notable_of_Person_type_name_eq: 'Ernie').result
|
|
266
412
|
expect(s).to be_an ActiveRecord::Relation
|
|
267
413
|
expect(s.to_sql).to match /#{people_name_field} = 'Ernie'/
|
|
414
|
+
expect(s.to_sql).to match /#{notable_type_field} = 'Person'/
|
|
268
415
|
end
|
|
269
416
|
|
|
270
417
|
it 'evaluates nested conditions' do
|
|
@@ -303,11 +450,8 @@ module Ransack
|
|
|
303
450
|
{ m: 'or', comments_body_cont: 'e', articles_comments_body_cont: 'e' }
|
|
304
451
|
]
|
|
305
452
|
)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
else
|
|
309
|
-
all_or_load, uniq_or_distinct = :load, :distinct
|
|
310
|
-
end
|
|
453
|
+
|
|
454
|
+
all_or_load, uniq_or_distinct = :load, :distinct
|
|
311
455
|
expect(s.result.send(all_or_load).size)
|
|
312
456
|
.to eq(9000)
|
|
313
457
|
expect(s.result(distinct: true).size)
|
|
@@ -316,6 +460,11 @@ module Ransack
|
|
|
316
460
|
.to eq s.result(distinct: true).send(all_or_load)
|
|
317
461
|
end
|
|
318
462
|
|
|
463
|
+
it 'evaluates joins with belongs_to join' do
|
|
464
|
+
s = Person.joins(:parent).ransack(parent_name_eq: 'Ernie').result(distinct: true)
|
|
465
|
+
expect(s).to be_an ActiveRecord::Relation
|
|
466
|
+
end
|
|
467
|
+
|
|
319
468
|
private
|
|
320
469
|
|
|
321
470
|
def remove_quotes_and_backticks(str)
|
|
@@ -355,88 +504,169 @@ module Ransack
|
|
|
355
504
|
expect(sort.dir).to eq 'asc'
|
|
356
505
|
end
|
|
357
506
|
|
|
358
|
-
it 'creates sorts based on
|
|
359
|
-
@s.sorts =
|
|
507
|
+
it 'creates sorts based on a single alias/direction' do
|
|
508
|
+
@s.sorts = 'daddy desc'
|
|
509
|
+
expect(@s.sorts.size).to eq(1)
|
|
510
|
+
sort = @s.sorts.first
|
|
511
|
+
expect(sort).to be_a Nodes::Sort
|
|
512
|
+
expect(sort.name).to eq 'parent_name'
|
|
513
|
+
expect(sort.dir).to eq 'desc'
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
it 'creates sorts based on a single alias and uppercase direction' do
|
|
517
|
+
@s.sorts = 'daddy DESC'
|
|
518
|
+
expect(@s.sorts.size).to eq(1)
|
|
519
|
+
sort = @s.sorts.first
|
|
520
|
+
expect(sort).to be_a Nodes::Sort
|
|
521
|
+
expect(sort.name).to eq 'parent_name'
|
|
522
|
+
expect(sort.dir).to eq 'desc'
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
it 'creates sorts based on a single alias and without direction' do
|
|
526
|
+
@s.sorts = 'daddy'
|
|
527
|
+
expect(@s.sorts.size).to eq(1)
|
|
528
|
+
sort = @s.sorts.first
|
|
529
|
+
expect(sort).to be_a Nodes::Sort
|
|
530
|
+
expect(sort.name).to eq 'parent_name'
|
|
531
|
+
expect(sort.dir).to eq 'asc'
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
it 'creates sorts based on attributes, alias and directions in array format' do
|
|
535
|
+
@s.sorts = ['id desc', { name: 'daddy', dir: 'asc' }]
|
|
360
536
|
expect(@s.sorts.size).to eq(2)
|
|
361
537
|
sort1, sort2 = @s.sorts
|
|
362
538
|
expect(sort1).to be_a Nodes::Sort
|
|
363
539
|
expect(sort1.name).to eq 'id'
|
|
364
540
|
expect(sort1.dir).to eq 'desc'
|
|
365
541
|
expect(sort2).to be_a Nodes::Sort
|
|
366
|
-
expect(sort2.name).to eq '
|
|
542
|
+
expect(sort2.name).to eq 'parent_name'
|
|
367
543
|
expect(sort2.dir).to eq 'asc'
|
|
368
544
|
end
|
|
369
545
|
|
|
370
|
-
it 'creates sorts based on
|
|
371
|
-
@s.sorts = ['id DESC', { name: '
|
|
546
|
+
it 'creates sorts based on attributes, alias and uppercase directions in array format' do
|
|
547
|
+
@s.sorts = ['id DESC', { name: 'daddy', dir: 'ASC' }]
|
|
372
548
|
expect(@s.sorts.size).to eq(2)
|
|
373
549
|
sort1, sort2 = @s.sorts
|
|
374
550
|
expect(sort1).to be_a Nodes::Sort
|
|
375
551
|
expect(sort1.name).to eq 'id'
|
|
376
552
|
expect(sort1.dir).to eq 'desc'
|
|
377
553
|
expect(sort2).to be_a Nodes::Sort
|
|
378
|
-
expect(sort2.name).to eq '
|
|
554
|
+
expect(sort2.name).to eq 'parent_name'
|
|
379
555
|
expect(sort2.dir).to eq 'asc'
|
|
380
556
|
end
|
|
381
557
|
|
|
382
|
-
it 'creates sorts based on
|
|
558
|
+
it 'creates sorts based on attributes, alias and different directions
|
|
383
559
|
in array format' do
|
|
384
|
-
@s.sorts = ['id DESC', { name: '
|
|
560
|
+
@s.sorts = ['id DESC', { name: 'daddy', dir: nil }]
|
|
385
561
|
expect(@s.sorts.size).to eq(2)
|
|
386
562
|
sort1, sort2 = @s.sorts
|
|
387
563
|
expect(sort1).to be_a Nodes::Sort
|
|
388
564
|
expect(sort1.name).to eq 'id'
|
|
389
565
|
expect(sort1.dir).to eq 'desc'
|
|
390
566
|
expect(sort2).to be_a Nodes::Sort
|
|
391
|
-
expect(sort2.name).to eq '
|
|
567
|
+
expect(sort2.name).to eq 'parent_name'
|
|
392
568
|
expect(sort2.dir).to eq 'asc'
|
|
393
569
|
end
|
|
394
570
|
|
|
395
|
-
it 'creates sorts based on
|
|
571
|
+
it 'creates sorts based on attributes, alias and directions in hash format' do
|
|
396
572
|
@s.sorts = {
|
|
397
573
|
'0' => { name: 'id', dir: 'desc' },
|
|
398
|
-
'1' => { name: '
|
|
574
|
+
'1' => { name: 'daddy', dir: 'asc' }
|
|
399
575
|
}
|
|
400
576
|
expect(@s.sorts.size).to eq(2)
|
|
401
577
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
402
578
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
403
|
-
|
|
579
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
404
580
|
expect(id_sort.dir).to eq 'desc'
|
|
405
|
-
expect(
|
|
581
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
406
582
|
end
|
|
407
583
|
|
|
408
|
-
it 'creates sorts based on
|
|
584
|
+
it 'creates sorts based on attributes, alias and uppercase directions
|
|
409
585
|
in hash format' do
|
|
410
586
|
@s.sorts = {
|
|
411
587
|
'0' => { name: 'id', dir: 'DESC' },
|
|
412
|
-
'1' => { name: '
|
|
588
|
+
'1' => { name: 'daddy', dir: 'ASC' }
|
|
413
589
|
}
|
|
414
590
|
expect(@s.sorts.size).to eq(2)
|
|
415
591
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
416
592
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
417
|
-
|
|
593
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
418
594
|
expect(id_sort.dir).to eq 'desc'
|
|
419
|
-
expect(
|
|
595
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
420
596
|
end
|
|
421
597
|
|
|
422
|
-
it 'creates sorts based on
|
|
598
|
+
it 'creates sorts based on attributes, alias and different directions
|
|
423
599
|
in hash format' do
|
|
424
600
|
@s.sorts = {
|
|
425
601
|
'0' => { name: 'id', dir: 'DESC' },
|
|
426
|
-
'1' => { name: '
|
|
602
|
+
'1' => { name: 'daddy', dir: nil }
|
|
427
603
|
}
|
|
428
604
|
expect(@s.sorts.size).to eq(2)
|
|
429
605
|
expect(@s.sorts).to be_all { |s| Nodes::Sort === s }
|
|
430
606
|
id_sort = @s.sorts.detect { |s| s.name == 'id' }
|
|
431
|
-
|
|
607
|
+
daddy_sort = @s.sorts.detect { |s| s.name == 'parent_name' }
|
|
432
608
|
expect(id_sort.dir).to eq 'desc'
|
|
433
|
-
expect(
|
|
609
|
+
expect(daddy_sort.dir).to eq 'asc'
|
|
434
610
|
end
|
|
435
611
|
|
|
436
612
|
it 'overrides existing sort' do
|
|
437
613
|
@s.sorts = 'id asc'
|
|
438
614
|
expect(@s.result.first.id).to eq 1
|
|
439
615
|
end
|
|
616
|
+
|
|
617
|
+
it "PG's sort option", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
618
|
+
default = Ransack.options.clone
|
|
619
|
+
|
|
620
|
+
s = Search.new(Person, s: 'name asc')
|
|
621
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC"
|
|
622
|
+
|
|
623
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
624
|
+
s = Search.new(Person, s: 'name asc')
|
|
625
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS FIRST"
|
|
626
|
+
s = Search.new(Person, s: 'name desc')
|
|
627
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS LAST"
|
|
628
|
+
|
|
629
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
|
630
|
+
s = Search.new(Person, s: 'name asc')
|
|
631
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" ASC NULLS LAST"
|
|
632
|
+
s = Search.new(Person, s: 'name desc')
|
|
633
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" DESC NULLS FIRST"
|
|
634
|
+
|
|
635
|
+
Ransack.options = default
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
it "PG's sort option with double name", if: ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" do
|
|
639
|
+
default = Ransack.options.clone
|
|
640
|
+
|
|
641
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
642
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC"
|
|
643
|
+
|
|
644
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_first }
|
|
645
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
646
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS FIRST"
|
|
647
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
648
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS LAST"
|
|
649
|
+
|
|
650
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_last }
|
|
651
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
652
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS LAST"
|
|
653
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
654
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
|
655
|
+
|
|
656
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_first }
|
|
657
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
658
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS FIRST"
|
|
659
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
660
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS FIRST"
|
|
661
|
+
|
|
662
|
+
Ransack.configure { |c| c.postgres_fields_sort_option = :nulls_always_last }
|
|
663
|
+
s = Search.new(Person, s: 'doubled_name asc')
|
|
664
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" ASC NULLS LAST"
|
|
665
|
+
s = Search.new(Person, s: 'doubled_name desc')
|
|
666
|
+
expect(s.result.to_sql).to eq "SELECT \"people\".* FROM \"people\" ORDER BY \"people\".\"name\" || \"people\".\"name\" DESC NULLS LAST"
|
|
667
|
+
|
|
668
|
+
Ransack.options = default
|
|
669
|
+
end
|
|
440
670
|
end
|
|
441
671
|
|
|
442
672
|
describe '#method_missing' do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
require 'machinist/active_record'
|
|
2
|
+
require 'polyamorous/polyamorous'
|
|
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')]
|
|
@@ -11,16 +17,17 @@ I18n.load_path += Dir[File.join(File.dirname(__FILE__), 'support', '*.yml')]
|
|
|
11
17
|
Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)]
|
|
12
18
|
.each { |f| require f }
|
|
13
19
|
|
|
20
|
+
Faker::Config.random = Random.new(0)
|
|
14
21
|
Sham.define do
|
|
15
22
|
name { Faker::Name.name }
|
|
16
23
|
title { Faker::Lorem.sentence }
|
|
17
24
|
body { Faker::Lorem.paragraph }
|
|
18
25
|
salary { |index| 30000 + (index * 1000) }
|
|
19
|
-
tag_name { Faker::Lorem.words(3).join(' ') }
|
|
20
|
-
note { Faker::Lorem.words(7).join(' ') }
|
|
21
|
-
only_admin { Faker::Lorem.words(3).join(' ') }
|
|
22
|
-
only_search { Faker::Lorem.words(3).join(' ') }
|
|
23
|
-
only_sort { Faker::Lorem.words(3).join(' ') }
|
|
26
|
+
tag_name { Faker::Lorem.words(number: 3).join(' ') }
|
|
27
|
+
note { Faker::Lorem.words(number: 7).join(' ') }
|
|
28
|
+
only_admin { Faker::Lorem.words(number: 3).join(' ') }
|
|
29
|
+
only_search { Faker::Lorem.words(number: 3).join(' ') }
|
|
30
|
+
only_sort { Faker::Lorem.words(number: 3).join(' ') }
|
|
24
31
|
notable_id { |id| id }
|
|
25
32
|
end
|
|
26
33
|
|
|
@@ -35,12 +42,14 @@ RSpec.configure do |config|
|
|
|
35
42
|
line = '=' * message.length
|
|
36
43
|
puts line, message, line
|
|
37
44
|
Schema.create
|
|
45
|
+
SubDB::Schema.create
|
|
38
46
|
end
|
|
39
47
|
|
|
40
48
|
config.before(:all) { Sham.reset(:before_all) }
|
|
41
49
|
config.before(:each) { Sham.reset(:before_each) }
|
|
42
50
|
|
|
43
51
|
config.include RansackHelper
|
|
52
|
+
config.include PolyamorousHelper
|
|
44
53
|
end
|
|
45
54
|
|
|
46
55
|
RSpec::Matchers.define :be_like do |expected|
|