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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 154a4037a4ee2795a1cfa074afb2e762969db793cbbdecfbee26325ceaac6d7e
4
- data.tar.gz: ae17fccdcae3305c410acf036c28fd2bd5bbede25f5e13afe722cfcfb7a8c188
3
+ metadata.gz: 292701a98892eef31e95d8b5d723e94ce71fd47e4956e8bed595b8f87797f49c
4
+ data.tar.gz: cc08372ce5c032e288c28b2f6409c218d361b271fc271de08acbe8e5430c8dcb
5
5
  SHA512:
6
- metadata.gz: aa942ecd16fbc913a084f17e06493f05ab95b7520bc212aa002fe1fc6386678e80638505fb2b5640ecaecd69212b956a1e7d03ed6475a30811db96d3de33a16e
7
- data.tar.gz: 6f648d0b981a95d4eb35ab1ab81c3fb199e25aefd3378032c3f7407fe8722c780c3542264f4dc99c5e7b9780dff02619ba6cd0fd34b36cd0ca4ae1565c7e083d
6
+ metadata.gz: e95e7240968269703ae6d010639f2b4380e7616962c7a07f4932ad5e21c77affae6ea3c90e9a8171641a506988fa076ecdb30224f2b081d1468fb13618713d2e
7
+ data.tar.gz: 4910a636f53e444c3995e0ca728bd21475d11347d8a4d8223a1e881f3360bf8dc7e4f5689bd05cc559dad106a08b077abda1b3f50c6108221e4dbf75c4d73ffa
@@ -45,7 +45,7 @@ Bundler/DuplicatedGem:
45
45
  Style/EmptyMethod:
46
46
  EnforcedStyle: expanded
47
47
 
48
- Layout/IndentArray:
48
+ Layout/IndentFirstArrayElement:
49
49
  EnforcedStyle: consistent
50
50
 
51
51
  Style/Documentation:
@@ -1,5 +1,9 @@
1
1
  # pg_search changelog
2
2
 
3
+ ## 2.2.0
4
+
5
+ * Add word_similarity option to trigram search (Severin Räz)
6
+
3
7
  ## 2.1.7
4
8
 
