pg_search 2.1.4 → 2.1.5
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 +4 -4
- data/.rubocop.yml +2 -4
- data/.travis.yml +27 -25
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -4
- data/README.md +184 -151
- data/Rakefile +1 -5
- data/lib/pg_search.rb +1 -1
- data/lib/pg_search/configuration.rb +2 -2
- data/lib/pg_search/document.rb +3 -3
- data/lib/pg_search/features/dmetaphone.rb +1 -1
- data/lib/pg_search/features/feature.rb +1 -1
- data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +1 -1
- data/lib/pg_search/multisearch.rb +1 -1
- data/lib/pg_search/multisearchable.rb +4 -4
- data/lib/pg_search/scope_options.rb +13 -28
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +1 -2
- data/spec/integration/associations_spec.rb +100 -100
- data/spec/integration/pagination_spec.rb +7 -7
- data/spec/integration/pg_search_spec.rb +225 -225
- data/spec/integration/single_table_inheritance_spec.rb +14 -14
- data/spec/lib/pg_search/configuration/association_spec.rb +5 -5
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +1 -1
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +2 -2
- data/spec/lib/pg_search/features/trigram_spec.rb +1 -1
- data/spec/lib/pg_search/features/tsearch_spec.rb +12 -12
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +10 -10
- data/spec/lib/pg_search/multisearch_spec.rb +5 -5
- data/spec/lib/pg_search/multisearchable_spec.rb +26 -26
- data/spec/lib/pg_search/normalizer_spec.rb +5 -5
- data/spec/lib/pg_search_spec.rb +30 -30
- data/spec/spec_helper.rb +1 -1
- data/spec/support/database.rb +12 -19
- metadata +4 -18
@@ -11,7 +11,7 @@ describe "pagination" do
|
|
11
11
|
|
12
12
|
model do
|
13
13
|
include PgSearch
|
14
|
-
pg_search_scope :search_name, :
|
14
|
+
pg_search_scope :search_name, against: :name
|
15
15
|
|
16
16
|
def self.page(page_number)
|
17
17
|
offset = (page_number - 1) * 2
|
@@ -21,18 +21,18 @@ describe "pagination" do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it "is chainable before a search scope" do
|
24
|
-
better = PaginatedModel.create!(:
|
25
|
-
best = PaginatedModel.create!(:
|
26
|
-
good = PaginatedModel.create!(:
|
24
|
+
better = PaginatedModel.create!(name: "foo foo bar")
|
25
|
+
best = PaginatedModel.create!(name: "foo foo foo")
|
26
|
+
good = PaginatedModel.create!(name: "foo bar bar")
|
27
27
|
|
28
28
|
expect(PaginatedModel.page(1).search_name("foo")).to eq([best, better])
|
29
29
|
expect(PaginatedModel.page(2).search_name("foo")).to eq([good])
|
30
30
|
end
|
31
31
|
|
32
32
|
it "is chainable after a search scope" do
|
33
|
-
better = PaginatedModel.create!(:
|
34
|
-
best = PaginatedModel.create!(:
|
35
|
-
good = PaginatedModel.create!(:
|
33
|
+
better = PaginatedModel.create!(name: "foo foo bar")
|
34
|
+
best = PaginatedModel.create!(name: "foo foo foo")
|
35
|
+
good = PaginatedModel.create!(name: "foo bar bar")
|
36
36
|
|
37
37
|
expect(PaginatedModel.search_name("foo").page(1)).to eq([best, better])
|
38
38
|
expect(PaginatedModel.search_name("foo").page(2)).to eq([good])
|
@@ -30,7 +30,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
30
30
|
|
31
31
|
describe ".pg_search_scope" do
|
32
32
|
it "builds a chainable scope" do
|
33
|
-
ModelWithPgSearch.pg_search_scope "matching_query", :
|
33
|
+
ModelWithPgSearch.pg_search_scope "matching_query", against: []
|
34
34
|
scope = ModelWithPgSearch.where("1 = 1").matching_query("foo").where("1 = 1")
|
35
35
|
expect(scope).to be_an ActiveRecord::Relation
|
36
36
|
end
|
@@ -40,13 +40,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
40
40
|
ModelWithPgSearch.pg_search_scope :search_title_or_content,
|
41
41
|
lambda { |query, pick_content|
|
42
42
|
{
|
43
|
-
:
|
44
|
-
:
|
43
|
+
query: query.gsub("-remove-", ""),
|
44
|
+
against: pick_content ? :content : :title
|
45
45
|
}
|
46
46
|
}
|
47
47
|
|
48
|
-
included = ModelWithPgSearch.create!(:
|
49
|
-
excluded = ModelWithPgSearch.create!(:
|
48
|
+
included = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
49
|
+
excluded = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
50
50
|
|
51
51
|
expect(ModelWithPgSearch.search_title_or_content('fo-remove-o', false)).to eq([included])
|
52
52
|
expect(ModelWithPgSearch.search_title_or_content('b-remove-ar', true)).to eq([included])
|
@@ -56,8 +56,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
56
56
|
context "when an unknown option is passed in" do
|
57
57
|
it "raises an exception when invoked" do
|
58
58
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
59
|
-
:
|
60
|
-
:
|
59
|
+
against: :content,
|
60
|
+
foo: :bar
|
61
61
|
|
62
62
|
expect {
|
63
63
|
ModelWithPgSearch.with_unknown_option("foo")
|
@@ -67,7 +67,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
67
67
|
context "dynamically" do
|
68
68
|
it "raises an exception when invoked" do
|
69
69
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
70
|
-
->(*) { { :
|
70
|
+
->(*) { { against: :content, foo: :bar } }
|
71
71
|
|
72
72
|
expect {
|
73
73
|
ModelWithPgSearch.with_unknown_option("foo")
|
@@ -79,8 +79,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
79
79
|
context "when an unknown :using is passed" do
|
80
80
|
it "raises an exception when invoked" do
|
81
81
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
82
|
-
:
|
83
|
-
:
|
82
|
+
against: :content,
|
83
|
+
using: :foo
|
84
84
|
|
85
85
|
expect {
|
86
86
|
ModelWithPgSearch.with_unknown_using("foo")
|
@@ -90,7 +90,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
90
90
|
context "dynamically" do
|
91
91
|
it "raises an exception when invoked" do
|
92
92
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
93
|
-
->(*) { { :
|
93
|
+
->(*) { { against: :content, using: :foo } }
|
94
94
|
|
95
95
|
expect {
|
96
96
|
ModelWithPgSearch.with_unknown_using("foo")
|
@@ -102,8 +102,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
102
102
|
context "when an unknown :ignoring is passed" do
|
103
103
|
it "raises an exception when invoked" do
|
104
104
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
105
|
-
:
|
106
|
-
:
|
105
|
+
against: :content,
|
106
|
+
ignoring: :foo
|
107
107
|
|
108
108
|
expect {
|
109
109
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
@@ -113,7 +113,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
113
113
|
context "dynamically" do
|
114
114
|
it "raises an exception when invoked" do
|
115
115
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
116
|
-
->(*) { { :
|
116
|
+
->(*) { { against: :content, ignoring: :foo } }
|
117
117
|
|
118
118
|
expect {
|
119
119
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
@@ -146,7 +146,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
146
146
|
describe "a search scope" do
|
147
147
|
context "against a single column" do
|
148
148
|
before do
|
149
|
-
ModelWithPgSearch.pg_search_scope :search_content, :
|
149
|
+
ModelWithPgSearch.pg_search_scope :search_content, against: :content
|
150
150
|
end
|
151
151
|
|
152
152
|
context "when chained after a select() scope" do
|
@@ -288,15 +288,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
288
288
|
end
|
289
289
|
|
290
290
|
it "returns an empty array when a blank query is passed in" do
|
291
|
-
ModelWithPgSearch.create!(:
|
291
|
+
ModelWithPgSearch.create!(content: 'foo')
|
292
292
|
|
293
293
|
results = ModelWithPgSearch.search_content('')
|
294
294
|
expect(results).to eq([])
|
295
295
|
end
|
296
296
|
|
297
297
|
it "returns rows where the column contains the term in the query" do
|
298
|
-
included = ModelWithPgSearch.create!(:
|
299
|
-
excluded = ModelWithPgSearch.create!(:
|
298
|
+
included = ModelWithPgSearch.create!(content: 'foo')
|
299
|
+
excluded = ModelWithPgSearch.create!(content: 'bar')
|
300
300
|
|
301
301
|
results = ModelWithPgSearch.search_content('foo')
|
302
302
|
expect(results).to include(included)
|
@@ -304,24 +304,24 @@ describe "an Active Record model which includes PgSearch" do
|
|
304
304
|
end
|
305
305
|
|
306
306
|
it "returns the correct count" do
|
307
|
-
ModelWithPgSearch.create!(:
|
308
|
-
ModelWithPgSearch.create!(:
|
307
|
+
ModelWithPgSearch.create!(content: 'foo')
|
308
|
+
ModelWithPgSearch.create!(content: 'bar')
|
309
309
|
|
310
310
|
results = ModelWithPgSearch.search_content('foo')
|
311
311
|
expect(results.count).to eq 1
|
312
312
|
end
|
313
313
|
|
314
314
|
it "returns the correct count(:all)" do
|
315
|
-
ModelWithPgSearch.create!(:
|
316
|
-
ModelWithPgSearch.create!(:
|
315
|
+
ModelWithPgSearch.create!(content: 'foo')
|
316
|
+
ModelWithPgSearch.create!(content: 'bar')
|
317
317
|
|
318
318
|
results = ModelWithPgSearch.search_content('foo')
|
319
319
|
expect(results.count(:all)).to eq 1
|
320
320
|
end
|
321
321
|
|
322
322
|
it "supports #select" do
|
323
|
-
record = ModelWithPgSearch.create!(:
|
324
|
-
other_record = ModelWithPgSearch.create!(:
|
323
|
+
record = ModelWithPgSearch.create!(content: 'foo')
|
324
|
+
other_record = ModelWithPgSearch.create!(content: 'bar')
|
325
325
|
|
326
326
|
records_with_only_id = ModelWithPgSearch.search_content('foo').select('id')
|
327
327
|
expect(records_with_only_id.length).to eq 1
|
@@ -332,16 +332,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
332
332
|
end
|
333
333
|
|
334
334
|
it "supports #pluck" do
|
335
|
-
record = ModelWithPgSearch.create!(:
|
336
|
-
other_record = ModelWithPgSearch.create!(:
|
335
|
+
record = ModelWithPgSearch.create!(content: 'foo')
|
336
|
+
other_record = ModelWithPgSearch.create!(content: 'bar')
|
337
337
|
|
338
338
|
ids = ModelWithPgSearch.search_content('foo').pluck('id')
|
339
339
|
expect(ids).to eq [record.id]
|
340
340
|
end
|
341
341
|
|
342
342
|
it "supports adding where clauses using the pg_search.rank" do
|
343
|
-
once = ModelWithPgSearch.create!(:
|
344
|
-
twice = ModelWithPgSearch.create!(:
|
343
|
+
once = ModelWithPgSearch.create!(content: 'foo bar')
|
344
|
+
twice = ModelWithPgSearch.create!(content: 'foo foo')
|
345
345
|
|
346
346
|
records = ModelWithPgSearch.search_content('foo')
|
347
347
|
.where("#{PgSearch::Configuration.alias(ModelWithPgSearch.table_name)}.rank > 0.07")
|
@@ -350,9 +350,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
350
350
|
end
|
351
351
|
|
352
352
|
it "returns rows where the column contains all the terms in the query in any order" do
|
353
|
-
included = [ModelWithPgSearch.create!(:
|
354
|
-
ModelWithPgSearch.create!(:
|
355
|
-
excluded = ModelWithPgSearch.create!(:
|
353
|
+
included = [ModelWithPgSearch.create!(content: 'foo bar'),
|
354
|
+
ModelWithPgSearch.create!(content: 'bar foo')]
|
355
|
+
excluded = ModelWithPgSearch.create!(content: 'foo')
|
356
356
|
|
357
357
|
results = ModelWithPgSearch.search_content('foo bar')
|
358
358
|
expect(results).to match_array(included)
|
@@ -360,8 +360,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
360
360
|
end
|
361
361
|
|
362
362
|
it "returns rows that match the query but not its case" do
|
363
|
-
included = [ModelWithPgSearch.create!(:
|
364
|
-
ModelWithPgSearch.create!(:
|
363
|
+
included = [ModelWithPgSearch.create!(content: "foo"),
|
364
|
+
ModelWithPgSearch.create!(content: "FOO")]
|
365
365
|
|
366
366
|
results = ModelWithPgSearch.search_content("Foo")
|
367
367
|
expect(results).to match_array(included)
|
@@ -371,8 +371,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
371
371
|
# \303\241 is a with acute accent
|
372
372
|
# \303\251 is e with acute accent
|
373
373
|
|
374
|
-
included = ModelWithPgSearch.create!(:
|
375
|
-
excluded = ModelWithPgSearch.create!(:
|
374
|
+
included = ModelWithPgSearch.create!(content: "abcd\303\251f")
|
375
|
+
excluded = ModelWithPgSearch.create!(content: "\303\241bcdef")
|
376
376
|
|
377
377
|
results = ModelWithPgSearch.search_content("abcd\303\251f")
|
378
378
|
expect(results).to eq([included])
|
@@ -380,8 +380,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
380
380
|
end
|
381
381
|
|
382
382
|
it "returns rows that match the query but not rows that are prefixed by the query" do
|
383
|
-
included = ModelWithPgSearch.create!(:
|
384
|
-
excluded = ModelWithPgSearch.create!(:
|
383
|
+
included = ModelWithPgSearch.create!(content: 'pre')
|
384
|
+
excluded = ModelWithPgSearch.create!(content: 'prefix')
|
385
385
|
|
386
386
|
results = ModelWithPgSearch.search_content("pre")
|
387
387
|
expect(results).to eq([included])
|
@@ -389,17 +389,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
389
389
|
end
|
390
390
|
|
391
391
|
it "returns rows that match the query exactly and not those that match the query when stemmed by the default english dictionary" do
|
392
|
-
included = ModelWithPgSearch.create!(:
|
393
|
-
excluded = [ModelWithPgSearch.create!(:
|
394
|
-
ModelWithPgSearch.create!(:
|
392
|
+
included = ModelWithPgSearch.create!(content: "jumped")
|
393
|
+
excluded = [ModelWithPgSearch.create!(content: "jump"),
|
394
|
+
ModelWithPgSearch.create!(content: "jumping")]
|
395
395
|
|
396
396
|
results = ModelWithPgSearch.search_content("jumped")
|
397
397
|
expect(results).to eq([included])
|
398
398
|
end
|
399
399
|
|
400
400
|
it "returns rows that match sorted by rank" do
|
401
|
-
loser = ModelWithPgSearch.create!(:
|
402
|
-
winner = ModelWithPgSearch.create!(:
|
401
|
+
loser = ModelWithPgSearch.create!(content: 'foo')
|
402
|
+
winner = ModelWithPgSearch.create!(content: 'foo foo')
|
403
403
|
|
404
404
|
results = ModelWithPgSearch.search_content("foo").with_pg_search_rank
|
405
405
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
@@ -409,8 +409,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
409
409
|
it 'allows pg_search_rank along with a join' do
|
410
410
|
parent_1 = ParentModel.create!(id: 98)
|
411
411
|
parent_2 = ParentModel.create!(id: 99)
|
412
|
-
loser = ModelWithPgSearch.create!(:
|
413
|
-
winner = ModelWithPgSearch.create!(:
|
412
|
+
loser = ModelWithPgSearch.create!(content: 'foo', parent_model: parent_2)
|
413
|
+
winner = ModelWithPgSearch.create!(content: 'foo foo', parent_model: parent_1)
|
414
414
|
|
415
415
|
results = ModelWithPgSearch.joins(:parent_model).merge(ParentModel.active).search_content("foo").with_pg_search_rank
|
416
416
|
expect(results.map(&:id)).to eq [winner.id, loser.id]
|
@@ -419,8 +419,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
419
419
|
end
|
420
420
|
|
421
421
|
it "returns results that match sorted by primary key for records that rank the same" do
|
422
|
-
sorted_results = [ModelWithPgSearch.create!(:
|
423
|
-
ModelWithPgSearch.create!(:
|
422
|
+
sorted_results = [ModelWithPgSearch.create!(content: 'foo'),
|
423
|
+
ModelWithPgSearch.create!(content: 'foo')].sort_by(&:id)
|
424
424
|
|
425
425
|
results = ModelWithPgSearch.search_content("foo")
|
426
426
|
expect(results).to eq(sorted_results)
|
@@ -428,13 +428,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
428
428
|
|
429
429
|
it "returns results that match a query with multiple space-separated search terms" do
|
430
430
|
included = [
|
431
|
-
ModelWithPgSearch.create!(:
|
432
|
-
ModelWithPgSearch.create!(:
|
433
|
-
ModelWithPgSearch.create!(:
|
431
|
+
ModelWithPgSearch.create!(content: 'foo bar'),
|
432
|
+
ModelWithPgSearch.create!(content: 'bar foo'),
|
433
|
+
ModelWithPgSearch.create!(content: 'bar foo baz')
|
434
434
|
]
|
435
435
|
excluded = [
|
436
|
-
ModelWithPgSearch.create!(:
|
437
|
-
ModelWithPgSearch.create!(:
|
436
|
+
ModelWithPgSearch.create!(content: 'foo'),
|
437
|
+
ModelWithPgSearch.create!(content: 'foo baz')
|
438
438
|
]
|
439
439
|
|
440
440
|
results = ModelWithPgSearch.search_content('foo bar')
|
@@ -443,15 +443,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
443
443
|
end
|
444
444
|
|
445
445
|
it "returns rows that match a query with characters that are invalid in a tsquery expression" do
|
446
|
-
included = ModelWithPgSearch.create!(:
|
446
|
+
included = ModelWithPgSearch.create!(content: "(:Foo.) Bar?, \\")
|
447
447
|
|
448
448
|
results = ModelWithPgSearch.search_content("foo :bar .,?() \\")
|
449
449
|
expect(results).to eq([included])
|
450
450
|
end
|
451
451
|
|
452
452
|
it "accepts non-string queries and calls #to_s on them" do
|
453
|
-
foo = ModelWithPgSearch.create!(:
|
454
|
-
not_a_string = double(:
|
453
|
+
foo = ModelWithPgSearch.create!(content: "foo")
|
454
|
+
not_a_string = double(to_s: "foo")
|
455
455
|
expect(ModelWithPgSearch.search_content(not_a_string)).to eq([foo])
|
456
456
|
end
|
457
457
|
|
@@ -467,7 +467,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
467
467
|
# WARNING: searching timestamps is not something PostgreSQL
|
468
468
|
# full-text search is good at. Use at your own risk.
|
469
469
|
pg_search_scope :search_timestamps,
|
470
|
-
:
|
470
|
+
against: %i[created_at updated_at]
|
471
471
|
end
|
472
472
|
end
|
473
473
|
|
@@ -483,17 +483,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
483
483
|
|
484
484
|
context "against multiple columns" do
|
485
485
|
before do
|
486
|
-
ModelWithPgSearch.pg_search_scope :search_title_and_content, :
|
486
|
+
ModelWithPgSearch.pg_search_scope :search_title_and_content, against: %i[title content]
|
487
487
|
end
|
488
488
|
|
489
489
|
it "returns rows whose columns contain all of the terms in the query across columns" do
|
490
490
|
included = [
|
491
|
-
ModelWithPgSearch.create!(:
|
492
|
-
ModelWithPgSearch.create!(:
|
491
|
+
ModelWithPgSearch.create!(title: 'foo', content: 'bar'),
|
492
|
+
ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
493
493
|
]
|
494
494
|
excluded = [
|
495
|
-
ModelWithPgSearch.create!(:
|
496
|
-
ModelWithPgSearch.create!(:
|
495
|
+
ModelWithPgSearch.create!(title: 'foo', content: 'foo'),
|
496
|
+
ModelWithPgSearch.create!(title: 'bar', content: 'bar')
|
497
497
|
]
|
498
498
|
|
499
499
|
results = ModelWithPgSearch.search_title_and_content('foo bar')
|
@@ -505,8 +505,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
505
505
|
end
|
506
506
|
|
507
507
|
it "returns rows where at one column contains all of the terms in the query and another does not" do
|
508
|
-
in_title = ModelWithPgSearch.create!(:
|
509
|
-
in_content = ModelWithPgSearch.create!(:
|
508
|
+
in_title = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
509
|
+
in_content = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
510
510
|
|
511
511
|
results = ModelWithPgSearch.search_title_and_content('foo')
|
512
512
|
expect(results).to match_array([in_title, in_content])
|
@@ -514,7 +514,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
514
514
|
|
515
515
|
# Searching with a NULL column will prevent any matches unless we coalesce it.
|
516
516
|
it "returns rows where at one column contains all of the terms in the query and another is NULL" do
|
517
|
-
included = ModelWithPgSearch.create!(:
|
517
|
+
included = ModelWithPgSearch.create!(title: 'foo', content: nil)
|
518
518
|
results = ModelWithPgSearch.search_title_and_content('foo')
|
519
519
|
expect(results).to eq([included])
|
520
520
|
end
|
@@ -522,31 +522,31 @@ describe "an Active Record model which includes PgSearch" do
|
|
522
522
|
|
523
523
|
context "using trigram" do
|
524
524
|
before do
|
525
|
-
ModelWithPgSearch.pg_search_scope :with_trigrams, :
|
525
|
+
ModelWithPgSearch.pg_search_scope :with_trigrams, against: %i[title content], using: :trigram
|
526
526
|
end
|
527
527
|
|
528
528
|
it "returns rows where one searchable column and the query share enough trigrams" do
|
529
|
-
included = ModelWithPgSearch.create!(:
|
529
|
+
included = ModelWithPgSearch.create!(title: 'abcdefghijkl', content: nil)
|
530
530
|
results = ModelWithPgSearch.with_trigrams('cdefhijkl')
|
531
531
|
expect(results).to eq([included])
|
532
532
|
end
|
533
533
|
|
534
534
|
it "returns rows where multiple searchable columns and the query share enough trigrams" do
|
535
|
-
included = ModelWithPgSearch.create!(:
|
535
|
+
included = ModelWithPgSearch.create!(title: 'abcdef', content: 'ghijkl')
|
536
536
|
results = ModelWithPgSearch.with_trigrams('cdefhijkl')
|
537
537
|
expect(results).to eq([included])
|
538
538
|
end
|
539
539
|
|
540
540
|
context "when a threshold is specified" do
|
541
541
|
before do
|
542
|
-
ModelWithPgSearch.pg_search_scope :with_strict_trigrams, :
|
543
|
-
ModelWithPgSearch.pg_search_scope :with_permissive_trigrams, :
|
542
|
+
ModelWithPgSearch.pg_search_scope :with_strict_trigrams, against: %i[title content], using: { trigram: { threshold: 0.5 } }
|
543
|
+
ModelWithPgSearch.pg_search_scope :with_permissive_trigrams, against: %i[title content], using: { trigram: { threshold: 0.1 } }
|
544
544
|
end
|
545
545
|
|
546
546
|
it "uses the threshold in the trigram expression" do
|
547
|
-
low_similarity = ModelWithPgSearch.create!(:
|
548
|
-
medium_similarity = ModelWithPgSearch.create!(:
|
549
|
-
high_similarity = ModelWithPgSearch.create!(:
|
547
|
+
low_similarity = ModelWithPgSearch.create!(title: "a")
|
548
|
+
medium_similarity = ModelWithPgSearch.create!(title: "abc")
|
549
|
+
high_similarity = ModelWithPgSearch.create!(title: "abcdefghijkl")
|
550
550
|
|
551
551
|
results = ModelWithPgSearch.with_strict_trigrams("abcdefg")
|
552
552
|
expect(results).to include(high_similarity)
|
@@ -565,16 +565,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
565
565
|
context "using tsearch" do
|
566
566
|
before do
|
567
567
|
ModelWithPgSearch.pg_search_scope :search_title_with_prefixes,
|
568
|
-
:
|
569
|
-
:
|
570
|
-
:
|
568
|
+
against: :title,
|
569
|
+
using: {
|
570
|
+
tsearch: { prefix: true }
|
571
571
|
}
|
572
572
|
end
|
573
573
|
|
574
|
-
context "with :
|
574
|
+
context "with prefix: true" do
|
575
575
|
it "returns rows that match the query and that are prefixed by the query" do
|
576
|
-
included = ModelWithPgSearch.create!(:
|
577
|
-
excluded = ModelWithPgSearch.create!(:
|
576
|
+
included = ModelWithPgSearch.create!(title: 'prefix')
|
577
|
+
excluded = ModelWithPgSearch.create!(title: 'postfix')
|
578
578
|
|
579
579
|
results = ModelWithPgSearch.search_title_with_prefixes("pre")
|
580
580
|
expect(results).to eq([included])
|
@@ -582,8 +582,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
582
582
|
end
|
583
583
|
|
584
584
|
it "returns rows that match the query when the query has a hyphen" do
|
585
|
-
included = ModelWithPgSearch.create!(:
|
586
|
-
excluded = ModelWithPgSearch.create!(:
|
585
|
+
included = ModelWithPgSearch.create!(title: 'foo-bar')
|
586
|
+
excluded = ModelWithPgSearch.create!(title: 'foo bar')
|
587
587
|
|
588
588
|
results = ModelWithPgSearch.search_title_with_prefixes("foo-bar")
|
589
589
|
expect(results).to include(included)
|
@@ -594,16 +594,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
594
594
|
context "with the english dictionary" do
|
595
595
|
before do
|
596
596
|
ModelWithPgSearch.pg_search_scope :search_content_with_english,
|
597
|
-
:
|
598
|
-
:
|
599
|
-
:
|
597
|
+
against: :content,
|
598
|
+
using: {
|
599
|
+
tsearch: { dictionary: :english }
|
600
600
|
}
|
601
601
|
end
|
602
602
|
|
603
603
|
it "returns rows that match the query when stemmed by the english dictionary" do
|
604
|
-
included = [ModelWithPgSearch.create!(:
|
605
|
-
ModelWithPgSearch.create!(:
|
606
|
-
ModelWithPgSearch.create!(:
|
604
|
+
included = [ModelWithPgSearch.create!(content: "jump"),
|
605
|
+
ModelWithPgSearch.create!(content: "jumped"),
|
606
|
+
ModelWithPgSearch.create!(content: "jumping")]
|
607
607
|
|
608
608
|
results = ModelWithPgSearch.search_content_with_english("jump")
|
609
609
|
expect(results).to match_array(included)
|
@@ -613,14 +613,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
613
613
|
describe "highlighting" do
|
614
614
|
before do
|
615
615
|
["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
|
616
|
-
ModelWithPgSearch.create! :
|
616
|
+
ModelWithPgSearch.create! content: name
|
617
617
|
end
|
618
618
|
end
|
619
619
|
|
620
620
|
context "with highlight turned on" do
|
621
621
|
before do
|
622
622
|
ModelWithPgSearch.pg_search_scope :search_content,
|
623
|
-
:
|
623
|
+
against: :content
|
624
624
|
end
|
625
625
|
|
626
626
|
it "adds a #pg_search_highlight method to each returned model record" do
|
@@ -638,19 +638,19 @@ describe "an Active Record model which includes PgSearch" do
|
|
638
638
|
|
639
639
|
context "with custom highlighting options" do
|
640
640
|
before do
|
641
|
-
ModelWithPgSearch.create! :
|
641
|
+
ModelWithPgSearch.create! content: "#{'text ' * 2}Let #{'text ' * 2}Let #{'text ' * 2}"
|
642
642
|
|
643
643
|
ModelWithPgSearch.pg_search_scope :search_content,
|
644
|
-
:
|
645
|
-
:
|
646
|
-
:
|
647
|
-
:
|
648
|
-
:
|
649
|
-
:
|
650
|
-
:
|
651
|
-
:
|
652
|
-
:
|
653
|
-
:
|
644
|
+
against: :content,
|
645
|
+
using: {
|
646
|
+
tsearch: {
|
647
|
+
highlight: {
|
648
|
+
StartSel: '<mark class="highlight">',
|
649
|
+
StopSel: '</mark>',
|
650
|
+
FragmentDelimiter: '<delim class="my_delim">',
|
651
|
+
MaxFragments: 2,
|
652
|
+
MaxWords: 2,
|
653
|
+
MinWords: 1
|
654
654
|
}
|
655
655
|
}
|
656
656
|
}
|
@@ -667,12 +667,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
667
667
|
describe "ranking" do
|
668
668
|
before do
|
669
669
|
["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
|
670
|
-
ModelWithPgSearch.create! :
|
670
|
+
ModelWithPgSearch.create! content: name
|
671
671
|
end
|
672
672
|
end
|
673
673
|
|
674
674
|
it "adds a #pg_search_rank method to each returned model record" do
|
675
|
-
ModelWithPgSearch.pg_search_scope :search_content, :
|
675
|
+
ModelWithPgSearch.pg_search_scope :search_content, against: :content
|
676
676
|
|
677
677
|
result = ModelWithPgSearch.search_content("Strip Down").with_pg_search_rank.first
|
678
678
|
|
@@ -682,9 +682,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
682
682
|
context "with a normalization specified" do
|
683
683
|
before do
|
684
684
|
ModelWithPgSearch.pg_search_scope :search_content_with_normalization,
|
685
|
-
:
|
686
|
-
:
|
687
|
-
:
|
685
|
+
against: :content,
|
686
|
+
using: {
|
687
|
+
tsearch: { normalization: 2 }
|
688
688
|
}
|
689
689
|
end
|
690
690
|
|
@@ -699,8 +699,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
699
699
|
context "with no normalization" do
|
700
700
|
before do
|
701
701
|
ModelWithPgSearch.pg_search_scope :search_content_without_normalization,
|
702
|
-
:
|
703
|
-
:
|
702
|
+
against: :content,
|
703
|
+
using: :tsearch
|
704
704
|
end
|
705
705
|
|
706
706
|
it "ranks the results equally" do
|
@@ -715,12 +715,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
715
715
|
context "against columns ranked with arrays" do
|
716
716
|
before do
|
717
717
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_array_of_arrays,
|
718
|
-
:
|
718
|
+
against: [[:content, 'B'], [:title, 'A']]
|
719
719
|
end
|
720
720
|
|
721
721
|
it "returns results sorted by weighted rank" do
|
722
|
-
loser = ModelWithPgSearch.create!(:
|
723
|
-
winner = ModelWithPgSearch.create!(:
|
722
|
+
loser = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
723
|
+
winner = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
724
724
|
|
725
725
|
results = ModelWithPgSearch.search_weighted_by_array_of_arrays('foo').with_pg_search_rank
|
726
726
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
@@ -731,12 +731,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
731
731
|
context "against columns ranked with a hash" do
|
732
732
|
before do
|
733
733
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_hash,
|
734
|
-
:
|
734
|
+
against: { content: 'B', title: 'A' }
|
735
735
|
end
|
736
736
|
|
737
737
|
it "returns results sorted by weighted rank" do
|
738
|
-
loser = ModelWithPgSearch.create!(:
|
739
|
-
winner = ModelWithPgSearch.create!(:
|
738
|
+
loser = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
739
|
+
winner = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
740
740
|
|
741
741
|
results = ModelWithPgSearch.search_weighted_by_hash('foo').with_pg_search_rank
|
742
742
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
@@ -747,12 +747,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
747
747
|
context "against columns of which only some are ranked" do
|
748
748
|
before do
|
749
749
|
ModelWithPgSearch.pg_search_scope :search_weighted,
|
750
|
-
:
|
750
|
+
against: [:content, [:title, 'A']]
|
751
751
|
end
|
752
752
|
|
753
753
|
it "returns results sorted by weighted rank using an implied low rank for unranked columns" do
|
754
|
-
loser = ModelWithPgSearch.create!(:
|
755
|
-
winner = ModelWithPgSearch.create!(:
|
754
|
+
loser = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
755
|
+
winner = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
756
756
|
|
757
757
|
results = ModelWithPgSearch.search_weighted('foo').with_pg_search_rank
|
758
758
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
@@ -763,17 +763,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
763
763
|
context "searching any_word option" do
|
764
764
|
before do
|
765
765
|
ModelWithPgSearch.pg_search_scope :search_title_with_any_word,
|
766
|
-
:
|
767
|
-
:
|
768
|
-
:
|
766
|
+
against: :title,
|
767
|
+
using: {
|
768
|
+
tsearch: { any_word: true }
|
769
769
|
}
|
770
770
|
|
771
771
|
ModelWithPgSearch.pg_search_scope :search_title_with_all_words,
|
772
|
-
:
|
772
|
+
against: :title
|
773
773
|
end
|
774
774
|
|
775
775
|
it "returns all results containing any word in their title" do
|
776
|
-
numbers = %w[one two three four].map { |number| ModelWithPgSearch.create!(:
|
776
|
+
numbers = %w[one two three four].map { |number| ModelWithPgSearch.create!(title: number) }
|
777
777
|
|
778
778
|
results = ModelWithPgSearch.search_title_with_any_word("one two three four")
|
779
779
|
|
@@ -788,21 +788,21 @@ describe "an Active Record model which includes PgSearch" do
|
|
788
788
|
context "with :negation" do
|
789
789
|
before do
|
790
790
|
ModelWithPgSearch.pg_search_scope :search_with_negation,
|
791
|
-
:
|
792
|
-
:
|
793
|
-
:
|
791
|
+
against: :title,
|
792
|
+
using: {
|
793
|
+
tsearch: { negation: true }
|
794
794
|
}
|
795
795
|
end
|
796
796
|
|
797
797
|
it "doesn't return results that contain terms prepended with '!'" do
|
798
798
|
included = [
|
799
|
-
ModelWithPgSearch.create!(:
|
800
|
-
ModelWithPgSearch.create!(:
|
799
|
+
ModelWithPgSearch.create!(title: "one fish"),
|
800
|
+
ModelWithPgSearch.create!(title: "two fish")
|
801
801
|
]
|
802
802
|
|
803
803
|
excluded = [
|
804
|
-
ModelWithPgSearch.create!(:
|
805
|
-
ModelWithPgSearch.create!(:
|
804
|
+
ModelWithPgSearch.create!(title: "red fish"),
|
805
|
+
ModelWithPgSearch.create!(title: "blue fish")
|
806
806
|
]
|
807
807
|
|
808
808
|
results = ModelWithPgSearch.search_with_negation("fish !red !blue")
|
@@ -815,19 +815,19 @@ describe "an Active Record model which includes PgSearch" do
|
|
815
815
|
context "without :negation" do
|
816
816
|
before do
|
817
817
|
ModelWithPgSearch.pg_search_scope :search_without_negation,
|
818
|
-
:
|
819
|
-
:
|
820
|
-
:
|
818
|
+
against: :title,
|
819
|
+
using: {
|
820
|
+
tsearch: {}
|
821
821
|
}
|
822
822
|
end
|
823
823
|
|
824
824
|
it "return results that contain terms prepended with '!'" do
|
825
825
|
included = [
|
826
|
-
ModelWithPgSearch.create!(:
|
826
|
+
ModelWithPgSearch.create!(title: "!bang")
|
827
827
|
]
|
828
828
|
|
829
829
|
excluded = [
|
830
|
-
ModelWithPgSearch.create!(:
|
830
|
+
ModelWithPgSearch.create!(title: "?question")
|
831
831
|
]
|
832
832
|
|
833
833
|
results = ModelWithPgSearch.search_without_negation("!bang")
|
@@ -841,27 +841,27 @@ describe "an Active Record model which includes PgSearch" do
|
|
841
841
|
context "using dmetaphone" do
|
842
842
|
before do
|
843
843
|
ModelWithPgSearch.pg_search_scope :with_dmetaphones,
|
844
|
-
:
|
845
|
-
:
|
844
|
+
against: %i[title content],
|
845
|
+
using: :dmetaphone
|
846
846
|
end
|
847
847
|
|
848
848
|
it "returns rows where one searchable column and the query share enough dmetaphones" do
|
849
|
-
included = ModelWithPgSearch.create!(:
|
850
|
-
excluded = ModelWithPgSearch.create!(:
|
849
|
+
included = ModelWithPgSearch.create!(title: 'Geoff', content: nil)
|
850
|
+
excluded = ModelWithPgSearch.create!(title: 'Bob', content: nil)
|
851
851
|
results = ModelWithPgSearch.with_dmetaphones('Jeff')
|
852
852
|
expect(results).to eq([included])
|
853
853
|
end
|
854
854
|
|
855
855
|
it "returns rows where multiple searchable columns and the query share enough dmetaphones" do
|
856
|
-
included = ModelWithPgSearch.create!(:
|
857
|
-
excluded = ModelWithPgSearch.create!(:
|
856
|
+
included = ModelWithPgSearch.create!(title: 'Geoff', content: 'George')
|
857
|
+
excluded = ModelWithPgSearch.create!(title: 'Bob', content: 'Jones')
|
858
858
|
results = ModelWithPgSearch.with_dmetaphones('Jeff Jorge')
|
859
859
|
expect(results).to eq([included])
|
860
860
|
end
|
861
861
|
|
862
862
|
it "returns rows that match dmetaphones that are English stopwords" do
|
863
|
-
included = ModelWithPgSearch.create!(:
|
864
|
-
excluded = ModelWithPgSearch.create!(:
|
863
|
+
included = ModelWithPgSearch.create!(title: 'White', content: nil)
|
864
|
+
excluded = ModelWithPgSearch.create!(title: 'Black', content: nil)
|
865
865
|
results = ModelWithPgSearch.with_dmetaphones('Wight')
|
866
866
|
expect(results).to eq([included])
|
867
867
|
end
|
@@ -869,8 +869,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
869
869
|
it "can handle terms that do not have a dmetaphone equivalent" do
|
870
870
|
term_with_blank_metaphone = "w"
|
871
871
|
|
872
|
-
included = ModelWithPgSearch.create!(:
|
873
|
-
excluded = ModelWithPgSearch.create!(:
|
872
|
+
included = ModelWithPgSearch.create!(title: 'White', content: nil)
|
873
|
+
excluded = ModelWithPgSearch.create!(title: 'Black', content: nil)
|
874
874
|
|
875
875
|
results = ModelWithPgSearch.with_dmetaphones('Wight W')
|
876
876
|
expect(results).to eq([included])
|
@@ -880,39 +880,39 @@ describe "an Active Record model which includes PgSearch" do
|
|
880
880
|
context "using multiple features" do
|
881
881
|
before do
|
882
882
|
ModelWithPgSearch.pg_search_scope :with_tsearch,
|
883
|
-
:
|
884
|
-
:
|
885
|
-
[:tsearch, { :
|
883
|
+
against: :title,
|
884
|
+
using: [
|
885
|
+
[:tsearch, { dictionary: 'english' }]
|
886
886
|
]
|
887
887
|
|
888
888
|
ModelWithPgSearch.pg_search_scope :with_trigram,
|
889
|
-
:
|
890
|
-
:
|
889
|
+
against: :title,
|
890
|
+
using: :trigram
|
891
891
|
|
892
892
|
ModelWithPgSearch.pg_search_scope :with_trigram_and_ignoring_accents,
|
893
|
-
:
|
894
|
-
:
|
895
|
-
:
|
893
|
+
against: :title,
|
894
|
+
ignoring: :accents,
|
895
|
+
using: :trigram
|
896
896
|
|
897
897
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram,
|
898
|
-
:
|
899
|
-
:
|
900
|
-
[:tsearch, { :
|
898
|
+
against: :title,
|
899
|
+
using: [
|
900
|
+
[:tsearch, { dictionary: 'english' }],
|
901
901
|
:trigram
|
902
902
|
]
|
903
903
|
|
904
904
|
ModelWithPgSearch.pg_search_scope :complex_search,
|
905
|
-
:
|
906
|
-
:
|
907
|
-
:
|
908
|
-
:
|
909
|
-
:
|
910
|
-
:
|
905
|
+
against: %i[content title],
|
906
|
+
ignoring: :accents,
|
907
|
+
using: {
|
908
|
+
tsearch: { dictionary: 'english' },
|
909
|
+
dmetaphone: {},
|
910
|
+
trigram: {}
|
911
911
|
}
|
912
912
|
end
|
913
913
|
|
914
914
|
it "returns rows that match using any of the features" do
|
915
|
-
record = ModelWithPgSearch.create!(:
|
915
|
+
record = ModelWithPgSearch.create!(title: "tiling is grouty")
|
916
916
|
|
917
917
|
# matches trigram only
|
918
918
|
trigram_query = "ling is grouty"
|
@@ -951,21 +951,21 @@ describe "an Active Record model which includes PgSearch" do
|
|
951
951
|
|
952
952
|
context "with feature-specific configuration" do
|
953
953
|
before do
|
954
|
-
@tsearch_config = tsearch_config = { :
|
955
|
-
@trigram_config = trigram_config = { :
|
954
|
+
@tsearch_config = tsearch_config = { dictionary: 'english' }
|
955
|
+
@trigram_config = trigram_config = { foo: 'bar' }
|
956
956
|
|
957
957
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram_using_hash,
|
958
|
-
:
|
959
|
-
:
|
960
|
-
:
|
961
|
-
:
|
958
|
+
against: :title,
|
959
|
+
using: {
|
960
|
+
tsearch: tsearch_config,
|
961
|
+
trigram: trigram_config
|
962
962
|
}
|
963
963
|
end
|
964
964
|
|
965
965
|
it "should pass the custom configuration down to the specified feature" do
|
966
966
|
stub_feature = double(
|
967
|
-
:
|
968
|
-
:
|
967
|
+
conditions: Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
968
|
+
rank: Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
969
969
|
)
|
970
970
|
|
971
971
|
expect(PgSearch::Features::TSearch).to receive(:new).with(anything, @tsearch_config, anything, anything, anything).at_least(:once).and_return(stub_feature)
|
@@ -1013,11 +1013,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
1013
1013
|
unexpected.comments.create(body: 'commentwo')
|
1014
1014
|
|
1015
1015
|
Post.pg_search_scope :search_by_content_with_tsvector,
|
1016
|
-
:
|
1017
|
-
:
|
1018
|
-
:
|
1019
|
-
:
|
1020
|
-
:
|
1016
|
+
associated_against: { comments: [:body] },
|
1017
|
+
using: {
|
1018
|
+
tsearch: {
|
1019
|
+
tsvector_column: 'content_tsvector',
|
1020
|
+
dictionary: 'english'
|
1021
1021
|
}
|
1022
1022
|
}
|
1023
1023
|
end
|
@@ -1041,11 +1041,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
1041
1041
|
include PgSearch
|
1042
1042
|
|
1043
1043
|
pg_search_scope :search_by_multiple_tsvector_columns,
|
1044
|
-
:
|
1045
|
-
:
|
1046
|
-
:
|
1047
|
-
:
|
1048
|
-
:
|
1044
|
+
against: ['content', 'message'],
|
1045
|
+
using: {
|
1046
|
+
tsearch: {
|
1047
|
+
tsvector_column: ['content_tsvector', 'message_tsvector'],
|
1048
|
+
dictionary: 'english'
|
1049
1049
|
}
|
1050
1050
|
}
|
1051
1051
|
end
|
@@ -1069,8 +1069,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
1069
1069
|
model { include PgSearch }
|
1070
1070
|
end
|
1071
1071
|
|
1072
|
-
let!(:expected) { ModelWithTsvector.create!(:
|
1073
|
-
let!(:unexpected) { ModelWithTsvector.create!(:
|
1072
|
+
let!(:expected) { ModelWithTsvector.create!(content: 'tiling is grouty') }
|
1073
|
+
let!(:unexpected) { ModelWithTsvector.create!(content: 'longcat is looooooooong') }
|
1074
1074
|
|
1075
1075
|
before do
|
1076
1076
|
ActiveRecord::Base.connection.execute <<-SQL.strip_heredoc
|
@@ -1079,11 +1079,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
1079
1079
|
SQL
|
1080
1080
|
|
1081
1081
|
ModelWithTsvector.pg_search_scope :search_by_content_with_tsvector,
|
1082
|
-
:
|
1083
|
-
:
|
1084
|
-
:
|
1085
|
-
:
|
1086
|
-
:
|
1082
|
+
against: :content,
|
1083
|
+
using: {
|
1084
|
+
tsearch: {
|
1085
|
+
tsvector_column: 'content_tsvector',
|
1086
|
+
dictionary: 'english'
|
1087
1087
|
}
|
1088
1088
|
}
|
1089
1089
|
end
|
@@ -1119,15 +1119,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
1119
1119
|
context "ignoring accents" do
|
1120
1120
|
before do
|
1121
1121
|
ModelWithPgSearch.pg_search_scope :search_title_without_accents,
|
1122
|
-
:
|
1123
|
-
:
|
1122
|
+
against: :title,
|
1123
|
+
ignoring: :accents
|
1124
1124
|
end
|
1125
1125
|
|
1126
1126
|
it "returns rows that match the query but not its accents" do
|
1127
1127
|
# \303\241 is a with acute accent
|
1128
1128
|
# \303\251 is e with acute accent
|
1129
1129
|
|
1130
|
-
included = ModelWithPgSearch.create!(:
|
1130
|
+
included = ModelWithPgSearch.create!(title: "\303\241bcdef")
|
1131
1131
|
|
1132
1132
|
results = ModelWithPgSearch.search_title_without_accents("abcd\303\251f")
|
1133
1133
|
expect(results).to eq([included])
|
@@ -1135,7 +1135,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
1135
1135
|
|
1136
1136
|
context "when the query includes accents" do
|
1137
1137
|
it "does not create an erroneous tsquery expression" do
|
1138
|
-
included = ModelWithPgSearch.create!(:
|
1138
|
+
included = ModelWithPgSearch.create!(title: "Weird L‘Content")
|
1139
1139
|
|
1140
1140
|
results = ModelWithPgSearch.search_title_without_accents("L‘Content")
|
1141
1141
|
expect(results).to eq([included])
|
@@ -1146,25 +1146,25 @@ describe "an Active Record model which includes PgSearch" do
|
|
1146
1146
|
context "when passed a :ranked_by expression" do
|
1147
1147
|
before do
|
1148
1148
|
ModelWithPgSearch.pg_search_scope :search_content_with_default_rank,
|
1149
|
-
:
|
1149
|
+
against: :content
|
1150
1150
|
|
1151
1151
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank,
|
1152
|
-
:
|
1153
|
-
:
|
1152
|
+
against: :content,
|
1153
|
+
ranked_by: "importance"
|
1154
1154
|
|
1155
1155
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank_multiplier,
|
1156
|
-
:
|
1157
|
-
:
|
1156
|
+
against: :content,
|
1157
|
+
ranked_by: ":tsearch * importance"
|
1158
1158
|
end
|
1159
1159
|
|
1160
1160
|
it "should return records with a rank attribute equal to the :ranked_by expression" do
|
1161
|
-
ModelWithPgSearch.create!(:
|
1161
|
+
ModelWithPgSearch.create!(content: 'foo', importance: 10)
|
1162
1162
|
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo").with_pg_search_rank
|
1163
1163
|
expect(results.first.pg_search_rank).to eq(10)
|
1164
1164
|
end
|
1165
1165
|
|
1166
1166
|
it "should substitute :tsearch with the tsearch rank expression in the :ranked_by expression" do
|
1167
|
-
ModelWithPgSearch.create!(:
|
1167
|
+
ModelWithPgSearch.create!(content: 'foo', importance: 10)
|
1168
1168
|
|
1169
1169
|
tsearch_result =
|
1170
1170
|
ModelWithPgSearch.search_content_with_default_rank("foo").with_pg_search_rank.first
|
@@ -1183,9 +1183,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
1183
1183
|
|
1184
1184
|
it "should return results in descending order of the value of the rank expression" do
|
1185
1185
|
records = [
|
1186
|
-
ModelWithPgSearch.create!(:
|
1187
|
-
ModelWithPgSearch.create!(:
|
1188
|
-
ModelWithPgSearch.create!(:
|
1186
|
+
ModelWithPgSearch.create!(content: 'foo', importance: 1),
|
1187
|
+
ModelWithPgSearch.create!(content: 'foo', importance: 3),
|
1188
|
+
ModelWithPgSearch.create!(content: 'foo', importance: 2)
|
1189
1189
|
]
|
1190
1190
|
|
1191
1191
|
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo")
|
@@ -1197,10 +1197,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
1197
1197
|
let(:scope_name) { :"search_content_ranked_by_#{feature}" }
|
1198
1198
|
before do
|
1199
1199
|
ModelWithPgSearch.pg_search_scope scope_name,
|
1200
|
-
:
|
1201
|
-
:
|
1200
|
+
against: :content,
|
1201
|
+
ranked_by: ":#{feature}"
|
1202
1202
|
|
1203
|
-
ModelWithPgSearch.create!(:
|
1203
|
+
ModelWithPgSearch.create!(content: 'foo')
|
1204
1204
|
end
|
1205
1205
|
|
1206
1206
|
context "when .with_pg_search_rank is chained after" do
|
@@ -1234,12 +1234,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1234
1234
|
context "using the tsearch ranking algorithm" do
|
1235
1235
|
it "sorts results by the tsearch rank" do
|
1236
1236
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_tsearch,
|
1237
|
-
:
|
1238
|
-
:
|
1239
|
-
:
|
1237
|
+
using: :tsearch,
|
1238
|
+
against: :content,
|
1239
|
+
ranked_by: ":tsearch"
|
1240
1240
|
|
1241
|
-
once = ModelWithPgSearch.create!(:
|
1242
|
-
twice = ModelWithPgSearch.create!(:
|
1241
|
+
once = ModelWithPgSearch.create!(content: 'foo bar')
|
1242
|
+
twice = ModelWithPgSearch.create!(content: 'foo foo')
|
1243
1243
|
|
1244
1244
|
results = ModelWithPgSearch.search_content_ranked_by_tsearch('foo')
|
1245
1245
|
expect(results.find_index(twice)).to be < results.find_index(once)
|
@@ -1249,12 +1249,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1249
1249
|
context "using the trigram ranking algorithm" do
|
1250
1250
|
it "sorts results by the trigram rank" do
|
1251
1251
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_trigram,
|
1252
|
-
:
|
1253
|
-
:
|
1254
|
-
:
|
1252
|
+
using: :trigram,
|
1253
|
+
against: :content,
|
1254
|
+
ranked_by: ":trigram"
|
1255
1255
|
|
1256
|
-
close = ModelWithPgSearch.create!(:
|
1257
|
-
exact = ModelWithPgSearch.create!(:
|
1256
|
+
close = ModelWithPgSearch.create!(content: 'abcdef')
|
1257
|
+
exact = ModelWithPgSearch.create!(content: 'abc')
|
1258
1258
|
|
1259
1259
|
results = ModelWithPgSearch.search_content_ranked_by_trigram('abc')
|
1260
1260
|
expect(results.find_index(exact)).to be < results.find_index(close)
|
@@ -1264,12 +1264,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1264
1264
|
context "using the dmetaphone ranking algorithm" do
|
1265
1265
|
it "sorts results by the dmetaphone rank" do
|
1266
1266
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1267
|
-
:
|
1268
|
-
:
|
1269
|
-
:
|
1267
|
+
using: :dmetaphone,
|
1268
|
+
against: :content,
|
1269
|
+
ranked_by: ":dmetaphone"
|
1270
1270
|
|
1271
|
-
once = ModelWithPgSearch.create!(:
|
1272
|
-
twice = ModelWithPgSearch.create!(:
|
1271
|
+
once = ModelWithPgSearch.create!(content: 'Phoo Bar')
|
1272
|
+
twice = ModelWithPgSearch.create!(content: 'Phoo Fu')
|
1273
1273
|
|
1274
1274
|
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone('foo')
|
1275
1275
|
expect(results.find_index(twice)).to be < results.find_index(once)
|
@@ -1280,17 +1280,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
1280
1280
|
context "when there is a sort only feature" do
|
1281
1281
|
it "excludes that feature from the conditions, but uses it in the sorting" do
|
1282
1282
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1283
|
-
:
|
1284
|
-
:
|
1285
|
-
:
|
1286
|
-
:
|
1283
|
+
against: :content,
|
1284
|
+
using: {
|
1285
|
+
tsearch: { any_word: true, prefix: true },
|
1286
|
+
dmetaphone: { any_word: true, prefix: true, sort_only: true }
|
1287
1287
|
},
|
1288
|
-
:
|
1288
|
+
ranked_by: ":tsearch + (0.5 * :dmetaphone)"
|
1289
1289
|
|
1290
|
-
exact = ModelWithPgSearch.create!(:
|
1291
|
-
one_exact_one_close = ModelWithPgSearch.create!(:
|
1292
|
-
one_exact = ModelWithPgSearch.create!(:
|
1293
|
-
one_close = ModelWithPgSearch.create!(:
|
1290
|
+
exact = ModelWithPgSearch.create!(content: "ash hines")
|
1291
|
+
one_exact_one_close = ModelWithPgSearch.create!(content: "ash heinz")
|
1292
|
+
one_exact = ModelWithPgSearch.create!(content: "ash smith")
|
1293
|
+
one_close = ModelWithPgSearch.create!(content: "leigh heinz")
|
1294
1294
|
|
1295
1295
|
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone("ash hines")
|
1296
1296
|
expect(results).to eq [exact, one_exact_one_close, one_exact]
|