pg_search 2.3.6 → 2.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +47 -35
- data/.github/workflows/codeql.yml +87 -0
- data/.standard.yml +6 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +21 -6
- data/LICENSE +1 -1
- data/README.md +133 -114
- data/Rakefile +4 -13
- data/lib/pg_search/configuration/column.rb +6 -4
- data/lib/pg_search/configuration/foreign_column.rb +1 -1
- data/lib/pg_search/configuration.rb +11 -27
- data/lib/pg_search/document.rb +8 -8
- data/lib/pg_search/features/dmetaphone.rb +1 -1
- data/lib/pg_search/features/trigram.rb +4 -4
- data/lib/pg_search/features/tsearch.rb +23 -30
- data/lib/pg_search/migration/dmetaphone_generator.rb +2 -2
- data/lib/pg_search/migration/generator.rb +5 -5
- data/lib/pg_search/migration/multisearch_generator.rb +2 -2
- data/lib/pg_search/model.rb +12 -14
- data/lib/pg_search/multisearch/rebuilder.rb +4 -3
- data/lib/pg_search/multisearch.rb +4 -2
- data/lib/pg_search/multisearchable.rb +7 -7
- data/lib/pg_search/normalizer.rb +17 -7
- data/lib/pg_search/scope_options.rb +36 -8
- data/lib/pg_search/tasks.rb +2 -2
- data/lib/pg_search/version.rb +1 -1
- data/lib/pg_search.rb +3 -3
- data/pg_search.gemspec +16 -31
- data/spec/integration/associations_spec.rb +118 -106
- data/spec/integration/deprecation_spec.rb +12 -9
- data/spec/integration/pagination_spec.rb +1 -0
- data/spec/integration/pg_search_spec.rb +343 -298
- data/spec/integration/single_table_inheritance_spec.rb +7 -5
- data/spec/lib/pg_search/configuration/association_spec.rb +17 -15
- data/spec/lib/pg_search/configuration/column_spec.rb +13 -1
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +5 -4
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +4 -4
- data/spec/lib/pg_search/features/trigram_spec.rb +32 -33
- data/spec/lib/pg_search/features/tsearch_spec.rb +57 -39
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +70 -20
- data/spec/lib/pg_search/multisearch_spec.rb +8 -8
- data/spec/lib/pg_search/multisearchable_spec.rb +34 -26
- data/spec/lib/pg_search/normalizer_spec.rb +11 -11
- data/spec/lib/pg_search_spec.rb +22 -18
- data/spec/spec_helper.rb +3 -18
- data/spec/support/database.rb +6 -6
- metadata +11 -219
- data/.codeclimate.yml +0 -17
- data/.rubocop.yml +0 -137
- data/.travis.yml +0 -37
- data/spec/.rubocop.yml +0 -14
- data/spec/integration/.rubocop.yml +0 -11
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# standard:disable RSpec/NestedGroups
|
|
6
6
|
describe "an Active Record model which includes PgSearch" do
|
|
7
7
|
with_model :ModelWithPgSearch do
|
|
8
8
|
table do |t|
|
|
9
|
-
t.string
|
|
10
|
-
t.text
|
|
11
|
-
t.integer
|
|
12
|
-
t.integer
|
|
9
|
+
t.string "title"
|
|
10
|
+
t.text "content"
|
|
11
|
+
t.integer "parent_model_id"
|
|
12
|
+
t.integer "importance"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
model do
|
|
16
16
|
include PgSearch::Model
|
|
17
|
+
|
|
17
18
|
belongs_to :parent_model
|
|
18
19
|
end
|
|
19
20
|
end
|
|
@@ -24,6 +25,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
24
25
|
|
|
25
26
|
model do
|
|
26
27
|
include PgSearch::Model
|
|
28
|
+
|
|
27
29
|
has_many :models_with_pg_search
|
|
28
30
|
scope :active, -> { where(active: true) }
|
|
29
31
|
end
|
|
@@ -39,26 +41,38 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
39
41
|
context "when passed a lambda" do
|
|
40
42
|
it "builds a dynamic scope" do
|
|
41
43
|
ModelWithPgSearch.pg_search_scope :search_title_or_content,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
lambda { |query, pick_content|
|
|
45
|
+
{
|
|
46
|
+
query: query.gsub("-remove-", ""),
|
|
47
|
+
against: pick_content ? :content : :title
|
|
48
|
+
}
|
|
49
|
+
}
|
|
48
50
|
|
|
49
|
-
included = ModelWithPgSearch.create!(title:
|
|
50
|
-
|
|
51
|
+
included = ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
52
|
+
ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
53
|
+
|
|
54
|
+
expect(ModelWithPgSearch.search_title_or_content("fo-remove-o", false)).to eq([included])
|
|
55
|
+
expect(ModelWithPgSearch.search_title_or_content("b-remove-ar", true)).to eq([included])
|
|
56
|
+
end
|
|
57
|
+
end
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
context "when passed an invalid argument" do
|
|
60
|
+
it "builds a dynamic scope" do
|
|
61
|
+
expect {
|
|
62
|
+
ModelWithPgSearch.pg_search_scope :search_title_or_content, :some_symbol
|
|
63
|
+
}.to(
|
|
64
|
+
raise_exception(ArgumentError).with_message(
|
|
65
|
+
"pg_search_scope expects a Hash or Proc"
|
|
66
|
+
)
|
|
67
|
+
)
|
|
54
68
|
end
|
|
55
69
|
end
|
|
56
70
|
|
|
57
71
|
context "when an unknown option is passed in" do
|
|
58
72
|
it "raises an exception when invoked" do
|
|
59
73
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
against: :content,
|
|
75
|
+
foo: :bar
|
|
62
76
|
|
|
63
77
|
expect {
|
|
64
78
|
ModelWithPgSearch.with_unknown_option("foo")
|
|
@@ -68,7 +82,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
68
82
|
context "with a lambda" do
|
|
69
83
|
it "raises an exception when invoked" do
|
|
70
84
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
|
71
|
-
|
|
85
|
+
->(*) { {against: :content, foo: :bar} }
|
|
72
86
|
|
|
73
87
|
expect {
|
|
74
88
|
ModelWithPgSearch.with_unknown_option("foo")
|
|
@@ -80,8 +94,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
80
94
|
context "when an unknown :using is passed" do
|
|
81
95
|
it "raises an exception when invoked" do
|
|
82
96
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
against: :content,
|
|
98
|
+
using: :foo
|
|
85
99
|
|
|
86
100
|
expect {
|
|
87
101
|
ModelWithPgSearch.with_unknown_using("foo")
|
|
@@ -91,7 +105,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
91
105
|
context "with a lambda" do
|
|
92
106
|
it "raises an exception when invoked" do
|
|
93
107
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
|
94
|
-
|
|
108
|
+
->(*) { {against: :content, using: :foo} }
|
|
95
109
|
|
|
96
110
|
expect {
|
|
97
111
|
ModelWithPgSearch.with_unknown_using("foo")
|
|
@@ -103,8 +117,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
103
117
|
context "when an unknown :ignoring is passed" do
|
|
104
118
|
it "raises an exception when invoked" do
|
|
105
119
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
against: :content,
|
|
121
|
+
ignoring: :foo
|
|
108
122
|
|
|
109
123
|
expect {
|
|
110
124
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
|
@@ -114,7 +128,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
114
128
|
context "with a lambda" do
|
|
115
129
|
it "raises an exception when invoked" do
|
|
116
130
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
|
117
|
-
|
|
131
|
+
->(*) { {against: :content, ignoring: :foo} }
|
|
118
132
|
|
|
119
133
|
expect {
|
|
120
134
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
|
@@ -168,15 +182,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
168
182
|
|
|
169
183
|
context "when chained after a select() scope" do
|
|
170
184
|
it "honors the select" do
|
|
171
|
-
included = ModelWithPgSearch.create!(content:
|
|
172
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
185
|
+
included = ModelWithPgSearch.create!(content: "foo", title: "bar")
|
|
186
|
+
excluded = ModelWithPgSearch.create!(content: "bar", title: "foo")
|
|
173
187
|
|
|
174
|
-
results = ModelWithPgSearch.select(
|
|
188
|
+
results = ModelWithPgSearch.select("id, title").search_content("foo")
|
|
175
189
|
|
|
176
190
|
expect(results).to include(included)
|
|
177
191
|
expect(results).not_to include(excluded)
|
|
178
192
|
|
|
179
|
-
expect(results.first.attributes.key?(
|
|
193
|
+
expect(results.first.attributes.key?("content")).to be false
|
|
180
194
|
|
|
181
195
|
expect(results.select { |record| record.title == "bar" }).to eq [included]
|
|
182
196
|
expect(results.reject { |record| record.title == "bar" }).to be_empty
|
|
@@ -185,15 +199,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
185
199
|
|
|
186
200
|
context "when chained before a select() scope" do
|
|
187
201
|
it "honors the select" do
|
|
188
|
-
included = ModelWithPgSearch.create!(content:
|
|
189
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
202
|
+
included = ModelWithPgSearch.create!(content: "foo", title: "bar")
|
|
203
|
+
excluded = ModelWithPgSearch.create!(content: "bar", title: "foo")
|
|
190
204
|
|
|
191
|
-
results = ModelWithPgSearch.search_content(
|
|
205
|
+
results = ModelWithPgSearch.search_content("foo").select("id, title")
|
|
192
206
|
|
|
193
207
|
expect(results).to include(included)
|
|
194
208
|
expect(results).not_to include(excluded)
|
|
195
209
|
|
|
196
|
-
expect(results.first.attributes.key?(
|
|
210
|
+
expect(results.first.attributes.key?("content")).to be false
|
|
197
211
|
|
|
198
212
|
expect(results.select { |record| record.title == "bar" }).to eq [included]
|
|
199
213
|
expect(results.reject { |record| record.title == "bar" }).to be_empty
|
|
@@ -202,15 +216,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
202
216
|
|
|
203
217
|
context "when surrouned by select() scopes" do
|
|
204
218
|
it "honors the select" do
|
|
205
|
-
included = ModelWithPgSearch.create!(content:
|
|
206
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
219
|
+
included = ModelWithPgSearch.create!(content: "foo", title: "bar")
|
|
220
|
+
excluded = ModelWithPgSearch.create!(content: "bar", title: "foo")
|
|
207
221
|
|
|
208
|
-
results = ModelWithPgSearch.select(
|
|
222
|
+
results = ModelWithPgSearch.select("id").search_content("foo").select("title")
|
|
209
223
|
|
|
210
224
|
expect(results).to include(included)
|
|
211
225
|
expect(results).not_to include(excluded)
|
|
212
226
|
|
|
213
|
-
expect(results.first.attributes.key?(
|
|
227
|
+
expect(results.first.attributes.key?("content")).to be false
|
|
214
228
|
|
|
215
229
|
expect(results.select { |record| record.title == "bar" }).to eq [included]
|
|
216
230
|
expect(results.reject { |record| record.title == "bar" }).to be_empty
|
|
@@ -226,6 +240,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
226
240
|
|
|
227
241
|
model do
|
|
228
242
|
include PgSearch::Model
|
|
243
|
+
|
|
229
244
|
belongs_to :person
|
|
230
245
|
pg_search_scope :search_city, against: [:city]
|
|
231
246
|
end
|
|
@@ -238,10 +253,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
238
253
|
|
|
239
254
|
model do
|
|
240
255
|
include PgSearch::Model
|
|
256
|
+
|
|
241
257
|
has_many :houses
|
|
242
258
|
pg_search_scope :named, against: [:name]
|
|
243
259
|
scope :with_house_in_city, lambda { |city|
|
|
244
|
-
joins(:houses).where(House.table_name.to_sym => {
|
|
260
|
+
joins(:houses).where(House.table_name.to_sym => {city: city})
|
|
245
261
|
}
|
|
246
262
|
scope :house_search_city, lambda { |query|
|
|
247
263
|
joins(:houses).merge(House.search_city(query))
|
|
@@ -285,7 +301,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
285
301
|
|
|
286
302
|
context "when chaining merged scopes" do
|
|
287
303
|
it "does not raise an exception" do
|
|
288
|
-
relation = Person.named(
|
|
304
|
+
relation = Person.named("foo").house_search_city("bar")
|
|
289
305
|
|
|
290
306
|
expect { relation.to_a }.not_to raise_error
|
|
291
307
|
end
|
|
@@ -298,49 +314,49 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
298
314
|
end
|
|
299
315
|
|
|
300
316
|
it "does not raise an exception" do
|
|
301
|
-
relation = ModelWithPgSearch.search_content(
|
|
317
|
+
relation = ModelWithPgSearch.search_content("foo").search_title("bar")
|
|
302
318
|
|
|
303
319
|
expect { relation.to_a }.not_to raise_error
|
|
304
320
|
end
|
|
305
321
|
end
|
|
306
322
|
|
|
307
323
|
it "returns an empty array when a blank query is passed in" do
|
|
308
|
-
ModelWithPgSearch.create!(content:
|
|
324
|
+
ModelWithPgSearch.create!(content: "foo")
|
|
309
325
|
|
|
310
|
-
results = ModelWithPgSearch.search_content(
|
|
326
|
+
results = ModelWithPgSearch.search_content("")
|
|
311
327
|
expect(results).to eq([])
|
|
312
328
|
end
|
|
313
329
|
|
|
314
330
|
it "returns rows where the column contains the term in the query" do
|
|
315
|
-
included = ModelWithPgSearch.create!(content:
|
|
316
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
331
|
+
included = ModelWithPgSearch.create!(content: "foo")
|
|
332
|
+
excluded = ModelWithPgSearch.create!(content: "bar")
|
|
317
333
|
|
|
318
|
-
results = ModelWithPgSearch.search_content(
|
|
334
|
+
results = ModelWithPgSearch.search_content("foo")
|
|
319
335
|
expect(results).to include(included)
|
|
320
336
|
expect(results).not_to include(excluded)
|
|
321
337
|
end
|
|
322
338
|
|
|
323
339
|
it "returns the correct count" do
|
|
324
|
-
ModelWithPgSearch.create!(content:
|
|
325
|
-
ModelWithPgSearch.create!(content:
|
|
340
|
+
ModelWithPgSearch.create!(content: "foo")
|
|
341
|
+
ModelWithPgSearch.create!(content: "bar")
|
|
326
342
|
|
|
327
|
-
results = ModelWithPgSearch.search_content(
|
|
343
|
+
results = ModelWithPgSearch.search_content("foo")
|
|
328
344
|
expect(results.count).to eq 1
|
|
329
345
|
end
|
|
330
346
|
|
|
331
347
|
it "returns the correct count(:all)" do
|
|
332
|
-
ModelWithPgSearch.create!(content:
|
|
333
|
-
ModelWithPgSearch.create!(content:
|
|
348
|
+
ModelWithPgSearch.create!(content: "foo")
|
|
349
|
+
ModelWithPgSearch.create!(content: "bar")
|
|
334
350
|
|
|
335
|
-
results = ModelWithPgSearch.search_content(
|
|
351
|
+
results = ModelWithPgSearch.search_content("foo")
|
|
336
352
|
expect(results.count(:all)).to eq 1
|
|
337
353
|
end
|
|
338
354
|
|
|
339
355
|
it "supports #select" do
|
|
340
|
-
record = ModelWithPgSearch.create!(content:
|
|
341
|
-
|
|
356
|
+
record = ModelWithPgSearch.create!(content: "foo")
|
|
357
|
+
ModelWithPgSearch.create!(content: "bar")
|
|
342
358
|
|
|
343
|
-
records_with_only_id = ModelWithPgSearch.search_content(
|
|
359
|
+
records_with_only_id = ModelWithPgSearch.search_content("foo").select("id")
|
|
344
360
|
expect(records_with_only_id.length).to eq 1
|
|
345
361
|
|
|
346
362
|
returned_record = records_with_only_id.first
|
|
@@ -349,36 +365,36 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
349
365
|
end
|
|
350
366
|
|
|
351
367
|
it "supports #pluck" do
|
|
352
|
-
record = ModelWithPgSearch.create!(content:
|
|
353
|
-
|
|
368
|
+
record = ModelWithPgSearch.create!(content: "foo")
|
|
369
|
+
ModelWithPgSearch.create!(content: "bar")
|
|
354
370
|
|
|
355
|
-
ids = ModelWithPgSearch.search_content(
|
|
371
|
+
ids = ModelWithPgSearch.search_content("foo").pluck("id")
|
|
356
372
|
expect(ids).to eq [record.id]
|
|
357
373
|
end
|
|
358
374
|
|
|
359
375
|
it "supports adding where clauses using the pg_search.rank" do
|
|
360
|
-
|
|
361
|
-
twice = ModelWithPgSearch.create!(content:
|
|
376
|
+
ModelWithPgSearch.create!(content: "foo bar")
|
|
377
|
+
twice = ModelWithPgSearch.create!(content: "foo foo")
|
|
362
378
|
|
|
363
|
-
records = ModelWithPgSearch.search_content(
|
|
364
|
-
|
|
379
|
+
records = ModelWithPgSearch.search_content("foo")
|
|
380
|
+
.where("#{PgSearch::Configuration.alias(ModelWithPgSearch.table_name)}.rank > 0.07")
|
|
365
381
|
|
|
366
382
|
expect(records).to eq [twice]
|
|
367
383
|
end
|
|
368
384
|
|
|
369
385
|
it "returns rows where the column contains all the terms in the query in any order" do
|
|
370
|
-
included = [ModelWithPgSearch.create!(content:
|
|
371
|
-
|
|
372
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
386
|
+
included = [ModelWithPgSearch.create!(content: "foo bar"),
|
|
387
|
+
ModelWithPgSearch.create!(content: "bar foo")]
|
|
388
|
+
excluded = ModelWithPgSearch.create!(content: "foo")
|
|
373
389
|
|
|
374
|
-
results = ModelWithPgSearch.search_content(
|
|
390
|
+
results = ModelWithPgSearch.search_content("foo bar")
|
|
375
391
|
expect(results).to match_array(included)
|
|
376
392
|
expect(results).not_to include(excluded)
|
|
377
393
|
end
|
|
378
394
|
|
|
379
395
|
it "returns rows that match the query but not its case" do
|
|
380
396
|
included = [ModelWithPgSearch.create!(content: "foo"),
|
|
381
|
-
|
|
397
|
+
ModelWithPgSearch.create!(content: "FOO")]
|
|
382
398
|
|
|
383
399
|
results = ModelWithPgSearch.search_content("Foo")
|
|
384
400
|
expect(results).to match_array(included)
|
|
@@ -397,8 +413,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
397
413
|
end
|
|
398
414
|
|
|
399
415
|
it "returns rows that match the query but not rows that are prefixed by the query" do
|
|
400
|
-
included = ModelWithPgSearch.create!(content:
|
|
401
|
-
excluded = ModelWithPgSearch.create!(content:
|
|
416
|
+
included = ModelWithPgSearch.create!(content: "pre")
|
|
417
|
+
excluded = ModelWithPgSearch.create!(content: "prefix")
|
|
402
418
|
|
|
403
419
|
results = ModelWithPgSearch.search_content("pre")
|
|
404
420
|
expect(results).to eq([included])
|
|
@@ -407,36 +423,36 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
407
423
|
|
|
408
424
|
it "returns rows that match the query exactly and not those that match the query when stemmed by the default english dictionary" do
|
|
409
425
|
included = ModelWithPgSearch.create!(content: "jumped")
|
|
410
|
-
|
|
411
|
-
|
|
426
|
+
ModelWithPgSearch.create!(content: "jump")
|
|
427
|
+
ModelWithPgSearch.create!(content: "jumping")
|
|
412
428
|
|
|
413
429
|
results = ModelWithPgSearch.search_content("jumped")
|
|
414
430
|
expect(results).to eq([included])
|
|
415
431
|
end
|
|
416
432
|
|
|
417
433
|
it "returns rows that match sorted by rank" do
|
|
418
|
-
loser = ModelWithPgSearch.create!(content:
|
|
419
|
-
winner = ModelWithPgSearch.create!(content:
|
|
434
|
+
loser = ModelWithPgSearch.create!(content: "foo")
|
|
435
|
+
winner = ModelWithPgSearch.create!(content: "foo foo")
|
|
420
436
|
|
|
421
437
|
results = ModelWithPgSearch.search_content("foo").with_pg_search_rank
|
|
422
438
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
|
423
439
|
expect(results).to eq([winner, loser])
|
|
424
440
|
end
|
|
425
441
|
|
|
426
|
-
it
|
|
427
|
-
|
|
442
|
+
it "preserves column selection when with_pg_search_rank is chained after a select()" do
|
|
443
|
+
ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
428
444
|
|
|
429
|
-
results = ModelWithPgSearch.search_content(
|
|
445
|
+
results = ModelWithPgSearch.search_content("bar").select(:content).with_pg_search_rank
|
|
430
446
|
|
|
431
447
|
expect(results.length).to be 1
|
|
432
|
-
expect(results.first.as_json.keys).to contain_exactly(
|
|
448
|
+
expect(results.first.as_json.keys).to contain_exactly("id", "content", "pg_search_rank")
|
|
433
449
|
end
|
|
434
450
|
|
|
435
|
-
it
|
|
451
|
+
it "allows pg_search_rank along with a join" do
|
|
436
452
|
parent_1 = ParentModel.create!(id: 98)
|
|
437
453
|
parent_2 = ParentModel.create!(id: 99)
|
|
438
|
-
loser = ModelWithPgSearch.create!(content:
|
|
439
|
-
winner = ModelWithPgSearch.create!(content:
|
|
454
|
+
loser = ModelWithPgSearch.create!(content: "foo", parent_model: parent_2)
|
|
455
|
+
winner = ModelWithPgSearch.create!(content: "foo foo", parent_model: parent_1)
|
|
440
456
|
|
|
441
457
|
results = ModelWithPgSearch.joins(:parent_model).merge(ParentModel.active).search_content("foo").with_pg_search_rank
|
|
442
458
|
expect(results.map(&:id)).to eq [winner.id, loser.id]
|
|
@@ -445,8 +461,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
445
461
|
end
|
|
446
462
|
|
|
447
463
|
it "returns results that match sorted by primary key for records that rank the same" do
|
|
448
|
-
sorted_results = [ModelWithPgSearch.create!(content:
|
|
449
|
-
|
|
464
|
+
sorted_results = [ModelWithPgSearch.create!(content: "foo"),
|
|
465
|
+
ModelWithPgSearch.create!(content: "foo")].sort_by(&:id)
|
|
450
466
|
|
|
451
467
|
results = ModelWithPgSearch.search_content("foo")
|
|
452
468
|
expect(results).to eq(sorted_results)
|
|
@@ -454,16 +470,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
454
470
|
|
|
455
471
|
it "returns results that match a query with multiple space-separated search terms" do
|
|
456
472
|
included = [
|
|
457
|
-
ModelWithPgSearch.create!(content:
|
|
458
|
-
ModelWithPgSearch.create!(content:
|
|
459
|
-
ModelWithPgSearch.create!(content:
|
|
473
|
+
ModelWithPgSearch.create!(content: "foo bar"),
|
|
474
|
+
ModelWithPgSearch.create!(content: "bar foo"),
|
|
475
|
+
ModelWithPgSearch.create!(content: "bar foo baz")
|
|
460
476
|
]
|
|
461
477
|
excluded = [
|
|
462
|
-
ModelWithPgSearch.create!(content:
|
|
463
|
-
ModelWithPgSearch.create!(content:
|
|
478
|
+
ModelWithPgSearch.create!(content: "foo"),
|
|
479
|
+
ModelWithPgSearch.create!(content: "foo baz")
|
|
464
480
|
]
|
|
465
481
|
|
|
466
|
-
results = ModelWithPgSearch.search_content(
|
|
482
|
+
results = ModelWithPgSearch.search_content("foo bar")
|
|
467
483
|
expect(results).to match_array(included)
|
|
468
484
|
expect(results).not_to include(excluded)
|
|
469
485
|
end
|
|
@@ -477,7 +493,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
477
493
|
|
|
478
494
|
it "accepts non-string queries and calls #to_s on them" do
|
|
479
495
|
foo = ModelWithPgSearch.create!(content: "foo")
|
|
480
|
-
not_a_string = instance_double(
|
|
496
|
+
not_a_string = instance_double(Object, to_s: "foo")
|
|
481
497
|
expect(ModelWithPgSearch.search_content(not_a_string)).to eq([foo])
|
|
482
498
|
end
|
|
483
499
|
|
|
@@ -493,7 +509,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
493
509
|
# WARNING: searching timestamps is not something PostgreSQL
|
|
494
510
|
# full-text search is good at. Use at your own risk.
|
|
495
511
|
pg_search_scope :search_timestamps,
|
|
496
|
-
|
|
512
|
+
against: %i[created_at updated_at]
|
|
497
513
|
end
|
|
498
514
|
end
|
|
499
515
|
|
|
@@ -514,15 +530,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
514
530
|
|
|
515
531
|
it "returns rows whose columns contain all of the terms in the query across columns" do
|
|
516
532
|
included = [
|
|
517
|
-
ModelWithPgSearch.create!(title:
|
|
518
|
-
ModelWithPgSearch.create!(title:
|
|
533
|
+
ModelWithPgSearch.create!(title: "foo", content: "bar"),
|
|
534
|
+
ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
519
535
|
]
|
|
520
536
|
excluded = [
|
|
521
|
-
ModelWithPgSearch.create!(title:
|
|
522
|
-
ModelWithPgSearch.create!(title:
|
|
537
|
+
ModelWithPgSearch.create!(title: "foo", content: "foo"),
|
|
538
|
+
ModelWithPgSearch.create!(title: "bar", content: "bar")
|
|
523
539
|
]
|
|
524
540
|
|
|
525
|
-
results = ModelWithPgSearch.search_title_and_content(
|
|
541
|
+
results = ModelWithPgSearch.search_title_and_content("foo bar")
|
|
526
542
|
|
|
527
543
|
expect(results).to match_array(included)
|
|
528
544
|
excluded.each do |result|
|
|
@@ -531,17 +547,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
531
547
|
end
|
|
532
548
|
|
|
533
549
|
it "returns rows where at one column contains all of the terms in the query and another does not" do
|
|
534
|
-
in_title = ModelWithPgSearch.create!(title:
|
|
535
|
-
in_content = ModelWithPgSearch.create!(title:
|
|
550
|
+
in_title = ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
551
|
+
in_content = ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
536
552
|
|
|
537
|
-
results = ModelWithPgSearch.search_title_and_content(
|
|
538
|
-
expect(results).to
|
|
553
|
+
results = ModelWithPgSearch.search_title_and_content("foo")
|
|
554
|
+
expect(results).to contain_exactly(in_title, in_content)
|
|
539
555
|
end
|
|
540
556
|
|
|
541
557
|
# Searching with a NULL column will prevent any matches unless we coalesce it.
|
|
542
558
|
it "returns rows where at one column contains all of the terms in the query and another is NULL" do
|
|
543
|
-
included = ModelWithPgSearch.create!(title:
|
|
544
|
-
results
|
|
559
|
+
included = ModelWithPgSearch.create!(title: "foo", content: nil)
|
|
560
|
+
results = ModelWithPgSearch.search_title_and_content("foo")
|
|
545
561
|
expect(results).to eq([included])
|
|
546
562
|
end
|
|
547
563
|
end
|
|
@@ -552,21 +568,21 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
552
568
|
end
|
|
553
569
|
|
|
554
570
|
it "returns rows where one searchable column and the query share enough trigrams" do
|
|
555
|
-
included = ModelWithPgSearch.create!(title:
|
|
556
|
-
results = ModelWithPgSearch.with_trigrams(
|
|
571
|
+
included = ModelWithPgSearch.create!(title: "abcdefghijkl", content: nil)
|
|
572
|
+
results = ModelWithPgSearch.with_trigrams("cdefhijkl")
|
|
557
573
|
expect(results).to eq([included])
|
|
558
574
|
end
|
|
559
575
|
|
|
560
576
|
it "returns rows where multiple searchable columns and the query share enough trigrams" do
|
|
561
|
-
included = ModelWithPgSearch.create!(title:
|
|
562
|
-
results = ModelWithPgSearch.with_trigrams(
|
|
577
|
+
included = ModelWithPgSearch.create!(title: "abcdef", content: "ghijkl")
|
|
578
|
+
results = ModelWithPgSearch.with_trigrams("cdefhijkl")
|
|
563
579
|
expect(results).to eq([included])
|
|
564
580
|
end
|
|
565
581
|
|
|
566
582
|
context "when a threshold is specified" do
|
|
567
583
|
before do
|
|
568
|
-
ModelWithPgSearch.pg_search_scope :with_strict_trigrams, against: %i[title content], using: {
|
|
569
|
-
ModelWithPgSearch.pg_search_scope :with_permissive_trigrams, against: %i[title content], using: {
|
|
584
|
+
ModelWithPgSearch.pg_search_scope :with_strict_trigrams, against: %i[title content], using: {trigram: {threshold: 0.5}}
|
|
585
|
+
ModelWithPgSearch.pg_search_scope :with_permissive_trigrams, against: %i[title content], using: {trigram: {threshold: 0.1}}
|
|
570
586
|
end
|
|
571
587
|
|
|
572
588
|
it "uses the threshold in the trigram expression" do
|
|
@@ -591,16 +607,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
591
607
|
context "when using tsearch" do
|
|
592
608
|
before do
|
|
593
609
|
ModelWithPgSearch.pg_search_scope :search_title_with_prefixes,
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
610
|
+
against: :title,
|
|
611
|
+
using: {
|
|
612
|
+
tsearch: {prefix: true}
|
|
613
|
+
}
|
|
598
614
|
end
|
|
599
615
|
|
|
600
616
|
context "with prefix: true" do
|
|
601
617
|
it "returns rows that match the query and that are prefixed by the query" do
|
|
602
|
-
included = ModelWithPgSearch.create!(title:
|
|
603
|
-
excluded = ModelWithPgSearch.create!(title:
|
|
618
|
+
included = ModelWithPgSearch.create!(title: "prefix")
|
|
619
|
+
excluded = ModelWithPgSearch.create!(title: "postfix")
|
|
604
620
|
|
|
605
621
|
results = ModelWithPgSearch.search_title_with_prefixes("pre")
|
|
606
622
|
expect(results).to eq([included])
|
|
@@ -608,8 +624,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
608
624
|
end
|
|
609
625
|
|
|
610
626
|
it "returns rows that match the query when the query has a hyphen" do
|
|
611
|
-
included = ModelWithPgSearch.create!(title:
|
|
612
|
-
excluded = ModelWithPgSearch.create!(title:
|
|
627
|
+
included = ModelWithPgSearch.create!(title: "foo-bar")
|
|
628
|
+
excluded = ModelWithPgSearch.create!(title: "foo bar")
|
|
613
629
|
|
|
614
630
|
results = ModelWithPgSearch.search_title_with_prefixes("foo-bar")
|
|
615
631
|
expect(results).to include(included)
|
|
@@ -620,16 +636,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
620
636
|
context "with the english dictionary" do
|
|
621
637
|
before do
|
|
622
638
|
ModelWithPgSearch.pg_search_scope :search_content_with_english,
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
639
|
+
against: :content,
|
|
640
|
+
using: {
|
|
641
|
+
tsearch: {dictionary: :english}
|
|
642
|
+
}
|
|
627
643
|
end
|
|
628
644
|
|
|
629
645
|
it "returns rows that match the query when stemmed by the english dictionary" do
|
|
630
646
|
included = [ModelWithPgSearch.create!(content: "jump"),
|
|
631
|
-
|
|
632
|
-
|
|
647
|
+
ModelWithPgSearch.create!(content: "jumped"),
|
|
648
|
+
ModelWithPgSearch.create!(content: "jumping")]
|
|
633
649
|
|
|
634
650
|
results = ModelWithPgSearch.search_content_with_english("jump")
|
|
635
651
|
expect(results).to match_array(included)
|
|
@@ -639,14 +655,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
639
655
|
describe "highlighting" do
|
|
640
656
|
before do
|
|
641
657
|
["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
|
|
642
|
-
ModelWithPgSearch.create! title:
|
|
658
|
+
ModelWithPgSearch.create! title: "Just a title", content: name
|
|
643
659
|
end
|
|
644
660
|
end
|
|
645
661
|
|
|
646
662
|
context "with highlight turned on" do
|
|
647
663
|
before do
|
|
648
664
|
ModelWithPgSearch.pg_search_scope :search_content,
|
|
649
|
-
|
|
665
|
+
against: :content
|
|
650
666
|
end
|
|
651
667
|
|
|
652
668
|
it "adds a #pg_search_highlight method to each returned model record" do
|
|
@@ -661,31 +677,31 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
661
677
|
expect(result.pg_search_highlight).to eq("Won't <b>Let</b> You Down")
|
|
662
678
|
end
|
|
663
679
|
|
|
664
|
-
it
|
|
680
|
+
it "preserves column selection when with_pg_search_highlight is chained after a select()" do
|
|
665
681
|
result = ModelWithPgSearch.search_content("Let").select(:content).with_pg_search_highlight.first
|
|
666
682
|
|
|
667
|
-
expect(result.as_json.keys).to contain_exactly(
|
|
683
|
+
expect(result.as_json.keys).to contain_exactly("id", "content", "pg_search_highlight")
|
|
668
684
|
end
|
|
669
685
|
end
|
|
670
686
|
|
|
671
687
|
context "with custom highlighting options" do
|
|
672
688
|
before do
|
|
673
|
-
ModelWithPgSearch.create! content: "#{
|
|
689
|
+
ModelWithPgSearch.create! content: "#{"text " * 2}Let #{"text " * 2}Let #{"text " * 2}"
|
|
674
690
|
|
|
675
691
|
ModelWithPgSearch.pg_search_scope :search_content,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
692
|
+
against: :content,
|
|
693
|
+
using: {
|
|
694
|
+
tsearch: {
|
|
695
|
+
highlight: {
|
|
696
|
+
StartSel: '<mark class="highlight">',
|
|
697
|
+
StopSel: "</mark>",
|
|
698
|
+
FragmentDelimiter: '<delim class="my_delim">',
|
|
699
|
+
MaxFragments: 2,
|
|
700
|
+
MaxWords: 2,
|
|
701
|
+
MinWords: 1
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
689
705
|
end
|
|
690
706
|
|
|
691
707
|
it "applies the options to the excerpts" do
|
|
@@ -714,10 +730,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
714
730
|
context "with a normalization specified" do
|
|
715
731
|
before do
|
|
716
732
|
ModelWithPgSearch.pg_search_scope :search_content_with_normalization,
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
733
|
+
against: :content,
|
|
734
|
+
using: {
|
|
735
|
+
tsearch: {normalization: 2}
|
|
736
|
+
}
|
|
721
737
|
end
|
|
722
738
|
|
|
723
739
|
it "ranks the results for documents with less text higher" do
|
|
@@ -731,8 +747,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
731
747
|
context "with no normalization" do
|
|
732
748
|
before do
|
|
733
749
|
ModelWithPgSearch.pg_search_scope :search_content_without_normalization,
|
|
734
|
-
|
|
735
|
-
|
|
750
|
+
against: :content,
|
|
751
|
+
using: :tsearch
|
|
736
752
|
end
|
|
737
753
|
|
|
738
754
|
it "ranks the results equally" do
|
|
@@ -747,14 +763,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
747
763
|
context "when against columns ranked with arrays" do
|
|
748
764
|
before do
|
|
749
765
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_array_of_arrays,
|
|
750
|
-
|
|
766
|
+
against: [[:content, "B"], [:title, "A"]]
|
|
751
767
|
end
|
|
752
768
|
|
|
753
769
|
it "returns results sorted by weighted rank" do
|
|
754
|
-
loser = ModelWithPgSearch.create!(title:
|
|
755
|
-
winner = ModelWithPgSearch.create!(title:
|
|
770
|
+
loser = ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
771
|
+
winner = ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
756
772
|
|
|
757
|
-
results = ModelWithPgSearch.search_weighted_by_array_of_arrays(
|
|
773
|
+
results = ModelWithPgSearch.search_weighted_by_array_of_arrays("foo").with_pg_search_rank
|
|
758
774
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
|
759
775
|
expect(results).to eq([winner, loser])
|
|
760
776
|
end
|
|
@@ -763,14 +779,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
763
779
|
context "when against columns ranked with a hash" do
|
|
764
780
|
before do
|
|
765
781
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_hash,
|
|
766
|
-
|
|
782
|
+
against: {content: "B", title: "A"}
|
|
767
783
|
end
|
|
768
784
|
|
|
769
785
|
it "returns results sorted by weighted rank" do
|
|
770
|
-
loser = ModelWithPgSearch.create!(title:
|
|
771
|
-
winner = ModelWithPgSearch.create!(title:
|
|
786
|
+
loser = ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
787
|
+
winner = ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
772
788
|
|
|
773
|
-
results = ModelWithPgSearch.search_weighted_by_hash(
|
|
789
|
+
results = ModelWithPgSearch.search_weighted_by_hash("foo").with_pg_search_rank
|
|
774
790
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
|
775
791
|
expect(results).to eq([winner, loser])
|
|
776
792
|
end
|
|
@@ -779,14 +795,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
779
795
|
context "when against columns of which only some are ranked" do
|
|
780
796
|
before do
|
|
781
797
|
ModelWithPgSearch.pg_search_scope :search_weighted,
|
|
782
|
-
|
|
798
|
+
against: [:content, [:title, "A"]]
|
|
783
799
|
end
|
|
784
800
|
|
|
785
801
|
it "returns results sorted by weighted rank using an implied low rank for unranked columns" do
|
|
786
|
-
loser = ModelWithPgSearch.create!(title:
|
|
787
|
-
winner = ModelWithPgSearch.create!(title:
|
|
802
|
+
loser = ModelWithPgSearch.create!(title: "bar", content: "foo")
|
|
803
|
+
winner = ModelWithPgSearch.create!(title: "foo", content: "bar")
|
|
788
804
|
|
|
789
|
-
results = ModelWithPgSearch.search_weighted(
|
|
805
|
+
results = ModelWithPgSearch.search_weighted("foo").with_pg_search_rank
|
|
790
806
|
expect(results[0].pg_search_rank).to be > results[1].pg_search_rank
|
|
791
807
|
expect(results).to eq([winner, loser])
|
|
792
808
|
end
|
|
@@ -795,17 +811,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
795
811
|
context "when searching any_word option" do
|
|
796
812
|
before do
|
|
797
813
|
ModelWithPgSearch.pg_search_scope :search_title_with_any_word,
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
814
|
+
against: :title,
|
|
815
|
+
using: {
|
|
816
|
+
tsearch: {any_word: true}
|
|
817
|
+
}
|
|
802
818
|
|
|
803
819
|
ModelWithPgSearch.pg_search_scope :search_title_with_all_words,
|
|
804
|
-
|
|
820
|
+
against: :title
|
|
805
821
|
end
|
|
806
822
|
|
|
807
823
|
it "returns all results containing any word in their title" do
|
|
808
|
-
|
|
824
|
+
%w[one two three four].map { |number| ModelWithPgSearch.create!(title: number) }
|
|
809
825
|
|
|
810
826
|
results = ModelWithPgSearch.search_title_with_any_word("one two three four")
|
|
811
827
|
|
|
@@ -820,10 +836,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
820
836
|
context "with :negation" do
|
|
821
837
|
before do
|
|
822
838
|
ModelWithPgSearch.pg_search_scope :search_with_negation,
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
839
|
+
against: :title,
|
|
840
|
+
using: {
|
|
841
|
+
tsearch: {negation: true}
|
|
842
|
+
}
|
|
827
843
|
end
|
|
828
844
|
|
|
829
845
|
it "doesn't return results that contain terms prepended with '!'" do
|
|
@@ -847,10 +863,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
847
863
|
context "without :negation" do
|
|
848
864
|
before do
|
|
849
865
|
ModelWithPgSearch.pg_search_scope :search_without_negation,
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
866
|
+
against: :title,
|
|
867
|
+
using: {
|
|
868
|
+
tsearch: {}
|
|
869
|
+
}
|
|
854
870
|
end
|
|
855
871
|
|
|
856
872
|
it "return results that contain terms prepended with '!'" do
|
|
@@ -873,38 +889,37 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
873
889
|
context "when using dmetaphone" do
|
|
874
890
|
before do
|
|
875
891
|
ModelWithPgSearch.pg_search_scope :with_dmetaphones,
|
|
876
|
-
|
|
877
|
-
|
|
892
|
+
against: %i[title content],
|
|
893
|
+
using: :dmetaphone
|
|
878
894
|
end
|
|
879
895
|
|
|
880
896
|
it "returns rows where one searchable column and the query share enough dmetaphones" do
|
|
881
|
-
included = ModelWithPgSearch.create!(title:
|
|
882
|
-
|
|
883
|
-
results = ModelWithPgSearch.with_dmetaphones(
|
|
897
|
+
included = ModelWithPgSearch.create!(title: "Geoff", content: nil)
|
|
898
|
+
ModelWithPgSearch.create!(title: "Bob", content: nil)
|
|
899
|
+
results = ModelWithPgSearch.with_dmetaphones("Jeff")
|
|
884
900
|
expect(results).to eq([included])
|
|
885
901
|
end
|
|
886
902
|
|
|
887
903
|
it "returns rows where multiple searchable columns and the query share enough dmetaphones" do
|
|
888
|
-
included = ModelWithPgSearch.create!(title:
|
|
889
|
-
|
|
890
|
-
results = ModelWithPgSearch.with_dmetaphones(
|
|
904
|
+
included = ModelWithPgSearch.create!(title: "Geoff", content: "George")
|
|
905
|
+
ModelWithPgSearch.create!(title: "Bob", content: "Jones")
|
|
906
|
+
results = ModelWithPgSearch.with_dmetaphones("Jeff Jorge")
|
|
891
907
|
expect(results).to eq([included])
|
|
892
908
|
end
|
|
893
909
|
|
|
894
910
|
it "returns rows that match dmetaphones that are English stopwords" do
|
|
895
|
-
included = ModelWithPgSearch.create!(title:
|
|
896
|
-
|
|
897
|
-
results = ModelWithPgSearch.with_dmetaphones(
|
|
911
|
+
included = ModelWithPgSearch.create!(title: "White", content: nil)
|
|
912
|
+
ModelWithPgSearch.create!(title: "Black", content: nil)
|
|
913
|
+
results = ModelWithPgSearch.with_dmetaphones("Wight")
|
|
898
914
|
expect(results).to eq([included])
|
|
899
915
|
end
|
|
900
916
|
|
|
901
917
|
it "can handle terms that do not have a dmetaphone equivalent" do
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
included = ModelWithPgSearch.create!(title: 'White', content: nil)
|
|
905
|
-
excluded = ModelWithPgSearch.create!(title: 'Black', content: nil)
|
|
918
|
+
included = ModelWithPgSearch.create!(title: "White", content: nil)
|
|
919
|
+
ModelWithPgSearch.create!(title: "Black", content: nil)
|
|
906
920
|
|
|
907
|
-
|
|
921
|
+
# "W" does not have a dmetaphone equivalent
|
|
922
|
+
results = ModelWithPgSearch.with_dmetaphones("Wight W")
|
|
908
923
|
expect(results).to eq([included])
|
|
909
924
|
end
|
|
910
925
|
end
|
|
@@ -912,35 +927,35 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
912
927
|
context "when using multiple features" do
|
|
913
928
|
before do
|
|
914
929
|
ModelWithPgSearch.pg_search_scope :with_tsearch,
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
930
|
+
against: :title,
|
|
931
|
+
using: [
|
|
932
|
+
[:tsearch, {dictionary: "english"}]
|
|
933
|
+
]
|
|
919
934
|
|
|
920
935
|
ModelWithPgSearch.pg_search_scope :with_trigram,
|
|
921
|
-
|
|
922
|
-
|
|
936
|
+
against: :title,
|
|
937
|
+
using: :trigram
|
|
923
938
|
|
|
924
939
|
ModelWithPgSearch.pg_search_scope :with_trigram_and_ignoring_accents,
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
940
|
+
against: :title,
|
|
941
|
+
ignoring: :accents,
|
|
942
|
+
using: :trigram
|
|
928
943
|
|
|
929
944
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram,
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
945
|
+
against: :title,
|
|
946
|
+
using: [
|
|
947
|
+
[:tsearch, {dictionary: "english"}],
|
|
948
|
+
:trigram
|
|
949
|
+
]
|
|
935
950
|
|
|
936
951
|
ModelWithPgSearch.pg_search_scope :complex_search,
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
952
|
+
against: %i[content title],
|
|
953
|
+
ignoring: :accents,
|
|
954
|
+
using: {
|
|
955
|
+
tsearch: {dictionary: "english"},
|
|
956
|
+
dmetaphone: {},
|
|
957
|
+
trigram: {}
|
|
958
|
+
}
|
|
944
959
|
end
|
|
945
960
|
|
|
946
961
|
it "returns rows that match using any of the features" do
|
|
@@ -982,24 +997,24 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
982
997
|
end
|
|
983
998
|
|
|
984
999
|
context "with feature-specific configuration" do
|
|
985
|
-
let(:tsearch_config) { {
|
|
986
|
-
let(:trigram_config) { {
|
|
1000
|
+
let(:tsearch_config) { {dictionary: "english"} }
|
|
1001
|
+
let(:trigram_config) { {foo: "bar"} }
|
|
987
1002
|
|
|
988
1003
|
before do
|
|
989
1004
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram_using_hash,
|
|
990
|
-
|
|
991
|
-
|
|
1005
|
+
against: :title,
|
|
1006
|
+
using: {tsearch: tsearch_config, trigram: trigram_config}
|
|
992
1007
|
end
|
|
993
1008
|
|
|
994
1009
|
it "passes the custom configuration down to the specified feature" do
|
|
995
1010
|
tsearch_feature = instance_double(
|
|
996
|
-
|
|
1011
|
+
PgSearch::Features::TSearch,
|
|
997
1012
|
conditions: Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
|
998
1013
|
rank: Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
|
999
1014
|
)
|
|
1000
1015
|
|
|
1001
1016
|
trigram_feature = instance_double(
|
|
1002
|
-
|
|
1017
|
+
PgSearch::Features::Trigram,
|
|
1003
1018
|
conditions: Arel::Nodes::Grouping.new(Arel.sql("1 = 1")),
|
|
1004
1019
|
rank: Arel::Nodes::Grouping.new(Arel.sql("1.0"))
|
|
1005
1020
|
)
|
|
@@ -1029,18 +1044,19 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1029
1044
|
|
|
1030
1045
|
with_model :Post do
|
|
1031
1046
|
table do |t|
|
|
1032
|
-
t.text
|
|
1033
|
-
t.tsvector
|
|
1047
|
+
t.text "content"
|
|
1048
|
+
t.tsvector "content_tsvector"
|
|
1034
1049
|
end
|
|
1035
1050
|
|
|
1036
1051
|
model do
|
|
1037
1052
|
include PgSearch::Model
|
|
1053
|
+
|
|
1038
1054
|
has_many :comments
|
|
1039
1055
|
end
|
|
1040
1056
|
end
|
|
1041
1057
|
|
|
1042
|
-
let!(:expected) { Post.create!(content:
|
|
1043
|
-
let!(:unexpected) { Post.create!(content:
|
|
1058
|
+
let!(:expected) { Post.create!(content: "phooey") }
|
|
1059
|
+
let!(:unexpected) { Post.create!(content: "longcat is looooooooong") }
|
|
1044
1060
|
|
|
1045
1061
|
before do
|
|
1046
1062
|
ActiveRecord::Base.connection.execute <<~SQL.squish
|
|
@@ -1048,17 +1064,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1048
1064
|
SET content_tsvector = to_tsvector('english'::regconfig, #{Post.quoted_table_name}."content")
|
|
1049
1065
|
SQL
|
|
1050
1066
|
|
|
1051
|
-
expected.comments.create(body:
|
|
1052
|
-
unexpected.comments.create(body:
|
|
1067
|
+
expected.comments.create!(body: "commentone")
|
|
1068
|
+
unexpected.comments.create!(body: "commentwo")
|
|
1053
1069
|
|
|
1054
1070
|
Post.pg_search_scope :search_by_content_with_tsvector,
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1071
|
+
associated_against: {comments: [:body]},
|
|
1072
|
+
using: {
|
|
1073
|
+
tsearch: {
|
|
1074
|
+
tsvector_column: "content_tsvector",
|
|
1075
|
+
dictionary: "english"
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1062
1078
|
end
|
|
1063
1079
|
|
|
1064
1080
|
it "finds by the tsvector column" do
|
|
@@ -1069,29 +1085,53 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1069
1085
|
expect(Post.search_by_content_with_tsvector("commentone").map(&:id)).to eq([expected.id])
|
|
1070
1086
|
end
|
|
1071
1087
|
|
|
1072
|
-
it
|
|
1088
|
+
it "finds by a combination of the two" do
|
|
1073
1089
|
expect(Post.search_by_content_with_tsvector("phooey commentone").map(&:id)).to eq([expected.id])
|
|
1074
1090
|
end
|
|
1091
|
+
|
|
1092
|
+
it "finds by the tsvector column when ordering by an associated table" do
|
|
1093
|
+
# Reference the physical table name that Active Record would normally
|
|
1094
|
+
# leave unaliased. The old string rank join made AliasTracker think the
|
|
1095
|
+
# name was already used and alias this outer join, breaking the order.
|
|
1096
|
+
# https://github.com/Casecommons/pg_search/issues/206
|
|
1097
|
+
results = Post
|
|
1098
|
+
.joins(:comments)
|
|
1099
|
+
.search_by_content_with_tsvector("phooey")
|
|
1100
|
+
.order(Comment.table_name => {id: :asc})
|
|
1101
|
+
|
|
1102
|
+
expect(results).to eq([expected])
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
it "finds by the tsvector column when ordering by an association alias" do
|
|
1106
|
+
results = Post
|
|
1107
|
+
.joins(:comments)
|
|
1108
|
+
.search_by_content_with_tsvector("phooey")
|
|
1109
|
+
.order(comments: {id: :asc})
|
|
1110
|
+
|
|
1111
|
+
expect(results).to eq([expected])
|
|
1112
|
+
end
|
|
1075
1113
|
end
|
|
1076
1114
|
|
|
1077
|
-
context
|
|
1115
|
+
context "when using multiple tsvector columns" do
|
|
1078
1116
|
with_model :ModelWithTsvector do
|
|
1117
|
+
table
|
|
1118
|
+
|
|
1079
1119
|
model do
|
|
1080
1120
|
include PgSearch::Model
|
|
1081
1121
|
|
|
1082
1122
|
pg_search_scope :search_by_multiple_tsvector_columns,
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1123
|
+
against: ["content", "message"],
|
|
1124
|
+
using: {
|
|
1125
|
+
tsearch: {
|
|
1126
|
+
tsvector_column: ["content_tsvector", "message_tsvector"],
|
|
1127
|
+
dictionary: "english"
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1090
1130
|
end
|
|
1091
1131
|
end
|
|
1092
1132
|
|
|
1093
|
-
it
|
|
1094
|
-
expected = "#{ModelWithTsvector.quoted_table_name}.\"content_tsvector\" || "\
|
|
1133
|
+
it "concats tsvector columns" do
|
|
1134
|
+
expected = "#{ModelWithTsvector.quoted_table_name}.\"content_tsvector\" || " \
|
|
1095
1135
|
"#{ModelWithTsvector.quoted_table_name}.\"message_tsvector\""
|
|
1096
1136
|
|
|
1097
1137
|
expect(ModelWithTsvector.search_by_multiple_tsvector_columns("something").to_sql).to include(expected)
|
|
@@ -1101,17 +1141,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1101
1141
|
context "when using a tsvector column with" do
|
|
1102
1142
|
with_model :ModelWithTsvector do
|
|
1103
1143
|
table do |t|
|
|
1104
|
-
t.text
|
|
1105
|
-
t.tsvector
|
|
1144
|
+
t.text "content"
|
|
1145
|
+
t.tsvector "content_tsvector"
|
|
1106
1146
|
end
|
|
1107
1147
|
|
|
1108
1148
|
model { include PgSearch::Model }
|
|
1109
1149
|
end
|
|
1110
1150
|
|
|
1111
|
-
let!(:expected) { ModelWithTsvector.create!(content:
|
|
1151
|
+
let!(:expected) { ModelWithTsvector.create!(content: "tiling is grouty") }
|
|
1112
1152
|
|
|
1113
1153
|
before do
|
|
1114
|
-
ModelWithTsvector.create!(content:
|
|
1154
|
+
ModelWithTsvector.create!(content: "longcat is looooooooong")
|
|
1115
1155
|
|
|
1116
1156
|
ActiveRecord::Base.connection.execute <<~SQL.squish
|
|
1117
1157
|
UPDATE #{ModelWithTsvector.quoted_table_name}
|
|
@@ -1119,13 +1159,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1119
1159
|
SQL
|
|
1120
1160
|
|
|
1121
1161
|
ModelWithTsvector.pg_search_scope :search_by_content_with_tsvector,
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1162
|
+
against: :content,
|
|
1163
|
+
using: {
|
|
1164
|
+
tsearch: {
|
|
1165
|
+
tsvector_column: "content_tsvector",
|
|
1166
|
+
dictionary: "english"
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1129
1169
|
end
|
|
1130
1170
|
|
|
1131
1171
|
it "does not use to_tsvector in the query" do
|
|
@@ -1159,8 +1199,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1159
1199
|
context "when ignoring accents" do
|
|
1160
1200
|
before do
|
|
1161
1201
|
ModelWithPgSearch.pg_search_scope :search_title_without_accents,
|
|
1162
|
-
|
|
1163
|
-
|
|
1202
|
+
against: :title,
|
|
1203
|
+
ignoring: :accents
|
|
1164
1204
|
end
|
|
1165
1205
|
|
|
1166
1206
|
it "returns rows that match the query but not its accents" do
|
|
@@ -1174,11 +1214,16 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1174
1214
|
end
|
|
1175
1215
|
|
|
1176
1216
|
context "when the query includes accents" do
|
|
1177
|
-
|
|
1178
|
-
|
|
1217
|
+
let(:term) { "L#{%w[‘ ’ ʻ ʼ ʹ ʽ ˈ ' ʼn].sample}Content" }
|
|
1218
|
+
let(:included) { ModelWithPgSearch.create!(title: "Weird #{term}") }
|
|
1219
|
+
let(:results) { ModelWithPgSearch.search_title_without_accents(term) }
|
|
1179
1220
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1221
|
+
before do
|
|
1222
|
+
ModelWithPgSearch.create!(title: "FooBar")
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
it "does not create an erroneous tsquery expression" do
|
|
1226
|
+
expect(results).to contain_exactly(included)
|
|
1182
1227
|
end
|
|
1183
1228
|
end
|
|
1184
1229
|
end
|
|
@@ -1186,25 +1231,25 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1186
1231
|
context "when passed a :ranked_by expression" do
|
|
1187
1232
|
before do
|
|
1188
1233
|
ModelWithPgSearch.pg_search_scope :search_content_with_default_rank,
|
|
1189
|
-
|
|
1234
|
+
against: :content
|
|
1190
1235
|
|
|
1191
1236
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank,
|
|
1192
|
-
|
|
1193
|
-
|
|
1237
|
+
against: :content,
|
|
1238
|
+
ranked_by: "importance"
|
|
1194
1239
|
|
|
1195
1240
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank_multiplier,
|
|
1196
|
-
|
|
1197
|
-
|
|
1241
|
+
against: :content,
|
|
1242
|
+
ranked_by: ":tsearch * importance"
|
|
1198
1243
|
end
|
|
1199
1244
|
|
|
1200
1245
|
it "returns records with a rank attribute equal to the :ranked_by expression" do
|
|
1201
|
-
ModelWithPgSearch.create!(content:
|
|
1246
|
+
ModelWithPgSearch.create!(content: "foo", importance: 10)
|
|
1202
1247
|
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo").with_pg_search_rank
|
|
1203
1248
|
expect(results.first.pg_search_rank).to eq(10)
|
|
1204
1249
|
end
|
|
1205
1250
|
|
|
1206
1251
|
it "substitutes :tsearch with the tsearch rank expression in the :ranked_by expression" do
|
|
1207
|
-
ModelWithPgSearch.create!(content:
|
|
1252
|
+
ModelWithPgSearch.create!(content: "foo", importance: 10)
|
|
1208
1253
|
|
|
1209
1254
|
tsearch_result =
|
|
1210
1255
|
ModelWithPgSearch.search_content_with_default_rank("foo").with_pg_search_rank.first
|
|
@@ -1213,8 +1258,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1213
1258
|
|
|
1214
1259
|
multiplied_result =
|
|
1215
1260
|
ModelWithPgSearch.search_content_with_importance_as_rank_multiplier("foo")
|
|
1216
|
-
|
|
1217
|
-
|
|
1261
|
+
.with_pg_search_rank
|
|
1262
|
+
.first
|
|
1218
1263
|
|
|
1219
1264
|
multiplied_rank = multiplied_result.pg_search_rank
|
|
1220
1265
|
|
|
@@ -1223,9 +1268,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1223
1268
|
|
|
1224
1269
|
it "returns results in descending order of the value of the rank expression" do
|
|
1225
1270
|
records = [
|
|
1226
|
-
ModelWithPgSearch.create!(content:
|
|
1227
|
-
ModelWithPgSearch.create!(content:
|
|
1228
|
-
ModelWithPgSearch.create!(content:
|
|
1271
|
+
ModelWithPgSearch.create!(content: "foo", importance: 1),
|
|
1272
|
+
ModelWithPgSearch.create!(content: "foo", importance: 3),
|
|
1273
|
+
ModelWithPgSearch.create!(content: "foo", importance: 2)
|
|
1229
1274
|
]
|
|
1230
1275
|
|
|
1231
1276
|
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo")
|
|
@@ -1238,32 +1283,32 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1238
1283
|
|
|
1239
1284
|
before do
|
|
1240
1285
|
ModelWithPgSearch.pg_search_scope scope_name,
|
|
1241
|
-
|
|
1242
|
-
|
|
1286
|
+
against: :content,
|
|
1287
|
+
ranked_by: ":#{feature}"
|
|
1243
1288
|
|
|
1244
|
-
ModelWithPgSearch.create!(content:
|
|
1289
|
+
ModelWithPgSearch.create!(content: "foo")
|
|
1245
1290
|
end
|
|
1246
1291
|
|
|
1247
1292
|
context "when .with_pg_search_rank is chained after" do
|
|
1248
1293
|
specify "its results respond to #pg_search_rank" do
|
|
1249
|
-
result = ModelWithPgSearch.send(scope_name,
|
|
1294
|
+
result = ModelWithPgSearch.send(scope_name, "foo").with_pg_search_rank.first
|
|
1250
1295
|
expect(result).to respond_to(:pg_search_rank)
|
|
1251
1296
|
end
|
|
1252
1297
|
|
|
1253
1298
|
it "returns the rank when #pg_search_rank is called on a result" do
|
|
1254
|
-
results = ModelWithPgSearch.send(scope_name,
|
|
1299
|
+
results = ModelWithPgSearch.send(scope_name, "foo").with_pg_search_rank
|
|
1255
1300
|
expect(results.first.pg_search_rank).to be_a Float
|
|
1256
1301
|
end
|
|
1257
1302
|
end
|
|
1258
1303
|
|
|
1259
1304
|
context "when .with_pg_search_rank is not chained after" do
|
|
1260
1305
|
specify "its results do not respond to #pg_search_rank" do
|
|
1261
|
-
result = ModelWithPgSearch.send(scope_name,
|
|
1306
|
+
result = ModelWithPgSearch.send(scope_name, "foo").first
|
|
1262
1307
|
expect(result).not_to respond_to(:pg_search_rank)
|
|
1263
1308
|
end
|
|
1264
1309
|
|
|
1265
1310
|
it "raises PgSearch::PgSearchRankNotSelected when #pg_search_rank is called on a result" do
|
|
1266
|
-
result = ModelWithPgSearch.send(scope_name,
|
|
1311
|
+
result = ModelWithPgSearch.send(scope_name, "foo").first
|
|
1267
1312
|
expect {
|
|
1268
1313
|
result.pg_search_rank
|
|
1269
1314
|
}.to raise_exception(PgSearch::PgSearchRankNotSelected)
|
|
@@ -1275,14 +1320,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1275
1320
|
context "when using the tsearch ranking algorithm" do
|
|
1276
1321
|
it "sorts results by the tsearch rank" do
|
|
1277
1322
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_tsearch,
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1323
|
+
using: :tsearch,
|
|
1324
|
+
against: :content,
|
|
1325
|
+
ranked_by: ":tsearch"
|
|
1281
1326
|
|
|
1282
|
-
once = ModelWithPgSearch.create!(content:
|
|
1283
|
-
twice = ModelWithPgSearch.create!(content:
|
|
1327
|
+
once = ModelWithPgSearch.create!(content: "foo bar")
|
|
1328
|
+
twice = ModelWithPgSearch.create!(content: "foo foo")
|
|
1284
1329
|
|
|
1285
|
-
results = ModelWithPgSearch.search_content_ranked_by_tsearch(
|
|
1330
|
+
results = ModelWithPgSearch.search_content_ranked_by_tsearch("foo")
|
|
1286
1331
|
expect(results.find_index(twice)).to be < results.find_index(once)
|
|
1287
1332
|
end
|
|
1288
1333
|
end
|
|
@@ -1290,14 +1335,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1290
1335
|
context "when using the trigram ranking algorithm" do
|
|
1291
1336
|
it "sorts results by the trigram rank" do
|
|
1292
1337
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_trigram,
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1338
|
+
using: :trigram,
|
|
1339
|
+
against: :content,
|
|
1340
|
+
ranked_by: ":trigram"
|
|
1296
1341
|
|
|
1297
|
-
close = ModelWithPgSearch.create!(content:
|
|
1298
|
-
exact = ModelWithPgSearch.create!(content:
|
|
1342
|
+
close = ModelWithPgSearch.create!(content: "abcdef")
|
|
1343
|
+
exact = ModelWithPgSearch.create!(content: "abc")
|
|
1299
1344
|
|
|
1300
|
-
results = ModelWithPgSearch.search_content_ranked_by_trigram(
|
|
1345
|
+
results = ModelWithPgSearch.search_content_ranked_by_trigram("abc")
|
|
1301
1346
|
expect(results.find_index(exact)).to be < results.find_index(close)
|
|
1302
1347
|
end
|
|
1303
1348
|
end
|
|
@@ -1305,14 +1350,14 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1305
1350
|
context "when using the dmetaphone ranking algorithm" do
|
|
1306
1351
|
it "sorts results by the dmetaphone rank" do
|
|
1307
1352
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1353
|
+
using: :dmetaphone,
|
|
1354
|
+
against: :content,
|
|
1355
|
+
ranked_by: ":dmetaphone"
|
|
1311
1356
|
|
|
1312
|
-
once = ModelWithPgSearch.create!(content:
|
|
1313
|
-
twice = ModelWithPgSearch.create!(content:
|
|
1357
|
+
once = ModelWithPgSearch.create!(content: "Phoo Bar")
|
|
1358
|
+
twice = ModelWithPgSearch.create!(content: "Phoo Fu")
|
|
1314
1359
|
|
|
1315
|
-
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone(
|
|
1360
|
+
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone("foo")
|
|
1316
1361
|
expect(results.find_index(twice)).to be < results.find_index(once)
|
|
1317
1362
|
end
|
|
1318
1363
|
end
|
|
@@ -1321,17 +1366,17 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1321
1366
|
context "when there is a sort only feature" do
|
|
1322
1367
|
it "excludes that feature from the conditions, but uses it in the sorting" do
|
|
1323
1368
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1369
|
+
against: :content,
|
|
1370
|
+
using: {
|
|
1371
|
+
tsearch: {any_word: true, prefix: true},
|
|
1372
|
+
dmetaphone: {any_word: true, prefix: true, sort_only: true}
|
|
1373
|
+
},
|
|
1374
|
+
ranked_by: ":tsearch + (0.5 * :dmetaphone)"
|
|
1330
1375
|
|
|
1331
1376
|
exact = ModelWithPgSearch.create!(content: "ash hines")
|
|
1332
1377
|
one_exact_one_close = ModelWithPgSearch.create!(content: "ash heinz")
|
|
1333
1378
|
one_exact = ModelWithPgSearch.create!(content: "ash smith")
|
|
1334
|
-
|
|
1379
|
+
ModelWithPgSearch.create!(content: "leigh heinz")
|
|
1335
1380
|
|
|
1336
1381
|
results = ModelWithPgSearch.search_content_ranked_by_dmetaphone("ash hines")
|
|
1337
1382
|
expect(results).to eq [exact, one_exact_one_close, one_exact]
|
|
@@ -1339,4 +1384,4 @@ describe "an Active Record model which includes PgSearch" do
|
|
|
1339
1384
|
end
|
|
1340
1385
|
end
|
|
1341
1386
|
end
|
|
1342
|
-
#
|
|
1387
|
+
# standard:enable RSpec/NestedGroups
|