pg_search 2.1.4 → 2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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]
|