5
9
  * Restore link to GitHub repository to original location
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 + [:threshold]
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("%", normalized_document, normalized_query)
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
- "similarity",
54
+ similarity_function,
31
55
  [
32
- normalized_document,
33
- normalized_query
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
- as: :searchable,
11
- class_name: "PgSearch::Document",
12
- dependent: :delete
10
+ as: :searchable,
11
+ class_name: "PgSearch::Document",
12
+ dependent: :delete
13
13
 
14
14
  after_save :update_pg_search_document,
15
- if: -> { PgSearch.multisearch_enabled? }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgSearch
4
- VERSION = '2.1.7'
4
+ VERSION = '2.2.0'
5
5
  end
@@ -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.67.2'
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
- class_name: 'FirstAssociatedModel',
170
- foreign_key: 'ModelWithManyAssociations_id'
169
+ class_name: 'FirstAssociatedModel',
170
+ foreign_key: 'ModelWithManyAssociations_id'
171
171
 
172
172
  belongs_to :model_of_second_type,
173
- class_name: 'SecondAssociatedModel'
173
+ class_name: 'SecondAssociatedModel'
174
174
 
175
175
  pg_search_scope :with_associated,
176
- against: :title,
177
- associated_against: { models_of_first_type: :title, model_of_second_type: :title }
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
- class_name: 'DoublyAssociatedModel',
229
- foreign_key: 'ModelWithDoubleAssociation_id'
228
+ class_name: 'DoublyAssociatedModel',
229
+ foreign_key: 'ModelWithDoubleAssociation_id'
230
230
 
231
231
  has_many :thingamabobs,
232
- class_name: 'DoublyAssociatedModel',
233
- foreign_key: 'ModelWithDoubleAssociation_again_id'
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
- lambda { |query, pick_content|
42
- {
43
- query: query.gsub("-remove-", ""),
44
- against: pick_content ? :content : :title
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
- against: :content,
60
- foo: :bar
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
- ->(*) { { against: :content, foo: :bar } }
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
- against: :content,
83
- using: :foo
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
- ->(*) { { against: :content, using: :foo } }
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
- against: :content,
106
- ignoring: :foo
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
- ->(*) { { against: :content, ignoring: :foo } }
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
- against: %i[created_at updated_at]
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
- against: :title,
569
- using: {
570
- tsearch: { prefix: true }
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
- against: :content,
598
- using: {
599
- tsearch: { dictionary: :english }
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
- against: :content
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
- 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
- }
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
- against: :content,
686
- using: {
687
- tsearch: { normalization: 2 }
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
- against: :content,
703
- using: :tsearch
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
- against: [[:content, 'B'], [:title, 'A']]
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
- against: { content: 'B', title: 'A' }
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
- against: [:content, [:title, 'A']]
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
- against: :title,
767
- using: {
768
- tsearch: { any_word: true }
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
- against: :title
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
- against: :title,
792
- using: {
793
- tsearch: { negation: true }
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
- against: :title,
819
- using: {
820
- tsearch: {}
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
- against: %i[title content],
845
- using: :dmetaphone
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
- against: :title,
884
- using: [
885
- [:tsearch, { dictionary: 'english' }]
886
- ]
883
+ against: :title,
884
+ using: [
885
+ [:tsearch, { dictionary: 'english' }]
886
+ ]
887
887
 
888
888
  ModelWithPgSearch.pg_search_scope :with_trigram,
889
- against: :title,
890
- using: :trigram
889
+ against: :title,
890
+ using: :trigram
891
891
 
892
892
  ModelWithPgSearch.pg_search_scope :with_trigram_and_ignoring_accents,
893
- against: :title,
894
- ignoring: :accents,
895
- using: :trigram
893
+ against: :title,
894
+ ignoring: :accents,
895
+ using: :trigram
896
896
 
897
897
  ModelWithPgSearch.pg_search_scope :with_tsearch_and_trigram,
898
- against: :title,
899
- using: [
900
- [:tsearch, { dictionary: 'english' }],
901
- :trigram
902
- ]
898
+ against: :title,
899
+ using: [
900
+ [:tsearch, { dictionary: 'english' }],
901
+ :trigram
902
+ ]
903
903
 
904
904
  ModelWithPgSearch.pg_search_scope :complex_search,
905
- against: %i[content title],
906
- ignoring: :accents,
907
- using: {
908
- tsearch: { dictionary: 'english' },
909
- dmetaphone: {},
910
- trigram: {}
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
- against: :title,
959
- using: {
960
- tsearch: tsearch_config,
961
- trigram: trigram_config
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
- associated_against: { comments: [:body] },
1017
- using: {
1018
- tsearch: {
1019
- tsvector_column: 'content_tsvector',
1020
- dictionary: 'english'
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
- against: ['content', 'message'],
1045
- using: {
1046
- tsearch: {
1047
- tsvector_column: ['content_tsvector', 'message_tsvector'],
1048
- dictionary: 'english'
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
- against: :content,
1083
- using: {
1084
- tsearch: {
1085
- tsvector_column: 'content_tsvector',
1086
- dictionary: 'english'
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
- against: :title,
1123
- ignoring: :accents
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
- against: :content
1149
+ against: :content
1150
1150
 
1151
1151
  ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank,
1152
- against: :content,
1153
- ranked_by: "importance"
1152
+ against: :content,
1153
+ ranked_by: "importance"
1154
1154
 
1155
1155
  ModelWithPgSearch.pg_search_scope :search_content_with_importance_as_rank_multiplier,
1156
- against: :content,
1157
- ranked_by: ":tsearch * importance"
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
- against: :content,
1201
- ranked_by: ":#{feature}"
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
- using: :tsearch,
1238
- against: :content,
1239
- ranked_by: ":tsearch"
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
- using: :trigram,
1253
- against: :content,
1254
- ranked_by: ":trigram"
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
- using: :dmetaphone,
1268
- against: :content,
1269
- ranked_by: ":dmetaphone"
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
- 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)"
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
- :another_model,
30
- :title)
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("((#{coalesced_columns}) % '#{query}')")
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("((unaccent(#{coalesced_columns})) % unaccent('#{query}'))")
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
- let(:options) do
47
- { threshold: 0.5 }
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
- it 'uses a minimum similarity expression instead of the "%" operator' do
51
- expect(feature.conditions.to_sql).to eq(
52
- "(similarity((#{coalesced_columns}), '#{query}') >= 0.5)"
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("((#{coalesced_column}) % '#{query}')")
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("((#{coalesced_columns}) % '#{query}')")
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((#{coalesced_columns}), '#{query}'))")
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.1.7
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-04-20 00:00:00.000000000 Z
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.67.2
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.67.2
97
+ version: 0.68.1
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rubocop-performance
100
100
  requirement: !ruby/object:Gem::Requirement