pg_search 2.1.7 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +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
|