pg_search 2.1.7 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +4 -0
- data/README.md +31 -0
- data/lib/pg_search/features/trigram.rb +29 -5
- data/lib/pg_search/multisearchable.rb +4 -4
- data/lib/pg_search/scope_options.rb +0 -8
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +1 -1
- data/spec/integration/associations_spec.rb +9 -9
- data/spec/integration/pg_search_spec.rb +133 -133
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +2 -2
- data/spec/lib/pg_search/features/trigram_spec.rb +36 -11
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 292701a98892eef31e95d8b5d723e94ce71fd47e4956e8bed595b8f87797f49c
|
4
|
+
data.tar.gz: cc08372ce5c032e288c28b2f6409c218d361b271fc271de08acbe8e5430c8dcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e95e7240968269703ae6d010639f2b4380e7616962c7a07f4932ad5e21c77affae6ea3c90e9a8171641a506988fa076ecdb30224f2b081d1468fb13618713d2e
|
7
|
+
data.tar.gz: 4910a636f53e444c3995e0ca728bd21475d11347d8a4d8223a1e881f3360bf8dc7e4f5689bd05cc559dad106a08b077abda1b3f50c6108221e4dbf75c4d73ffa
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -877,6 +877,37 @@ Vegetable.roughly_spelled_like("collyflower") # => [cauliflower]
|
|
877
877
|
Vegetable.strictly_spelled_like("collyflower") # => []
|
878
878
|
```
|
879
879
|
|
880
|
+
##### :word_similarity
|
881
|
+
|
882
|
+
Allows you to match words in longer strings.
|
883
|
+
By default, trigram searches use `%` or `similarity()` as a similarity value.
|
884
|
+
Set `word_similarity` to `true` to opt for `<%` and `word_similarity` instead.
|
885
|
+
This causes the trigram search to use the similarity of the query term
|
886
|
+
and the word with greatest similarity.
|
887
|
+
|
888
|
+
```ruby
|
889
|
+
class Sentence < ActiveRecord::Base
|
890
|
+
include PgSearch
|
891
|
+
|
892
|
+
pg_search_scope :similarity_like,
|
893
|
+
against: :words,
|
894
|
+
using: {
|
895
|
+
trigram: {
|
896
|
+
word_similarity: true
|
897
|
+
}
|
898
|
+
}
|
899
|
+
|
900
|
+
pg_search_scope :word_similarity_like,
|
901
|
+
against: :words,
|
902
|
+
using: [:trigram]
|
903
|
+
end
|
904
|
+
|
905
|
+
sentence = Sentence.create! name: "Those are two words."
|
906
|
+
|
907
|
+
Sentence.similarity_like("word") # => []
|
908
|
+
Sentence.word_similarity_like("word") # => [sentence]
|
909
|
+
```
|
910
|
+
|
880
911
|
### Limiting Fields When Combining Features
|
881
912
|
|
882
913
|
Sometimes when doing queries combining different features you
|
@@ -4,7 +4,7 @@ module PgSearch
|
|
4
4
|
module Features
|
5
5
|
class Trigram < Feature
|
6
6
|
def self.valid_options
|
7
|
-
super + [
|
7
|
+
super + %i[threshold word_similarity]
|
8
8
|
end
|
9
9
|
|
10
10
|
def conditions
|
@@ -14,7 +14,11 @@ module PgSearch
|
|
14
14
|
)
|
15
15
|
else
|
16
16
|
Arel::Nodes::Grouping.new(
|
17
|
-
Arel::Nodes::InfixOperation.new(
|
17
|
+
Arel::Nodes::InfixOperation.new(
|
18
|
+
infix_operator,
|
19
|
+
normalized_query,
|
20
|
+
normalized_document
|
21
|
+
)
|
18
22
|
)
|
19
23
|
end
|
20
24
|
end
|
@@ -25,12 +29,32 @@ module PgSearch
|
|
25
29
|
|
26
30
|
private
|
27
31
|
|
32
|
+
def word_similarity?
|
33
|
+
options[:word_similarity]
|
34
|
+
end
|
35
|
+
|
36
|
+
def similarity_function
|
37
|
+
if word_similarity?
|
38
|
+
'word_similarity'
|
39
|
+
else
|
40
|
+
'similarity'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def infix_operator
|
45
|
+
if word_similarity?
|
46
|
+
'<%'
|
47
|
+
else
|
48
|
+
'%'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
28
52
|
def similarity
|
29
53
|
Arel::Nodes::NamedFunction.new(
|
30
|
-
|
54
|
+
similarity_function,
|
31
55
|
[
|
32
|
-
|
33
|
-
|
56
|
+
normalized_query,
|
57
|
+
normalized_document
|
34
58
|
]
|
35
59
|
)
|
36
60
|
end
|
@@ -7,12 +7,12 @@ module PgSearch
|
|
7
7
|
def self.included(mod)
|
8
8
|
mod.class_eval do
|
9
9
|
has_one :pg_search_document,
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
as: :searchable,
|
11
|
+
class_name: "PgSearch::Document",
|
12
|
+
dependent: :delete
|
13
13
|
|
14
14
|
after_save :update_pg_search_document,
|
15
|
-
|
15
|
+
if: -> { PgSearch.multisearch_enabled? }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -19,18 +19,10 @@ module PgSearch
|
|
19
19
|
scope
|
20
20
|
.joins(rank_join(rank_table_alias))
|
21
21
|
.order(Arel.sql("#{rank_table_alias}.rank DESC, #{order_within_rank}"))
|
22
|
-
.extend(DisableEagerLoading)
|
23
22
|
.extend(WithPgSearchRank)
|
24
23
|
.extend(WithPgSearchHighlight[feature_for(:tsearch)])
|
25
24
|
end
|
26
25
|
|
27
|
-
# workaround for https://github.com/Casecommons/pg_search/issues/14
|
28
|
-
module DisableEagerLoading
|
29
|
-
def eager_loading?
|
30
|
-
false
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
26
|
module WithPgSearchHighlight
|
35
27
|
def self.[](tsearch)
|
36
28
|
Module.new do
|
data/lib/pg_search/version.rb
CHANGED
data/pg_search.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
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.68.1'
|
28
28
|
s.add_development_dependency 'rubocop-performance'
|
29
29
|
s.add_development_dependency 'simplecov'
|
30
30
|
s.add_development_dependency 'with_model', '>= 1.2'
|
@@ -166,15 +166,15 @@ describe PgSearch do
|
|
166
166
|
include PgSearch
|
167
167
|
|
168
168
|
has_many :models_of_first_type,
|
169
|
-
|
170
|
-
|
169
|
+
class_name: 'FirstAssociatedModel',
|
170
|
+
foreign_key: 'ModelWithManyAssociations_id'
|
171
171
|
|
172
172
|
belongs_to :model_of_second_type,
|
173
|
-
|
173
|
+
class_name: 'SecondAssociatedModel'
|
174
174
|
|
175
175
|
pg_search_scope :with_associated,
|
176
|
-
|
177
|
-
|
176
|
+
against: :title,
|
177
|
+
associated_against: { models_of_first_type: :title, model_of_second_type: :title }
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
@@ -225,12 +225,12 @@ describe PgSearch do
|
|
225
225
|
include PgSearch
|
226
226
|
|
227
227
|
has_many :things,
|
228
|
-
|
229
|
-
|
228
|
+
class_name: 'DoublyAssociatedModel',
|
229
|
+
foreign_key: 'ModelWithDoubleAssociation_id'
|
230
230
|
|
231
231
|
has_many :thingamabobs,
|
232
|
-
|
233
|
-
|
232
|
+
class_name: 'DoublyAssociatedModel',
|
233
|
+
foreign_key: 'ModelWithDoubleAssociation_again_id'
|
234
234
|
|
235
235
|
pg_search_scope :with_associated, against: :title,
|
236
236
|
associated_against: { things: :title, thingamabobs: :title }
|
@@ -38,12 +38,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
38
38
|
context "when passed a lambda" do
|
39
39
|
it "builds a dynamic scope" do
|
40
40
|
ModelWithPgSearch.pg_search_scope :search_title_or_content,
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
lambda { |query, pick_content|
|
42
|
+
{
|
43
|
+
query: query.gsub("-remove-", ""),
|
44
|
+
against: pick_content ? :content : :title
|
45
|
+
}
|
46
|
+
}
|
47
47
|
|
48
48
|
included = ModelWithPgSearch.create!(title: 'foo', content: 'bar')
|
49
49
|
excluded = ModelWithPgSearch.create!(title: 'bar', content: 'foo')
|
@@ -56,8 +56,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
56
56
|
context "when an unknown option is passed in" do
|
57
57
|
it "raises an exception when invoked" do
|
58
58
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
59
|
-
|
60
|
-
|
59
|
+
against: :content,
|
60
|
+
foo: :bar
|
61
61
|
|
62
62
|
expect {
|
63
63
|
ModelWithPgSearch.with_unknown_option("foo")
|
@@ -67,7 +67,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
67
67
|
context "dynamically" do
|
68
68
|
it "raises an exception when invoked" do
|
69
69
|
ModelWithPgSearch.pg_search_scope :with_unknown_option,
|
70
|
-
|
70
|
+
->(*) { { against: :content, foo: :bar } }
|
71
71
|
|
72
72
|
expect {
|
73
73
|
ModelWithPgSearch.with_unknown_option("foo")
|
@@ -79,8 +79,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
79
79
|
context "when an unknown :using is passed" do
|
80
80
|
it "raises an exception when invoked" do
|
81
81
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
82
|
-
|
83
|
-
|
82
|
+
against: :content,
|
83
|
+
using: :foo
|
84
84
|
|
85
85
|
expect {
|
86
86
|
ModelWithPgSearch.with_unknown_using("foo")
|
@@ -90,7 +90,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
90
90
|
context "dynamically" do
|
91
91
|
it "raises an exception when invoked" do
|
92
92
|
ModelWithPgSearch.pg_search_scope :with_unknown_using,
|
93
|
-
|
93
|
+
->(*) { { against: :content, using: :foo } }
|
94
94
|
|
95
95
|
expect {
|
96
96
|
ModelWithPgSearch.with_unknown_using("foo")
|
@@ -102,8 +102,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
102
102
|
context "when an unknown :ignoring is passed" do
|
103
103
|
it "raises an exception when invoked" do
|
104
104
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
105
|
-
|
106
|
-
|
105
|
+
against: :content,
|
106
|
+
ignoring: :foo
|
107
107
|
|
108
108
|
expect {
|
109
109
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
@@ -113,7 +113,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
113
113
|
context "dynamically" do
|
114
114
|
it "raises an exception when invoked" do
|
115
115
|
ModelWithPgSearch.pg_search_scope :with_unknown_ignoring,
|
116
|
-
|
116
|
+
->(*) { { against: :content, ignoring: :foo } }
|
117
117
|
|
118
118
|
expect {
|
119
119
|
ModelWithPgSearch.with_unknown_ignoring("foo")
|
@@ -467,7 +467,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
467
467
|
# WARNING: searching timestamps is not something PostgreSQL
|
468
468
|
# full-text search is good at. Use at your own risk.
|
469
469
|
pg_search_scope :search_timestamps,
|
470
|
-
|
470
|
+
against: %i[created_at updated_at]
|
471
471
|
end
|
472
472
|
end
|
473
473
|
|
@@ -565,10 +565,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
565
565
|
context "using tsearch" do
|
566
566
|
before do
|
567
567
|
ModelWithPgSearch.pg_search_scope :search_title_with_prefixes,
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
568
|
+
against: :title,
|
569
|
+
using: {
|
570
|
+
tsearch: { prefix: true }
|
571
|
+
}
|
572
572
|
end
|
573
573
|
|
574
574
|
context "with prefix: true" do
|
@@ -594,10 +594,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
594
594
|
context "with the english dictionary" do
|
595
595
|
before do
|
596
596
|
ModelWithPgSearch.pg_search_scope :search_content_with_english,
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
597
|
+
against: :content,
|
598
|
+
using: {
|
599
|
+
tsearch: { dictionary: :english }
|
600
|
+
}
|
601
601
|
end
|
602
602
|
|
603
603
|
it "returns rows that match the query when stemmed by the english dictionary" do
|
@@ -620,7 +620,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
620
620
|
context "with highlight turned on" do
|
621
621
|
before do
|
622
622
|
ModelWithPgSearch.pg_search_scope :search_content,
|
623
|
-
|
623
|
+
against: :content
|
624
624
|
end
|
625
625
|
|
626
626
|
it "adds a #pg_search_highlight method to each returned model record" do
|
@@ -641,19 +641,19 @@ describe "an Active Record model which includes PgSearch" do
|
|
641
641
|
ModelWithPgSearch.create! content: "#{'text ' * 2}Let #{'text ' * 2}Let #{'text ' * 2}"
|
642
642
|
|
643
643
|
ModelWithPgSearch.pg_search_scope :search_content,
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
644
|
+
against: :content,
|
645
|
+
using: {
|
646
|
+
tsearch: {
|
647
|
+
highlight: {
|
648
|
+
StartSel: '<mark class="highlight">',
|
649
|
+
StopSel: '</mark>',
|
650
|
+
FragmentDelimiter: '<delim class="my_delim">',
|
651
|
+
MaxFragments: 2,
|
652
|
+
MaxWords: 2,
|
653
|
+
MinWords: 1
|
654
|
+
}
|
655
|
+
}
|
656
|
+
}
|
657
657
|
end
|
658
658
|
|
659
659
|
it "applies the options to the excerpts" do
|
@@ -682,10 +682,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
682
682
|
context "with a normalization specified" do
|
683
683
|
before do
|
684
684
|
ModelWithPgSearch.pg_search_scope :search_content_with_normalization,
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
685
|
+
against: :content,
|
686
|
+
using: {
|
687
|
+
tsearch: { normalization: 2 }
|
688
|
+
}
|
689
689
|
end
|
690
690
|
|
691
691
|
it "ranks the results for documents with less text higher" do
|
@@ -699,8 +699,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
699
699
|
context "with no normalization" do
|
700
700
|
before do
|
701
701
|
ModelWithPgSearch.pg_search_scope :search_content_without_normalization,
|
702
|
-
|
703
|
-
|
702
|
+
against: :content,
|
703
|
+
using: :tsearch
|
704
704
|
end
|
705
705
|
|
706
706
|
it "ranks the results equally" do
|
@@ -715,7 +715,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
715
715
|
context "against columns ranked with arrays" do
|
716
716
|
before do
|
717
717
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_array_of_arrays,
|
718
|
-
|
718
|
+
against: [[:content, 'B'], [:title, 'A']]
|
719
719
|
end
|
720
720
|
|
721
721
|
it "returns results sorted by weighted rank" do
|
@@ -731,7 +731,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
731
731
|
context "against columns ranked with a hash" do
|
732
732
|
before do
|
733
733
|
ModelWithPgSearch.pg_search_scope :search_weighted_by_hash,
|
734
|
-
|
734
|
+
against: { content: 'B', title: 'A' }
|
735
735
|
end
|
736
736
|
|
737
737
|
it "returns results sorted by weighted rank" do
|
@@ -747,7 +747,7 @@ describe "an Active Record model which includes PgSearch" do
|
|
747
747
|
context "against columns of which only some are ranked" do
|
748
748
|
before do
|
749
749
|
ModelWithPgSearch.pg_search_scope :search_weighted,
|
750
|
-
|
750
|
+
against: [:content, [:title, 'A']]
|
751
751
|
end
|
752
752
|
|
753
753
|
it "returns results sorted by weighted rank using an implied low rank for unranked columns" do
|
@@ -763,13 +763,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
763
763
|
context "searching any_word option" do
|
764
764
|
before do
|
765
765
|
ModelWithPgSearch.pg_search_scope :search_title_with_any_word,
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
766
|
+
against: :title,
|
767
|
+
using: {
|
768
|
+
tsearch: { any_word: true }
|
769
|
+
}
|
770
770
|
|
771
771
|
ModelWithPgSearch.pg_search_scope :search_title_with_all_words,
|
772
|
-
|
772
|
+
against: :title
|
773
773
|
end
|
774
774
|
|
775
775
|
it "returns all results containing any word in their title" do
|
@@ -788,10 +788,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
788
788
|
context "with :negation" do
|
789
789
|
before do
|
790
790
|
ModelWithPgSearch.pg_search_scope :search_with_negation,
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
791
|
+
against: :title,
|
792
|
+
using: {
|
793
|
+
tsearch: { negation: true }
|
794
|
+
}
|
795
795
|
end
|
796
796
|
|
797
797
|
it "doesn't return results that contain terms prepended with '!'" do
|
@@ -815,10 +815,10 @@ describe "an Active Record model which includes PgSearch" do
|
|
815
815
|
context "without :negation" do
|
816
816
|
before do
|
817
817
|
ModelWithPgSearch.pg_search_scope :search_without_negation,
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
818
|
+
against: :title,
|
819
|
+
using: {
|
820
|
+
tsearch: {}
|
821
|
+
}
|
822
822
|
end
|
823
823
|
|
824
824
|
it "return results that contain terms prepended with '!'" do
|
@@ -841,8 +841,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
841
841
|
context "using dmetaphone" do
|
842
842
|
before do
|
843
843
|
ModelWithPgSearch.pg_search_scope :with_dmetaphones,
|
844
|
-
|
845
|
-
|
844
|
+
against: %i[title content],
|
845
|
+
using: :dmetaphone
|
846
846
|
end
|
847
847
|
|
848
848
|
it "returns rows where one searchable column and the query share enough dmetaphones" do
|
@@ -880,35 +880,35 @@ describe "an Active Record model which includes PgSearch" do
|
|
880
880
|
context "using multiple features" do
|
881
881
|
before do
|
882
882
|
ModelWithPgSearch.pg_search_scope :with_tsearch,
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
883
|
+
against: :title,
|
884
|
+
using: [
|
885
|
+
[:tsearch, { dictionary: 'english' }]
|
886
|
+
]
|
887
887
|
|
888
888
|
ModelWithPgSearch.pg_search_scope :with_trigram,
|
889
|
-
|
890
|
-
|
889
|
+
against: :title,
|
890
|
+
using: :trigram
|
891
891
|
|
892
892
|
ModelWithPgSearch.pg_search_scope :with_trigram_and_ignoring_accents,
|
893
|
-
|
894
|
-
|
895
|
-
|
893
|
+
against: :title,
|
894
|
+
ignoring: :accents,
|
895
|
+
using: :trigram
|
896
896
|
|
897
897
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram,
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
898
|
+
against: :title,
|
899
|
+
using: [
|
900
|
+
[:tsearch, { dictionary: 'english' }],
|
901
|
+
:trigram
|
902
|
+
]
|
903
903
|
|
904
904
|
ModelWithPgSearch.pg_search_scope :complex_search,
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
905
|
+
against: %i[content title],
|
906
|
+
ignoring: :accents,
|
907
|
+
using: {
|
908
|
+
tsearch: { dictionary: 'english' },
|
909
|
+
dmetaphone: {},
|
910
|
+
trigram: {}
|
911
|
+
}
|
912
912
|
end
|
913
913
|
|
914
914
|
it "returns rows that match using any of the features" do
|
@@ -955,11 +955,11 @@ describe "an Active Record model which includes PgSearch" do
|
|
955
955
|
@trigram_config = trigram_config = { foo: 'bar' }
|
956
956
|
|
957
957
|
ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram_using_hash,
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
958
|
+
against: :title,
|
959
|
+
using: {
|
960
|
+
tsearch: tsearch_config,
|
961
|
+
trigram: trigram_config
|
962
|
+
}
|
963
963
|
end
|
964
964
|
|
965
965
|
it "should pass the custom configuration down to the specified feature" do
|
@@ -1013,13 +1013,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
1013
1013
|
unexpected.comments.create(body: 'commentwo')
|
1014
1014
|
|
1015
1015
|
Post.pg_search_scope :search_by_content_with_tsvector,
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1016
|
+
associated_against: { comments: [:body] },
|
1017
|
+
using: {
|
1018
|
+
tsearch: {
|
1019
|
+
tsvector_column: 'content_tsvector',
|
1020
|
+
dictionary: 'english'
|
1021
|
+
}
|
1022
|
+
}
|
1023
1023
|
end
|
1024
1024
|
|
1025
1025
|
it "should find by the tsvector column" do
|
@@ -1041,13 +1041,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
1041
1041
|
include PgSearch
|
1042
1042
|
|
1043
1043
|
pg_search_scope :search_by_multiple_tsvector_columns,
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1044
|
+
against: ['content', 'message'],
|
1045
|
+
using: {
|
1046
|
+
tsearch: {
|
1047
|
+
tsvector_column: ['content_tsvector', 'message_tsvector'],
|
1048
|
+
dictionary: 'english'
|
1049
|
+
}
|
1050
|
+
}
|
1051
1051
|
end
|
1052
1052
|
end
|
1053
1053
|
|
@@ -1079,13 +1079,13 @@ describe "an Active Record model which includes PgSearch" do
|
|
1079
1079
|
SQL
|
1080
1080
|
|
1081
1081
|
ModelWithTsvector.pg_search_scope :search_by_content_with_tsvector,
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1082
|
+
against: :content,
|
1083
|
+
using: {
|
1084
|
+
tsearch: {
|
1085
|
+
tsvector_column: 'content_tsvector',
|
1086
|
+
dictionary: 'english'
|
1087
|
+
}
|
1088
|
+
}
|
1089
1089
|
end
|
1090
1090
|
|
1091
1091
|
it "should not use to_tsvector in the query" do
|
@@ -1119,8 +1119,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
1119
1119
|
context "ignoring accents" do
|
1120
1120
|
before do
|
1121
1121
|
ModelWithPgSearch.pg_search_scope :search_title_without_accents,
|
1122
|
-
|
1123
|
-
|
1122
|
+
against: :title,
|
1123
|
+
ignoring: :accents
|
1124
1124
|
end
|
1125
1125
|
|
1126
1126
|
it "returns rows that match the query but not its accents" do
|
@@ -1146,15 +1146,15 @@ describe "an Active Record model which includes PgSearch" do
|
|
1146
1146
|
context "when passed a :ranked_by expression" do
|
1147
1147
|
before do
|
1148
1148
|
ModelWithPgSearch.pg_search_scope :search_content_with_default_rank,
|
1149
|
-
|
1149
|
+
against: :content
|
1150
1150
|
|
1151
1151
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank,
|
1152
|
-
|
1153
|
-
|
1152
|
+
against: :content,
|
1153
|
+
ranked_by: "importance"
|
1154
1154
|
|
1155
1155
|
ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank_multiplier,
|
1156
|
-
|
1157
|
-
|
1156
|
+
against: :content,
|
1157
|
+
ranked_by: ":tsearch * importance"
|
1158
1158
|
end
|
1159
1159
|
|
1160
1160
|
it "should return records with a rank attribute equal to the :ranked_by expression" do
|
@@ -1197,8 +1197,8 @@ describe "an Active Record model which includes PgSearch" do
|
|
1197
1197
|
let(:scope_name) { :"search_content_ranked_by_#{feature}" }
|
1198
1198
|
before do
|
1199
1199
|
ModelWithPgSearch.pg_search_scope scope_name,
|
1200
|
-
|
1201
|
-
|
1200
|
+
against: :content,
|
1201
|
+
ranked_by: ":#{feature}"
|
1202
1202
|
|
1203
1203
|
ModelWithPgSearch.create!(content: 'foo')
|
1204
1204
|
end
|
@@ -1234,9 +1234,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
1234
1234
|
context "using the tsearch ranking algorithm" do
|
1235
1235
|
it "sorts results by the tsearch rank" do
|
1236
1236
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_tsearch,
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1237
|
+
using: :tsearch,
|
1238
|
+
against: :content,
|
1239
|
+
ranked_by: ":tsearch"
|
1240
1240
|
|
1241
1241
|
once = ModelWithPgSearch.create!(content: 'foo bar')
|
1242
1242
|
twice = ModelWithPgSearch.create!(content: 'foo foo')
|
@@ -1249,9 +1249,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
1249
1249
|
context "using the trigram ranking algorithm" do
|
1250
1250
|
it "sorts results by the trigram rank" do
|
1251
1251
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_trigram,
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1252
|
+
using: :trigram,
|
1253
|
+
against: :content,
|
1254
|
+
ranked_by: ":trigram"
|
1255
1255
|
|
1256
1256
|
close = ModelWithPgSearch.create!(content: 'abcdef')
|
1257
1257
|
exact = ModelWithPgSearch.create!(content: 'abc')
|
@@ -1264,9 +1264,9 @@ describe "an Active Record model which includes PgSearch" do
|
|
1264
1264
|
context "using the dmetaphone ranking algorithm" do
|
1265
1265
|
it "sorts results by the dmetaphone rank" do
|
1266
1266
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1267
|
+
using: :dmetaphone,
|
1268
|
+
against: :content,
|
1269
|
+
ranked_by: ":dmetaphone"
|
1270
1270
|
|
1271
1271
|
once = ModelWithPgSearch.create!(content: 'Phoo Bar')
|
1272
1272
|
twice = ModelWithPgSearch.create!(content: 'Phoo Fu')
|
@@ -1280,12 +1280,12 @@ describe "an Active Record model which includes PgSearch" do
|
|
1280
1280
|
context "when there is a sort only feature" do
|
1281
1281
|
it "excludes that feature from the conditions, but uses it in the sorting" do
|
1282
1282
|
ModelWithPgSearch.pg_search_scope :search_content_ranked_by_dmetaphone,
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1283
|
+
against: :content,
|
1284
|
+
using: {
|
1285
|
+
tsearch: { any_word: true, prefix: true },
|
1286
|
+
dmetaphone: { any_word: true, prefix: true, sort_only: true }
|
1287
|
+
},
|
1288
|
+
ranked_by: ":tsearch + (0.5 * :dmetaphone)"
|
1289
1289
|
|
1290
1290
|
exact = ModelWithPgSearch.create!(content: "ash hines")
|
1291
1291
|
one_exact_one_close = ModelWithPgSearch.create!(content: "ash heinz")
|
@@ -26,8 +26,8 @@ describe PgSearch::Configuration::ForeignColumn do
|
|
26
26
|
|
27
27
|
it "returns a consistent string" do
|
28
28
|
association = PgSearch::Configuration::Association.new(Model,
|
29
|
-
|
30
|
-
|
29
|
+
:another_model,
|
30
|
+
:title)
|
31
31
|
foreign_column = described_class.new("title", nil, Model, association)
|
32
32
|
|
33
33
|
column_alias = foreign_column.alias
|
@@ -32,25 +32,50 @@ describe PgSearch::Features::Trigram do
|
|
32
32
|
describe 'conditions' do
|
33
33
|
it 'escapes the search document and query' do
|
34
34
|
config.ignore = []
|
35
|
-
expect(feature.conditions.to_sql).to eq("(
|
35
|
+
expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_columns}))")
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'searching by word_similarity' do
|
39
|
+
let(:options) do
|
40
|
+
{ word_similarity: true }
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'uses the "<%" operator when searching by word_similarity' do
|
44
|
+
config.ignore = []
|
45
|
+
expect(feature.conditions.to_sql).to eq("('#{query}' <% (#{coalesced_columns}))")
|
46
|
+
end
|
36
47
|
end
|
37
48
|
|
38
49
|
context 'ignoring accents' do
|
39
50
|
it 'escapes the search document and query, but not the accent function' do
|
40
51
|
config.ignore = [:accents]
|
41
|
-
expect(feature.conditions.to_sql).to eq("(
|
52
|
+
expect(feature.conditions.to_sql).to eq("(unaccent('#{query}') % (unaccent(#{coalesced_columns})))")
|
42
53
|
end
|
43
54
|
end
|
44
55
|
|
45
56
|
context 'when a threshold is specified' do
|
46
|
-
|
47
|
-
|
57
|
+
context 'searching by similarity' do
|
58
|
+
let(:options) do
|
59
|
+
{ threshold: 0.5 }
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'uses a minimum similarity expression instead of the "%" operator' do
|
63
|
+
expect(feature.conditions.to_sql).to eq(
|
64
|
+
"(similarity('#{query}', (#{coalesced_columns})) >= 0.5)"
|
65
|
+
)
|
66
|
+
end
|
48
67
|
end
|
49
68
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
69
|
+
context 'searching by word_similarity' do
|
70
|
+
let(:options) do
|
71
|
+
{ threshold: 0.5, word_similarity: true }
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'uses a minimum similarity expression instead of the "<%" operator' do
|
75
|
+
expect(feature.conditions.to_sql).to eq(
|
76
|
+
"(word_similarity('#{query}', (#{coalesced_columns})) >= 0.5)"
|
77
|
+
)
|
78
|
+
end
|
54
79
|
end
|
55
80
|
end
|
56
81
|
|
@@ -61,7 +86,7 @@ describe PgSearch::Features::Trigram do
|
|
61
86
|
it 'only searches against the select column' do
|
62
87
|
options = { only: :name }
|
63
88
|
coalesced_column = "coalesce(#{Model.quoted_table_name}.\"name\"::text, '')"
|
64
|
-
expect(feature.conditions.to_sql).to eq("(
|
89
|
+
expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_column}))")
|
65
90
|
end
|
66
91
|
end
|
67
92
|
context 'multiple columns' do
|
@@ -69,7 +94,7 @@ describe PgSearch::Features::Trigram do
|
|
69
94
|
|
70
95
|
it 'concatenates when multiples columns are selected' do
|
71
96
|
options = { only: %i[name content] }
|
72
|
-
expect(feature.conditions.to_sql).to eq("(
|
97
|
+
expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_columns}))")
|
73
98
|
end
|
74
99
|
end
|
75
100
|
end
|
@@ -77,7 +102,7 @@ describe PgSearch::Features::Trigram do
|
|
77
102
|
|
78
103
|
describe '#rank' do
|
79
104
|
it 'returns an expression using the similarity() function' do
|
80
|
-
expect(feature.rank.to_sql).to eq("(similarity(
|
105
|
+
expect(feature.rank.to_sql).to eq("(similarity('#{query}', (#{coalesced_columns})))")
|
81
106
|
end
|
82
107
|
end
|
83
108
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Grant Hutchins
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-05-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -87,14 +87,14 @@ dependencies:
|
|
87
87
|
requirements:
|
88
88
|
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
|
-
version: 0.
|
90
|
+
version: 0.68.1
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
95
|
- - ">="
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version: 0.
|
97
|
+
version: 0.68.1
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: rubocop-performance
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|