pg_search 2.1.7 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.editorconfig +10 -0
- data/.github/dependabot.yml +11 -0
- data/.rubocop.yml +89 -7
- data/.travis.yml +11 -19
- data/CHANGELOG.md +38 -14
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +74 -42
- data/lib/pg_search.rb +15 -58
- data/lib/pg_search/document.rb +2 -2
- data/lib/pg_search/features/dmetaphone.rb +4 -6
- data/lib/pg_search/features/trigram.rb +29 -5
- data/lib/pg_search/features/tsearch.rb +13 -12
- data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +6 -6
- data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +2 -2
- data/lib/pg_search/model.rb +59 -0
- data/lib/pg_search/multisearch.rb +10 -1
- data/lib/pg_search/multisearch/rebuilder.rb +7 -3
- data/lib/pg_search/multisearchable.rb +4 -4
- data/lib/pg_search/scope_options.rb +2 -10
- data/lib/pg_search/tasks.rb +2 -1
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +10 -5
- data/spec/.rubocop.yml +2 -2
- data/spec/integration/.rubocop.yml +11 -0
- data/spec/integration/associations_spec.rb +36 -75
- data/spec/integration/deprecation_spec.rb +33 -0
- data/spec/integration/pagination_spec.rb +1 -1
- data/spec/integration/pg_search_spec.rb +199 -188
- data/spec/integration/single_table_inheritance_spec.rb +2 -2
- data/spec/lib/pg_search/configuration/association_spec.rb +10 -8
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +3 -3
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +2 -2
- data/spec/lib/pg_search/features/trigram_spec.rb +48 -19
- data/spec/lib/pg_search/features/tsearch_spec.rb +16 -10
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +124 -76
- data/spec/lib/pg_search/multisearch_spec.rb +49 -30
- data/spec/lib/pg_search/multisearchable_spec.rb +155 -101
- data/spec/lib/pg_search/normalizer_spec.rb +12 -10
- data/spec/lib/pg_search_spec.rb +62 -46
- data/spec/spec_helper.rb +13 -4
- data/spec/support/database.rb +1 -1
- metadata +90 -13
data/lib/pg_search/tasks.rb
CHANGED
@@ -7,11 +7,12 @@ namespace :pg_search do
|
|
7
7
|
namespace :multisearch do
|
8
8
|
desc "Rebuild PgSearch multisearch records for a given model"
|
9
9
|
task :rebuild, %i[model schema] => :environment do |_task, args|
|
10
|
-
raise ArgumentError,
|
10
|
+
raise ArgumentError, <<~MESSAGE unless args.model
|
11
11
|
|
12
12
|
You must pass a model as an argument.
|
13
13
|
Example: rake pg_search:multisearch:rebuild[BlogPost]
|
14
14
|
MESSAGE
|
15
|
+
|
15
16
|
model_class = args.model.classify.constantize
|
16
17
|
connection = PgSearch::Document.connection
|
17
18
|
original_schema_search_path = connection.schema_search_path
|
data/lib/pg_search/version.rb
CHANGED
data/pg_search.gemspec
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
4
|
require 'pg_search/version'
|
5
5
|
|
6
|
-
Gem::Specification.new do |s|
|
6
|
+
Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
|
7
7
|
s.name = 'pg_search'
|
8
8
|
s.version = PgSearch::VERSION
|
9
9
|
s.platform = Gem::Platform::RUBY
|
@@ -18,16 +18,21 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
s.add_dependency 'activerecord', '>=
|
22
|
-
s.add_dependency 'activesupport', '>=
|
21
|
+
s.add_dependency 'activerecord', '>= 5.2'
|
22
|
+
s.add_dependency 'activesupport', '>= 5.2'
|
23
23
|
|
24
24
|
s.add_development_dependency 'pry'
|
25
25
|
s.add_development_dependency 'rake'
|
26
26
|
s.add_development_dependency 'rspec', '>= 3.3'
|
27
|
-
s.add_development_dependency 'rubocop', '>= 0.
|
27
|
+
s.add_development_dependency 'rubocop', '>= 0.90.0'
|
28
28
|
s.add_development_dependency 'rubocop-performance'
|
29
|
+
s.add_development_dependency 'rubocop-rails'
|
30
|
+
s.add_development_dependency 'rubocop-rake'
|
31
|
+
s.add_development_dependency 'rubocop-rspec'
|
32
|
+
s.add_development_dependency 'rubocop-thread_safety', '>= 0.4.1'
|
29
33
|
s.add_development_dependency 'simplecov'
|
34
|
+
s.add_development_dependency 'warning'
|
30
35
|
s.add_development_dependency 'with_model', '>= 1.2'
|
31
36
|
|
32
|
-
s.required_ruby_version = '>= 2.
|
37
|
+
s.required_ruby_version = '>= 2.5'
|
33
38
|
end
|
data/spec/.rubocop.yml
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
# rubocop:disable RSpec/NestedGroups
|
6
|
+
describe "a pg_search_scope" do
|
7
|
+
context "when joining to another table" do
|
7
8
|
context "without an :against" do
|
8
9
|
with_model :AssociatedModel do
|
9
10
|
table do |t|
|
@@ -18,7 +19,7 @@ describe PgSearch do
|
|
18
19
|
end
|
19
20
|
|
20
21
|
model do
|
21
|
-
include PgSearch
|
22
|
+
include PgSearch::Model
|
22
23
|
belongs_to :another_model, class_name: 'AssociatedModel'
|
23
24
|
|
24
25
|
pg_search_scope :with_another, associated_against: { another_model: :title }
|
@@ -41,7 +42,7 @@ describe PgSearch do
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
context "
|
45
|
+
context "via a belongs_to association" do
|
45
46
|
with_model :AssociatedModel do
|
46
47
|
table do |t|
|
47
48
|
t.string 'title'
|
@@ -55,7 +56,7 @@ describe PgSearch do
|
|
55
56
|
end
|
56
57
|
|
57
58
|
model do
|
58
|
-
include PgSearch
|
59
|
+
include PgSearch::Model
|
59
60
|
belongs_to :another_model, class_name: 'AssociatedModel'
|
60
61
|
|
61
62
|
pg_search_scope :with_associated, against: :title, associated_against: { another_model: :title }
|
@@ -77,7 +78,7 @@ describe PgSearch do
|
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
80
|
-
context "
|
81
|
+
context "via a has_many association" do
|
81
82
|
with_model :AssociatedModelWithHasMany do
|
82
83
|
table do |t|
|
83
84
|
t.string 'title'
|
@@ -91,7 +92,7 @@ describe PgSearch do
|
|
91
92
|
end
|
92
93
|
|
93
94
|
model do
|
94
|
-
include PgSearch
|
95
|
+
include PgSearch::Model
|
95
96
|
has_many :other_models, class_name: 'AssociatedModelWithHasMany', foreign_key: 'ModelWithHasMany_id'
|
96
97
|
|
97
98
|
pg_search_scope :with_associated, against: [:title], associated_against: { other_models: :title }
|
@@ -141,8 +142,8 @@ describe PgSearch do
|
|
141
142
|
end
|
142
143
|
end
|
143
144
|
|
144
|
-
context "across multiple associations" do
|
145
|
-
context "on different tables" do
|
145
|
+
context "when across multiple associations" do
|
146
|
+
context "when on different tables" do
|
146
147
|
with_model :FirstAssociatedModel do
|
147
148
|
table do |t|
|
148
149
|
t.string 'title'
|
@@ -163,18 +164,18 @@ describe PgSearch do
|
|
163
164
|
end
|
164
165
|
|
165
166
|
model do
|
166
|
-
include PgSearch
|
167
|
+
include PgSearch::Model
|
167
168
|
|
168
169
|
has_many :models_of_first_type,
|
169
|
-
|
170
|
-
|
170
|
+
class_name: 'FirstAssociatedModel',
|
171
|
+
foreign_key: 'ModelWithManyAssociations_id'
|
171
172
|
|
172
173
|
belongs_to :model_of_second_type,
|
173
|
-
|
174
|
+
class_name: 'SecondAssociatedModel'
|
174
175
|
|
175
176
|
pg_search_scope :with_associated,
|
176
|
-
|
177
|
-
|
177
|
+
against: :title,
|
178
|
+
associated_against: { models_of_first_type: :title, model_of_second_type: :title }
|
178
179
|
end
|
179
180
|
end
|
180
181
|
|
@@ -207,7 +208,7 @@ describe PgSearch do
|
|
207
208
|
end
|
208
209
|
end
|
209
210
|
|
210
|
-
context "on the same table" do
|
211
|
+
context "when on the same table" do
|
211
212
|
with_model :DoublyAssociatedModel do
|
212
213
|
table do |t|
|
213
214
|
t.string 'title'
|
@@ -222,15 +223,15 @@ describe PgSearch do
|
|
222
223
|
end
|
223
224
|
|
224
225
|
model do
|
225
|
-
include PgSearch
|
226
|
+
include PgSearch::Model
|
226
227
|
|
227
228
|
has_many :things,
|
228
|
-
|
229
|
-
|
229
|
+
class_name: 'DoublyAssociatedModel',
|
230
|
+
foreign_key: 'ModelWithDoubleAssociation_id'
|
230
231
|
|
231
232
|
has_many :thingamabobs,
|
232
|
-
|
233
|
-
|
233
|
+
class_name: 'DoublyAssociatedModel',
|
234
|
+
foreign_key: 'ModelWithDoubleAssociation_again_id'
|
234
235
|
|
235
236
|
pg_search_scope :with_associated, against: :title,
|
236
237
|
associated_against: { things: :title, thingamabobs: :title }
|
@@ -268,7 +269,7 @@ describe PgSearch do
|
|
268
269
|
end
|
269
270
|
end
|
270
271
|
|
271
|
-
context "against multiple attributes on one association" do
|
272
|
+
context "when against multiple attributes on one association" do
|
272
273
|
with_model :AssociatedModel do
|
273
274
|
table do |t|
|
274
275
|
t.string 'title'
|
@@ -282,14 +283,14 @@ describe PgSearch do
|
|
282
283
|
end
|
283
284
|
|
284
285
|
model do
|
285
|
-
include PgSearch
|
286
|
+
include PgSearch::Model
|
286
287
|
belongs_to :another_model, class_name: 'AssociatedModel'
|
287
288
|
|
288
289
|
pg_search_scope :with_associated, associated_against: { another_model: %i[title author] }
|
289
290
|
end
|
290
291
|
end
|
291
292
|
|
292
|
-
it "
|
293
|
+
it "joins only once" do
|
293
294
|
included = [
|
294
295
|
ModelWithAssociation.create!(
|
295
296
|
another_model: AssociatedModel.create!(
|
@@ -321,7 +322,7 @@ describe PgSearch do
|
|
321
322
|
end
|
322
323
|
end
|
323
324
|
|
324
|
-
context "against non-text columns" do
|
325
|
+
context "when against non-text columns" do
|
325
326
|
with_model :AssociatedModel do
|
326
327
|
table do |t|
|
327
328
|
t.integer 'number'
|
@@ -335,14 +336,14 @@ describe PgSearch do
|
|
335
336
|
end
|
336
337
|
|
337
338
|
model do
|
338
|
-
include PgSearch
|
339
|
+
include PgSearch::Model
|
339
340
|
belongs_to :another_model, class_name: 'AssociatedModel'
|
340
341
|
|
341
342
|
pg_search_scope :with_associated, associated_against: { another_model: :number }
|
342
343
|
end
|
343
344
|
end
|
344
345
|
|
345
|
-
it "
|
346
|
+
it "casts the columns to text" do
|
346
347
|
associated = AssociatedModel.create!(number: 123)
|
347
348
|
included = [
|
348
349
|
Model.create!(number: 123, another_model: associated),
|
@@ -366,7 +367,7 @@ describe PgSearch do
|
|
366
367
|
|
367
368
|
model do
|
368
369
|
has_many :children
|
369
|
-
include PgSearch
|
370
|
+
include PgSearch::Model
|
370
371
|
pg_search_scope :search_name, against: :name
|
371
372
|
end
|
372
373
|
end
|
@@ -395,7 +396,7 @@ describe PgSearch do
|
|
395
396
|
end
|
396
397
|
end
|
397
398
|
|
398
|
-
context "merging a pg_search_scope into another model's scope" do
|
399
|
+
context "when merging a pg_search_scope into another model's scope" do
|
399
400
|
with_model :ModelWithAssociation do
|
400
401
|
model do
|
401
402
|
has_many :associated_models
|
@@ -409,14 +410,14 @@ describe PgSearch do
|
|
409
410
|
end
|
410
411
|
|
411
412
|
model do
|
412
|
-
include PgSearch
|
413
|
+
include PgSearch::Model
|
413
414
|
belongs_to :model_with_association
|
414
415
|
|
415
416
|
pg_search_scope :search_content, against: :content
|
416
417
|
end
|
417
418
|
end
|
418
419
|
|
419
|
-
it "
|
420
|
+
it "finds records of the other model" do
|
420
421
|
included_associated_1 = AssociatedModel.create(content: "foo bar")
|
421
422
|
included_associated_2 = AssociatedModel.create(content: "foo baz")
|
422
423
|
excluded_associated_1 = AssociatedModel.create(content: "baz quux")
|
@@ -441,7 +442,7 @@ describe PgSearch do
|
|
441
442
|
end
|
442
443
|
end
|
443
444
|
|
444
|
-
context "chained onto a has_many association" do
|
445
|
+
context "when chained onto a has_many association" do
|
445
446
|
with_model :Company do
|
446
447
|
model do
|
447
448
|
has_many :positions
|
@@ -455,54 +456,13 @@ describe PgSearch do
|
|
455
456
|
end
|
456
457
|
|
457
458
|
model do
|
458
|
-
include PgSearch
|
459
|
+
include PgSearch::Model
|
459
460
|
pg_search_scope :search, against: :title, using: %i[tsearch trigram]
|
460
461
|
end
|
461
462
|
end
|
462
463
|
|
463
464
|
# https://github.com/Casecommons/pg_search/issues/106
|
464
|
-
it "
|
465
|
-
company = Company.create!
|
466
|
-
another_company = Company.create!
|
467
|
-
|
468
|
-
included = [
|
469
|
-
Position.create!(company_id: company.id, title: "teller 1")
|
470
|
-
]
|
471
|
-
|
472
|
-
excluded = [
|
473
|
-
Position.create!(company_id: nil, title: "teller 1"),
|
474
|
-
Position.create!(company_id: another_company.id, title: "teller 1"),
|
475
|
-
Position.create!(company_id: company.id, title: "penn 1")
|
476
|
-
]
|
477
|
-
|
478
|
-
results = company.positions.search('teller 1')
|
479
|
-
|
480
|
-
expect(results).to include(*included)
|
481
|
-
expect(results).not_to include(*excluded)
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
context "chained onto a has_many association" do
|
486
|
-
with_model :Company do
|
487
|
-
model do
|
488
|
-
has_many :positions
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
with_model :Position do
|
493
|
-
table do |t|
|
494
|
-
t.string :title
|
495
|
-
t.belongs_to :company
|
496
|
-
end
|
497
|
-
|
498
|
-
model do
|
499
|
-
include PgSearch
|
500
|
-
pg_search_scope :search, against: :title, using: %i[tsearch trigram]
|
501
|
-
end
|
502
|
-
end
|
503
|
-
|
504
|
-
# https://github.com/Casecommons/pg_search/issues/106
|
505
|
-
it "should handle numbers in a trigram query properly" do
|
465
|
+
it "handles numbers in a trigram query properly" do
|
506
466
|
company = Company.create!
|
507
467
|
another_company = Company.create!
|
508
468
|
|
@@ -524,3 +484,4 @@ describe PgSearch do
|
|
524
484
|
end
|
525
485
|
end
|
526
486
|
end
|
487
|
+
# rubocop:enable RSpec/NestedGroups
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "Including the deprecated PgSearch module" do
|
6
|
+
with_model :SomeModel do
|
7
|
+
model do
|
8
|
+
ActiveSupport::Deprecation.silence do
|
9
|
+
include PgSearch
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
with_model :AnotherModel
|
15
|
+
|
16
|
+
it "includes PgSearch::Model" do
|
17
|
+
expect(SomeModel.ancestors).to include PgSearch::Model
|
18
|
+
end
|
19
|
+
|
20
|
+
it "prints a deprecation message" do
|
21
|
+
allow(ActiveSupport::Deprecation).to receive(:warn)
|
22
|
+
|
23
|
+
AnotherModel.include(PgSearch)
|
24
|
+
|
25
|
+
expect(ActiveSupport::Deprecation).to have_received(:warn).with(
|
26
|
+
<<~MESSAGE
|
27
|
+
Directly including `PgSearch` into an Active Record model is deprecated and will be removed in pg_search 3.0.
|
28
|
+
|
29
|
+
Please replace `include PgSearch` with `include PgSearch::Model`.
|
30
|
+
MESSAGE
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
+
# rubocop:disable RSpec/NestedGroups
|
5
6
|
describe "an Active Record model which includes PgSearch" do
|
6
7
|
with_model :ModelWithPgSearch do
|
7
8
|
table do |t|
|
@@ -12,7 +13,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
12
13
|
end
|
13
14
|
|
14
15
|
model do
|
15
|
-
include PgSearch
|
16
|
+
include PgSearch::Model
|
16
17
|
belongs_to :parent_model
|
17
18
|
end
|
18
19
|
end
|
@@ -22,7 +23,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
22
23
|
end
|
23
24
|
|
24
25
|
model do
|
25
|
-
include PgSearch
|
26
|
+
include PgSearch::Model
|
26
27
|
has_many :models_with_pg_search
|
27
28
|
scope :active, -> { where(active: true) }
|
28
29
|
end
|
@@ -38,12 +39,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
38
39
|
context "when passed a lambda" do
|
39
40
|
it "builds a dynamic scope" do
|
40
41
|
ModelWithPgSearch.pg_search_scope :search_title_or_content,
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
lambda { |query, pick_content|
|
43
|
+
{
|
44
|
+
query: query.gsub("-remove-", ""),
|
45
|
+
against: pick_content ? :content : :title
|
46
|
+
}
|
47
|
+
}
|
47
48
|
|
48
49
|
included = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
49
50
|
excluded = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
@@ -56,18 +57,18 @@ describe "an Active Record model which includes PgSearch" do
|
|
56
57
|
context "when an unknown option is passed in" do
|
57
58
|
it "raises an exception when invoked" do
|
58
59
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
59
|
-
|
60
|
-
|
60
|
+
against: :content,
|
61
|
+
foo: :bar
|
61
62
|
|
62
63
|
expect {
|
63
64
|
ModelWithPgSearch.with_unknown_option("foo")
|
64
65
|
}.to raise_error(ArgumentError, /foo/)
|
65
66
|
end
|
66
67
|
|
67
|
-
context "
|
68
|
+
context "with a lambda" do
|
68
69
|
it "raises an exception when invoked" do
|
69
70
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
70
|
-
|
71
|
+
->(*) { { against: :content, foo: :bar } }
|
71
72
|
|
72
73
|
expect {
|
73
74
|
ModelWithPgSearch.with_unknown_option("foo")
|
@@ -79,18 +80,18 @@ describe "an Active Record model which includes PgSearch" do
|
|
79
80
|
context "when an unknown :using is passed" do
|
80
81
|
it "raises an exception when invoked" do
|
81
82
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
82
|
-
|
83
|
-
|
83
|
+
against: :content,
|
84
|
+
using: :foo
|
84
85
|
|
85
86
|
expect {
|
86
87
|
ModelWithPgSearch.with_unknown_using("foo")
|
87
88
|
}.to raise_error(ArgumentError, /foo/)
|
88
89
|
end
|
89
90
|
|
90
|
-
context "
|
91
|
+
context "with a lambda" do
|
91
92
|
it "raises an exception when invoked" do
|
92
93
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
93
|
-
|
94
|
+
->(*) { { against: :content, using: :foo } }
|
94
95
|
|
95
96
|
expect {
|
96
97
|
ModelWithPgSearch.with_unknown_using("foo")
|
@@ -102,18 +103,18 @@ describe "an Active Record model which includes PgSearch" do
|
|
102
103
|
context "when an unknown :ignoring is passed" do
|
103
104
|
it "raises an exception when invoked" do
|
104
105
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
105
|
-
|
106
|
-
|
106
|
+
against: :content,
|
107
|
+
ignoring: :foo
|
107
108
|
|
108
109
|
expect {
|
109
110
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
110
111
|
}.to raise_error(ArgumentError, /ignoring.*foo/)
|
111
112
|
end
|
112
113
|
|
113
|
-
context "
|
114
|
+
context "with a lambda" do
|
114
115
|
it "raises an exception when invoked" do
|
115
116
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
116
|
-
|
117
|
+
->(*) { { against: :content, ignoring: :foo } }
|
117
118
|
|
118
119
|
expect {
|
119
120
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
@@ -130,7 +131,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
130
131
|
}.to raise_error(ArgumentError, /against/)
|
131
132
|
end
|
132
133
|
|
133
|
-
context "
|
134
|
+
context "with a lambda" do
|
134
135
|
it "raises an exception when invoked" do
|
135
136
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring, ->(*) { {} }
|
136
137
|
|
@@ -144,7 +145,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
144
145
|
end
|
145
146
|
|
146
147
|
describe "a search scope" do
|
147
|
-
context "against a single column" do
|
148
|
+
context "when against a single column" do
|
148
149
|
before do
|
149
150
|
ModelWithPgSearch.pg_search_scope :search_content, against: :content
|
150
151
|
end
|
@@ -157,7 +158,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
157
158
|
results = ModelWithPgSearch.select('id, title').search_content('foo')
|
158
159
|
|
159
160
|
expect(results).to include(included)
|
160
|
-
expect(results).
|
161
|
+
expect(results).not_to include(excluded)
|
161
162
|
|
162
163
|
expect(results.first.attributes.key?('content')).to eq false
|
163
164
|
|
@@ -174,7 +175,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
174
175
|
results = ModelWithPgSearch.search_content('foo').select('id, title')
|
175
176
|
|
176
177
|
expect(results).to include(included)
|
177
|
-
expect(results).
|
178
|
+
expect(results).not_to include(excluded)
|
178
179
|
|
179
180
|
expect(results.first.attributes.key?('content')).to eq false
|
180
181
|
|
@@ -191,7 +192,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
191
192
|
results = ModelWithPgSearch.select('id').search_content('foo').select('title')
|
192
193
|
|
193
194
|
expect(results).to include(included)
|
194
|
-
expect(results).
|
195
|
+
expect(results).not_to include(excluded)
|
195
196
|
|
196
197
|
expect(results.first.attributes.key?('content')).to eq false
|
197
198
|
|
@@ -200,7 +201,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
200
201
|
end
|
201
202
|
end
|
202
203
|
|
203
|
-
context "chained to a cross-table scope" do
|
204
|
+
context "when chained to a cross-table scope" do
|
204
205
|
with_model :House do
|
205
206
|
table do |t|
|
206
207
|
t.references :person
|
@@ -208,7 +209,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
208
209
|
end
|
209
210
|
|
210
211
|
model do
|
211
|
-
include PgSearch
|
212
|
+
include PgSearch::Model
|
212
213
|
belongs_to :person
|
213
214
|
pg_search_scope :search_city, against: [:city]
|
214
215
|
end
|
@@ -220,7 +221,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
220
221
|
end
|
221
222
|
|
222
223
|
model do
|
223
|
-
include PgSearch
|
224
|
+
include PgSearch::Model
|
224
225
|
has_many :houses
|
225
226
|
pg_search_scope :named, against: [:name]
|
226
227
|
scope :with_house_in_city, lambda { |city|
|
@@ -270,7 +271,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
270
271
|
it "does not raise an exception" do
|
271
272
|
relation = Person.named('foo').house_search_city('bar')
|
272
273
|
|
273
|
-
expect { relation.to_a }.
|
274
|
+
expect { relation.to_a }.not_to raise_error
|
274
275
|
end
|
275
276
|
end
|
276
277
|
end
|
@@ -283,7 +284,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
283
284
|
it "does not raise an exception" do
|
284
285
|
relation = ModelWithPgSearch.search_content('foo').search_title('bar')
|
285
286
|
|
286
|
-
expect { relation.to_a }.
|
287
|
+
expect { relation.to_a }.not_to raise_error
|
287
288
|
end
|
288
289
|
end
|
289
290
|
|
@@ -451,7 +452,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
451
452
|
|
452
453
|
it "accepts non-string queries and calls #to_s on them" do
|
453
454
|
foo = ModelWithPgSearch.create!(content: "foo")
|
454
|
-
not_a_string =
|
455
|
+
not_a_string = instance_double("Object", to_s: "foo")
|
455
456
|
expect(ModelWithPgSearch.search_content(not_a_string)).to eq([foo])
|
456
457
|
end
|
457
458
|
|
@@ -462,12 +463,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
462
463
|
end
|
463
464
|
|
464
465
|
model do
|
465
|
-
include PgSearch
|
466
|
+
include PgSearch::Model
|
466
467
|
|
467
468
|
# WARNING: searching timestamps is not something PostgreSQL
|
468
469
|
# full-text search is good at. Use at your own risk.
|
469
470
|
pg_search_scope :search_timestamps,
|
470
|
-
|
471
|
+
against: %i[created_at updated_at]
|
471
472
|
end
|
472
473
|
end
|
473
474
|
|
@@ -481,7 +482,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
481
482
|
end
|
482
483
|
end
|
483
484
|
|
484
|
-
context "against multiple columns" do
|
485
|
+
context "when against multiple columns" do
|
485
486
|
before do
|
486
487
|
ModelWithPgSearch.pg_search_scope :search_title_and_content, against: %i[title content]
|
487
488
|
end
|
@@ -520,7 +521,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
520
521
|
end
|
521
522
|
end
|
522
523
|
|
523
|
-
context "using trigram" do
|
524
|
+
context "when using trigram" do
|
524
525
|
before do
|
525
526
|
ModelWithPgSearch.pg_search_scope :with_trigrams, against: %i[title content], using: :trigram
|
526
527
|
end
|
@@ -562,13 +563,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
562
563
|
end
|
563
564
|
end
|
564
565
|
|
565
|
-
context "using tsearch" do
|
566
|
+
context "when using tsearch" do
|
566
567
|
before do
|
567
568
|
ModelWithPgSearch.pg_search_scope :search_title_with_prefixes,
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
569
|
+
against: :title,
|
570
|
+
using: {
|
571
|
+
tsearch: { prefix: true }
|
572
|
+
}
|
572
573
|
end
|
573
574
|
|
574
575
|
context "with prefix: true" do
|
@@ -594,10 +595,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
594
595
|
context "with the english dictionary" do
|
595
596
|
before do
|
596
597
|
ModelWithPgSearch.pg_search_scope :search_content_with_english,
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
598
|
+
against: :content,
|
599
|
+
using: {
|
600
|
+
tsearch: { dictionary: :english }
|
601
|
+
}
|
601
602
|
end
|
602
603
|
|
603
604
|
it "returns rows that match the query when stemmed by the english dictionary" do
|
@@ -620,7 +621,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
620
621
|
context "with highlight turned on" do
|
621
622
|
before do
|
622
623
|
ModelWithPgSearch.pg_search_scope :search_content,
|
623
|
-
|
624
|
+
against: :content
|
624
625
|
end
|
625
626
|
|
626
627
|
it "adds a #pg_search_highlight method to each returned model record" do
|
@@ -641,19 +642,19 @@ describe "an Active Record model which includes PgSearch" do
|
|
641
642
|
ModelWithPgSearch.create! content: "#{'text ' * 2}Let #{'text ' * 2}Let #{'text ' * 2}"
|
642
643
|
|
643
644
|
ModelWithPgSearch.pg_search_scope :search_content,
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
645
|
+
against: :content,
|
646
|
+
using: {
|
647
|
+
tsearch: {
|
648
|
+
highlight: {
|
649
|
+
StartSel: '<mark class="highlight">',
|
650
|
+
StopSel: '</mark>',
|
651
|
+
FragmentDelimiter: '<delim class="my_delim">',
|
652
|
+
MaxFragments: 2,
|
653
|
+
MaxWords: 2,
|
654
|
+
MinWords: 1
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
657
658
|
end
|
658
659
|
|
659
660
|
it "applies the options to the excerpts" do
|
@@ -682,10 +683,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
682
683
|
context "with a normalization specified" do
|
683
684
|
before do
|
684
685
|
ModelWithPgSearch.pg_search_scope :search_content_with_normalization,
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
686
|
+
against: :content,
|
687
|
+
using: {
|
688
|
+
tsearch: { normalization: 2 }
|
689
|
+
}
|
689
690
|
end
|
690
691
|
|
691
692
|
it "ranks the results for documents with less text higher" do
|
@@ -699,8 +700,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
699
700
|
context "with no normalization" do
|
700
701
|
before do
|
701
702
|
ModelWithPgSearch.pg_search_scope :search_content_without_normalization,
|
702
|
-
|
703
|
-
|
703
|
+
against: :content,
|
704
|
+
using: :tsearch
|
704
705
|
end
|
705
706
|
|
706
707
|
it "ranks the results equally" do
|
@@ -712,10 +713,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
712
713
|
end
|
713
714
|
end
|
714
715
|
|
715
|
-
context "against columns ranked with arrays" do
|
716
|
+
context "when against columns ranked with arrays" do
|
716
717
|
before do
|
717
718
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_array_of_arrays,
|
718
|
-
|
719
|
+
against: [[:content, 'B'], [:title, 'A']]
|
719
720
|
end
|
720
721
|
|
721
722
|
it "returns results sorted by weighted rank" do
|
@@ -728,10 +729,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
728
729
|
end
|
729
730
|
end
|
730
731
|
|
731
|
-
context "against columns ranked with a hash" do
|
732
|
+
context "when against columns ranked with a hash" do
|
732
733
|
before do
|
733
734
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_hash,
|
734
|
-
|
735
|
+
against: { content: 'B', title: 'A' }
|
735
736
|
end
|
736
737
|
|
737
738
|
it "returns results sorted by weighted rank" do
|
@@ -744,10 +745,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
744
745
|
end
|
745
746
|
end
|
746
747
|
|
747
|
-
context "against columns of which only some are ranked" do
|
748
|
+
context "when against columns of which only some are ranked" do
|
748
749
|
before do
|
749
750
|
ModelWithPgSearch.pg_search_scope :search_weighted,
|
750
|
-
|
751
|
+
against: [:content, [:title, 'A']]
|
751
752
|
end
|
752
753
|
|
753
754
|
it "returns results sorted by weighted rank using an implied low rank for unranked columns" do
|
@@ -760,16 +761,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
760
761
|
end
|
761
762
|
end
|
762
763
|
|
763
|
-
context "searching any_word option" do
|
764
|
+
context "when searching any_word option" do
|
764
765
|
before do
|
765
766
|
ModelWithPgSearch.pg_search_scope :search_title_with_any_word,
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
767
|
+
against: :title,
|
768
|
+
using: {
|
769
|
+
tsearch: { any_word: true }
|
770
|
+
}
|
770
771
|
|
771
772
|
ModelWithPgSearch.pg_search_scope :search_title_with_all_words,
|
772
|
-
|
773
|
+
against: :title
|
773
774
|
end
|
774
775
|
|
775
776
|
it "returns all results containing any word in their title" do
|
@@ -788,10 +789,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
788
789
|
context "with :negation" do
|
789
790
|
before do
|
790
791
|
ModelWithPgSearch.pg_search_scope :search_with_negation,
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
792
|
+
against: :title,
|
793
|
+
using: {
|
794
|
+
tsearch: { negation: true }
|
795
|
+
}
|
795
796
|
end
|
796
797
|
|
797
798
|
it "doesn't return results that contain terms prepended with '!'" do
|
@@ -815,10 +816,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
815
816
|
context "without :negation" do
|
816
817
|
before do
|
817
818
|
ModelWithPgSearch.pg_search_scope :search_without_negation,
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
819
|
+
against: :title,
|
820
|
+
using: {
|
821
|
+
tsearch: {}
|
822
|
+
}
|
822
823
|
end
|
823
824
|
|
824
825
|
it "return results that contain terms prepended with '!'" do
|
@@ -838,11 +839,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
838
839
|
end
|
839
840
|
end
|
840
841
|
|
841
|
-
context "using dmetaphone" do
|
842
|
+
context "when using dmetaphone" do
|
842
843
|
before do
|
843
844
|
ModelWithPgSearch.pg_search_scope :with_dmetaphones,
|
844
|
-
|
845
|
-
|
845
|
+
against: %i[title content],
|
846
|
+
using: :dmetaphone
|
846
847
|
end
|
847
848
|
|
848
849
|
it "returns rows where one searchable column and the query share enough dmetaphones" do
|
@@ -877,38 +878,38 @@ describe "an Active Record model which includes PgSearch" do
|
|
877
878
|
end
|
878
879
|
end
|
879
880
|
|
880
|
-
context "using multiple features" do
|
881
|
+
context "when using multiple features" do
|
881
882
|
before do
|
882
883
|
ModelWithPgSearch.pg_search_scope :with_tsearch,
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
884
|
+
against: :title,
|
885
|
+
using: [
|
886
|
+
[:tsearch, { dictionary: 'english' }]
|
887
|
+
]
|
887
888
|
|
888
889
|
ModelWithPgSearch.pg_search_scope :with_trigram,
|
889
|
-
|
890
|
-
|
890
|
+
against: :title,
|
891
|
+
using: :trigram
|
891
892
|
|
892
893
|
ModelWithPgSearch.pg_search_scope :with_trigram_and_ignoring_accents,
|
893
|
-
|
894
|
-
|
895
|
-
|
894
|
+
against: :title,
|
895
|
+
ignoring: :accents,
|
896
|
+
using: :trigram
|
896
897
|
|
897
898
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram,
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
899
|
+
against: :title,
|
900
|
+
using: [
|
901
|
+
[:tsearch, { dictionary: 'english' }],
|
902
|
+
:trigram
|
903
|
+
]
|
903
904
|
|
904
905
|
ModelWithPgSearch.pg_search_scope :complex_search,
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
906
|
+
against: %i[content title],
|
907
|
+
ignoring: :accents,
|
908
|
+
using: {
|
909
|
+
tsearch: { dictionary: 'english' },
|
910
|
+
dmetaphone: {},
|
911
|
+
trigram: {}
|
912
|
+
}
|
912
913
|
end
|
913
914
|
|
914
915
|
it "returns rows that match using any of the features" do
|
@@ -950,33 +951,40 @@ describe "an Active Record model which includes PgSearch" do
|
|
950
951
|
end
|
951
952
|
|
952
953
|
context "with feature-specific configuration" do
|
953
|
-
|
954
|
-
|
955
|
-
@trigram_config = trigram_config = { foo: 'bar' }
|
954
|
+
let(:tsearch_config) { { dictionary: 'english' } }
|
955
|
+
let(:trigram_config) { { foo: 'bar' } }
|
956
956
|
|
957
|
+
before do
|
957
958
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram_using_hash,
|
958
|
-
|
959
|
-
|
960
|
-
tsearch: tsearch_config,
|
961
|
-
trigram: trigram_config
|
962
|
-
}
|
959
|
+
against: :title,
|
960
|
+
using: { tsearch: tsearch_config, trigram: trigram_config }
|
963
961
|
end
|
964
962
|
|
965
|
-
it "
|
966
|
-
|
963
|
+
it "passes the custom configuration down to the specified feature" do
|
964
|
+
tsearch_feature = instance_double(
|
965
|
+
"PgSearch::Features::TSearch",
|
966
|
+
conditions: Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
967
|
+
rank: Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
968
|
+
)
|
969
|
+
|
970
|
+
trigram_feature = instance_double(
|
971
|
+
"PgSearch::Features::Trigram",
|
967
972
|
conditions: Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
968
973
|
rank: Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
969
974
|
)
|
970
975
|
|
971
|
-
|
972
|
-
|
976
|
+
allow(PgSearch::Features::TSearch).to receive(:new).with(anything, tsearch_config, anything, anything, anything).and_return(tsearch_feature)
|
977
|
+
allow(PgSearch::Features::Trigram).to receive(:new).with(anything, trigram_config, anything, anything, anything).and_return(trigram_feature)
|
973
978
|
|
974
979
|
ModelWithPgSearch.with_tsearch_and_trigram_using_hash("foo")
|
980
|
+
|
981
|
+
expect(PgSearch::Features::TSearch).to have_received(:new).with(anything, tsearch_config, anything, anything, anything).at_least(:once)
|
982
|
+
expect(PgSearch::Features::Trigram).to have_received(:new).with(anything, trigram_config, anything, anything, anything).at_least(:once)
|
975
983
|
end
|
976
984
|
end
|
977
985
|
end
|
978
986
|
|
979
|
-
context "using a tsvector column and an association" do
|
987
|
+
context "when using a tsvector column and an association" do
|
980
988
|
with_model :Comment do
|
981
989
|
table do |t|
|
982
990
|
t.integer :post_id
|
@@ -995,7 +1003,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
995
1003
|
end
|
996
1004
|
|
997
1005
|
model do
|
998
|
-
include PgSearch
|
1006
|
+
include PgSearch::Model
|
999
1007
|
has_many :comments
|
1000
1008
|
end
|
1001
1009
|
end
|
@@ -1004,7 +1012,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
1004
1012
|
let!(:unexpected) { Post.create!(content: 'longcat is looooooooong') }
|
1005
1013
|
|
1006
1014
|
before do
|
1007
|
-
ActiveRecord::Base.connection.execute
|
1015
|
+
ActiveRecord::Base.connection.execute <<~SQL.squish
|
1008
1016
|
UPDATE #{Post.quoted_table_name}
|
1009
1017
|
SET content_tsvector = to_tsvector('english'::regconfig, #{Post.quoted_table_name}."content")
|
1010
1018
|
SQL
|
@@ -1013,41 +1021,41 @@ describe "an Active Record model which includes PgSearch" do
|
|
1013
1021
|
unexpected.comments.create(body: 'commentwo')
|
1014
1022
|
|
1015
1023
|
Post.pg_search_scope :search_by_content_with_tsvector,
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1024
|
+
associated_against: { comments: [:body] },
|
1025
|
+
using: {
|
1026
|
+
tsearch: {
|
1027
|
+
tsvector_column: 'content_tsvector',
|
1028
|
+
dictionary: 'english'
|
1029
|
+
}
|
1030
|
+
}
|
1023
1031
|
end
|
1024
1032
|
|
1025
|
-
it "
|
1033
|
+
it "finds by the tsvector column" do
|
1026
1034
|
expect(Post.search_by_content_with_tsvector("phooey").map(&:id)).to eq([expected.id])
|
1027
1035
|
end
|
1028
1036
|
|
1029
|
-
it "
|
1037
|
+
it "finds by the associated record" do
|
1030
1038
|
expect(Post.search_by_content_with_tsvector("commentone").map(&:id)).to eq([expected.id])
|
1031
1039
|
end
|
1032
1040
|
|
1033
|
-
it '
|
1041
|
+
it 'finds by a combination of the two' do
|
1034
1042
|
expect(Post.search_by_content_with_tsvector("phooey commentone").map(&:id)).to eq([expected.id])
|
1035
1043
|
end
|
1036
1044
|
end
|
1037
1045
|
|
1038
|
-
context 'using multiple tsvector columns' do
|
1046
|
+
context 'when using multiple tsvector columns' do
|
1039
1047
|
with_model :ModelWithTsvector do
|
1040
1048
|
model do
|
1041
|
-
include PgSearch
|
1049
|
+
include PgSearch::Model
|
1042
1050
|
|
1043
1051
|
pg_search_scope :search_by_multiple_tsvector_columns,
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1052
|
+
against: ['content', 'message'],
|
1053
|
+
using: {
|
1054
|
+
tsearch: {
|
1055
|
+
tsvector_column: ['content_tsvector', 'message_tsvector'],
|
1056
|
+
dictionary: 'english'
|
1057
|
+
}
|
1058
|
+
}
|
1051
1059
|
end
|
1052
1060
|
end
|
1053
1061
|
|
@@ -1059,40 +1067,41 @@ describe "an Active Record model which includes PgSearch" do
|
|
1059
1067
|
end
|
1060
1068
|
end
|
1061
1069
|
|
1062
|
-
context "using a tsvector column with" do
|
1070
|
+
context "when using a tsvector column with" do
|
1063
1071
|
with_model :ModelWithTsvector do
|
1064
1072
|
table do |t|
|
1065
1073
|
t.text 'content'
|
1066
1074
|
t.tsvector 'content_tsvector'
|
1067
1075
|
end
|
1068
1076
|
|
1069
|
-
model { include PgSearch }
|
1077
|
+
model { include PgSearch::Model }
|
1070
1078
|
end
|
1071
1079
|
|
1072
1080
|
let!(:expected) { ModelWithTsvector.create!(content: 'tiling is grouty') }
|
1073
|
-
let!(:unexpected) { ModelWithTsvector.create!(content: 'longcat is looooooooong') }
|
1074
1081
|
|
1075
1082
|
before do
|
1076
|
-
|
1083
|
+
ModelWithTsvector.create!(content: 'longcat is looooooooong')
|
1084
|
+
|
1085
|
+
ActiveRecord::Base.connection.execute <<~SQL.squish
|
1077
1086
|
UPDATE #{ModelWithTsvector.quoted_table_name}
|
1078
1087
|
SET content_tsvector = to_tsvector('english'::regconfig, #{ModelWithTsvector.quoted_table_name}."content")
|
1079
1088
|
SQL
|
1080
1089
|
|
1081
1090
|
ModelWithTsvector.pg_search_scope :search_by_content_with_tsvector,
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1091
|
+
against: :content,
|
1092
|
+
using: {
|
1093
|
+
tsearch: {
|
1094
|
+
tsvector_column: 'content_tsvector',
|
1095
|
+
dictionary: 'english'
|
1096
|
+
}
|
1097
|
+
}
|
1089
1098
|
end
|
1090
1099
|
|
1091
|
-
it "
|
1100
|
+
it "does not use to_tsvector in the query" do
|
1092
1101
|
expect(ModelWithTsvector.search_by_content_with_tsvector("tiles").to_sql).not_to match(/to_tsvector/)
|
1093
1102
|
end
|
1094
1103
|
|
1095
|
-
it "
|
1104
|
+
it "finds the expected result" do
|
1096
1105
|
expect(ModelWithTsvector.search_by_content_with_tsvector("tiles").map(&:id)).to eq([expected.id])
|
1097
1106
|
end
|
1098
1107
|
|
@@ -1108,7 +1117,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
1108
1117
|
ModelWithTsvector.has_many :another_models
|
1109
1118
|
end
|
1110
1119
|
|
1111
|
-
it "
|
1120
|
+
it "refers to the tsvector column in the query unambiguously" do
|
1112
1121
|
expect {
|
1113
1122
|
ModelWithTsvector.joins(:another_models).search_by_content_with_tsvector("test").to_a
|
1114
1123
|
}.not_to raise_exception
|
@@ -1116,11 +1125,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
1116
1125
|
end
|
1117
1126
|
end
|
1118
1127
|
|
1119
|
-
context "ignoring accents" do
|
1128
|
+
context "when ignoring accents" do
|
1120
1129
|
before do
|
1121
1130
|
ModelWithPgSearch.pg_search_scope :search_title_without_accents,
|
1122
|
-
|
1123
|
-
|
1131
|
+
against: :title,
|
1132
|
+
ignoring: :accents
|
1124
1133
|
end
|
1125
1134
|
|
1126
1135
|
it "returns rows that match the query but not its accents" do
|
@@ -1146,24 +1155,24 @@ describe "an Active Record model which includes PgSearch" do
|
|
1146
1155
|
context "when passed a :ranked_by expression" do
|
1147
1156
|
before do
|
1148
1157
|
ModelWithPgSearch.pg_search_scope :search_content_with_default_rank,
|
1149
|
-
|
1158
|
+
against: :content
|
1150
1159
|
|
1151
1160
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank,
|
1152
|
-
|
1153
|
-
|
1161
|
+
against: :content,
|
1162
|
+
ranked_by: "importance"
|
1154
1163
|
|
1155
1164
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank_multiplier,
|
1156
|
-
|
1157
|
-
|
1165
|
+
against: :content,
|
1166
|
+
ranked_by: ":tsearch * importance"
|
1158
1167
|
end
|
1159
1168
|
|
1160
|
-
it "
|
1169
|
+
it "returns records with a rank attribute equal to the :ranked_by expression" do
|
1161
1170
|
ModelWithPgSearch.create!(content: 'foo', importance: 10)
|
1162
1171
|
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo").with_pg_search_rank
|
1163
1172
|
expect(results.first.pg_search_rank).to eq(10)
|
1164
1173
|
end
|
1165
1174
|
|
1166
|
-
it "
|
1175
|
+
it "substitutes :tsearch with the tsearch rank expression in the :ranked_by expression" do
|
1167
1176
|
ModelWithPgSearch.create!(content: 'foo', importance: 10)
|
1168
1177
|
|
1169
1178
|
tsearch_result =
|
@@ -1181,7 +1190,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
1181
1190
|
expect(multiplied_rank).to be_within(0.001).of(tsearch_rank * 10)
|
1182
1191
|
end
|
1183
1192
|
|
1184
|
-
it "
|
1193
|
+
it "returns results in descending order of the value of the rank expression" do
|
1185
1194
|
records = [
|
1186
1195
|
ModelWithPgSearch.create!(content: 'foo', importance: 1),
|
1187
1196
|
ModelWithPgSearch.create!(content: 'foo', importance: 3),
|
@@ -1195,10 +1204,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
1195
1204
|
%w[tsearch trigram dmetaphone].each do |feature|
|
1196
1205
|
context "using the #{feature} ranking algorithm" do
|
1197
1206
|
let(:scope_name) { :"search_content_ranked_by_#{feature}" }
|
1207
|
+
|
1198
1208
|
before do
|
1199
1209
|
ModelWithPgSearch.pg_search_scope scope_name,
|
1200
|
-
|
1201
|
-
|
1210
|
+
against: :content,
|
1211
|
+
ranked_by: ":#{feature}"
|
1202
1212
|
|
1203
1213
|
ModelWithPgSearch.create!(content: 'foo')
|
1204
1214
|
end
|
@@ -1231,12 +1241,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1231
1241
|
end
|
1232
1242
|
end
|
1233
1243
|
|
1234
|
-
context "using the tsearch ranking algorithm" do
|
1244
|
+
context "when using the tsearch ranking algorithm" do
|
1235
1245
|
it "sorts results by the tsearch rank" do
|
1236
1246
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_tsearch,
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1247
|
+
using: :tsearch,
|
1248
|
+
against: :content,
|
1249
|
+
ranked_by: ":tsearch"
|
1240
1250
|
|
1241
1251
|
once = ModelWithPgSearch.create!(content: 'foo bar')
|
1242
1252
|
twice = ModelWithPgSearch.create!(content: 'foo foo')
|
@@ -1246,12 +1256,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1246
1256
|
end
|
1247
1257
|
end
|
1248
1258
|
|
1249
|
-
context "using the trigram ranking algorithm" do
|
1259
|
+
context "when using the trigram ranking algorithm" do
|
1250
1260
|
it "sorts results by the trigram rank" do
|
1251
1261
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_trigram,
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1262
|
+
using: :trigram,
|
1263
|
+
against: :content,
|
1264
|
+
ranked_by: ":trigram"
|
1255
1265
|
|
1256
1266
|
close = ModelWithPgSearch.create!(content: 'abcdef')
|
1257
1267
|
exact = ModelWithPgSearch.create!(content: 'abc')
|
@@ -1261,12 +1271,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1261
1271
|
end
|
1262
1272
|
end
|
1263
1273
|
|
1264
|
-
context "using the dmetaphone ranking algorithm" do
|
1274
|
+
context "when using the dmetaphone ranking algorithm" do
|
1265
1275
|
it "sorts results by the dmetaphone rank" do
|
1266
1276
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1277
|
+
using: :dmetaphone,
|
1278
|
+
against: :content,
|
1279
|
+
ranked_by: ":dmetaphone"
|
1270
1280
|
|
1271
1281
|
once = ModelWithPgSearch.create!(content: 'Phoo Bar')
|
1272
1282
|
twice = ModelWithPgSearch.create!(content: 'Phoo Fu')
|
@@ -1280,12 +1290,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1280
1290
|
context "when there is a sort only feature" do
|
1281
1291
|
it "excludes that feature from the conditions, but uses it in the sorting" do
|
1282
1292
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1293
|
+
against: :content,
|
1294
|
+
using: {
|
1295
|
+
tsearch: { any_word: true, prefix: true },
|
1296
|
+
dmetaphone: { any_word: true, prefix: true, sort_only: true }
|
1297
|
+
},
|
1298
|
+
ranked_by: ":tsearch + (0.5 * :dmetaphone)"
|
1289
1299
|
|
1290
1300
|
exact = ModelWithPgSearch.create!(content: "ash hines")
|
1291
1301
|
one_exact_one_close = ModelWithPgSearch.create!(content: "ash heinz")
|
@@ -1298,3 +1308,4 @@ describe "an Active Record model which includes PgSearch" do
|
|
1298
1308
|
end
|
1299
1309
|
end
|
1300
1310
|
end
|
1311
|
+
# rubocop:enable RSpec/NestedGroups
|