pg_search 1.0.5 → 1.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8d495a89c4bddfe4c4d367fb1cc8e4c5b1bea048
4
- data.tar.gz: 611249f3cddce656579b5f4618a4d8a26ed77f8d
3
+ metadata.gz: 55ed2cdc0eaecdb0dcb05ee5fcf7e7460556669d
4
+ data.tar.gz: 8ff17add1a0a7c7a16dd6501b6335e5d364b07b4
5
5
  SHA512:
6
- metadata.gz: b6bfca34ff32c71bc153173f6cd5ea293ab35bea8aa55cdabd53388b687e56b273402b2b822789994d378fed58e3591a1a91c724cfc91f1085edba9d988773f6
7
- data.tar.gz: d03fc9fe66c02fb33744ec86ab12ec97d662c3eaff075da0c1b0f6f994e3c3f4c8da47045d4ce227bb6552e8890d95729d1cc679e80115378aabd9f7fd4b2324
6
+ metadata.gz: 1acf5bc208de87a781c1c2ddaa3b44b33609afb8927cd8bbbb256a9a9caf099f3c2507232a0d9f2a9ad45acaf997e3590bbcbac6d3cb4936515e6874c3cb4ea1
7
+ data.tar.gz: d569da3e3f8aa7b205596fbce5d1bd72e0db4dab9576ac9331b810b4dbcefd80f77918a8ce51cfb3e944f63520f4166e86bd5db883b01c0e2b8f97e3bff7018d
data/.rubocop_todo.yml CHANGED
@@ -1,37 +1,84 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2014-12-12 15:10:11 -0600 using RuboCop version 0.28.0.
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-01-25 14:11:25 -0600 using RuboCop version 0.36.0.
3
4
  # The point is for the user to remove these configuration records
4
5
  # one by one as the offenses are removed from the code base.
5
6
  # Note that changes in the inspected code, or installation of new
6
7
  # versions of RuboCop, may require this file to be generated again.
7
8
 
9
+ # Offense count: 2
10
+ # Cop supports --auto-correct.
11
+ Lint/UnneededDisable:
12
+ Exclude:
13
+ - 'lib/pg_search/features/tsearch.rb'
14
+ - 'lib/pg_search/scope_options.rb'
15
+
16
+ # Offense count: 1
17
+ # Cop supports --auto-correct.
18
+ Performance/Casecmp:
19
+ Exclude:
20
+ - 'spec/support/database.rb'
21
+
8
22
  # Offense count: 27
9
23
  Style/Documentation:
10
24
  Enabled: false
11
25
 
12
- # Offense count: 16
26
+ # Offense count: 3
13
27
  # Cop supports --auto-correct.
14
- Style/NumericLiterals:
15
- MinDigits: 6
28
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
29
+ # SupportedStyles: when_needed, always
30
+ Style/FrozenStringLiteralComment:
31
+ Exclude:
32
+ - 'lib/pg_search/migration/associated_against_generator.rb'
33
+ - 'lib/pg_search/migration/dmetaphone_generator.rb'
34
+ - 'lib/pg_search/version.rb'
16
35
 
17
- # Offense count: 2
36
+ # Offense count: 1
37
+ Style/IfInsideElse:
38
+ Exclude:
39
+ - 'lib/pg_search/multisearchable.rb'
40
+
41
+ # Offense count: 26
18
42
  # Cop supports --auto-correct.
19
- # Configuration parameters: EnforcedStyle, SupportedStyles.
20
- Style/PercentQLiterals:
43
+ # Configuration parameters: SupportedStyles, IndentationWidth.
44
+ # SupportedStyles: special_inside_parentheses, consistent, align_brackets
45
+ Style/IndentArray:
46
+ EnforcedStyle: consistent
47
+
48
+ # Offense count: 3
49
+ # Cop supports --auto-correct.
50
+ # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
51
+ # SupportedStyles: aligned, indented
52
+ Style/MultilineMethodCallIndentation:
21
53
  Enabled: false
22
54
 
55
+ # Offense count: 2
56
+ # Cop supports --auto-correct.
57
+ Style/MutableConstant:
58
+ Exclude:
59
+ - 'lib/pg_search/configuration.rb'
60
+ - 'lib/pg_search/scope_options.rb'
61
+
62
+ # Offense count: 16
63
+ # Cop supports --auto-correct.
64
+ Style/NumericLiterals:
65
+ MinDigits: 6
66
+
23
67
  # Offense count: 1
24
68
  # Cop supports --auto-correct.
25
69
  Style/PerlBackrefs:
26
- Enabled: false
70
+ Exclude:
71
+ - 'lib/pg_search/scope_options.rb'
27
72
 
28
73
  # Offense count: 1
29
74
  # Cop supports --auto-correct.
30
75
  Style/Proc:
31
- Enabled: false
76
+ Exclude:
77
+ - 'lib/pg_search/document.rb'
32
78
 
33
- # Offense count: 4
79
+ # Offense count: 5
34
80
  # Configuration parameters: EnforcedStyle, SupportedStyles.
81
+ # SupportedStyles: compact, exploded
35
82
  Style/RaiseArgs:
36
83
  Enabled: false
37
84
 
@@ -39,78 +86,114 @@ Style/RaiseArgs:
39
86
  # Cop supports --auto-correct.
40
87
  # Configuration parameters: AllowMultipleReturnValues.
41
88
  Style/RedundantReturn:
42
- Enabled: false
89
+ Exclude:
90
+ - 'lib/pg_search/scope_options.rb'
43
91
 
44
- # Offense count: 10
92
+ # Offense count: 11
45
93
  # Cop supports --auto-correct.
46
94
  # Configuration parameters: EnforcedStyle, SupportedStyles.
95
+ # SupportedStyles: only_raise, only_fail, semantic
47
96
  Style/SignalException:
48
- Enabled: false
97
+ Exclude:
98
+ - 'lib/pg_search.rb'
99
+ - 'lib/pg_search/configuration.rb'
100
+ - 'lib/pg_search/features/tsearch.rb'
101
+ - 'lib/pg_search/multisearch/rebuilder.rb'
102
+ - 'lib/pg_search/normalizer.rb'
103
+ - 'lib/pg_search/scope_options.rb'
104
+ - 'lib/pg_search/tasks.rb'
105
+ - 'spec/lib/pg_search_spec.rb'
106
+ - 'spec/support/database.rb'
49
107
 
50
108
  # Offense count: 2
51
109
  # Cop supports --auto-correct.
52
110
  Style/SpaceAfterComma:
53
- Enabled: false
111
+ Exclude:
112
+ - 'lib/pg_search/configuration.rb'
113
+ - 'lib/pg_search/tasks.rb'
54
114
 
55
115
  # Offense count: 1
56
116
  # Cop supports --auto-correct.
57
117
  # Configuration parameters: EnforcedStyle, SupportedStyles.
118
+ # SupportedStyles: space, no_space
58
119
  Style/SpaceAroundEqualsInParameterDefault:
59
120
  Enabled: false
60
121
 
61
- # Offense count: 1
122
+ # Offense count: 4
62
123
  # Cop supports --auto-correct.
63
124
  # Configuration parameters: EnforcedStyle, SupportedStyles.
125
+ # SupportedStyles: space, no_space
64
126
  Style/SpaceBeforeBlockBraces:
65
127
  Enabled: false
66
128
 
67
- # Offense count: 2
129
+ # Offense count: 3
68
130
  # Cop supports --auto-correct.
69
131
  # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
132
+ # SupportedStyles: space, no_space
70
133
  Style/SpaceInsideBlockBraces:
71
134
  Enabled: false
72
135
 
73
136
  # Offense count: 76
74
137
  # Cop supports --auto-correct.
75
138
  # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
139
+ # SupportedStyles: space, no_space
76
140
  Style/SpaceInsideHashLiteralBraces:
77
141
  Enabled: false
78
142
 
79
143
  # Offense count: 2
80
144
  # Cop supports --auto-correct.
81
145
  Style/SpaceInsideParens:
82
- Enabled: false
146
+ Exclude:
147
+ - 'spec/lib/pg_search/multisearch/rebuilder_spec.rb'
83
148
 
84
149
  # Offense count: 3
85
150
  # Cop supports --auto-correct.
151
+ # Configuration parameters: SupportedStyles.
152
+ # SupportedStyles: use_perl_names, use_english_names
86
153
  Style/SpecialGlobalVars:
87
- Enabled: false
154
+ EnforcedStyle: use_english_names
88
155
 
89
156
  # Offense count: 2
90
157
  # Cop supports --auto-correct.
91
158
  # Configuration parameters: IgnoredMethods.
159
+ # IgnoredMethods: respond_to
92
160
  Style/SymbolProc:
93
- Enabled: false
161
+ Exclude:
162
+ - 'lib/pg_search/features/feature.rb'
163
+ - 'lib/pg_search/multisearch/rebuilder.rb'
94
164
 
95
- # Offense count: 4
165
+ # Offense count: 5
96
166
  # Cop supports --auto-correct.
97
167
  # Configuration parameters: EnforcedStyle, SupportedStyles.
168
+ # SupportedStyles: final_newline, final_blank_line
98
169
  Style/TrailingBlankLines:
99
- Enabled: false
170
+ Exclude:
171
+ - 'Guardfile'
172
+ - 'lib/pg_search/extensions/arel.rb'
173
+ - 'lib/pg_search/migration/multisearch_generator.rb'
174
+ - 'lib/pg_search/multisearch.rb'
175
+ - 'spec/integration/single_table_inheritance_spec.rb'
100
176
 
101
177
  # Offense count: 9
102
178
  # Cop supports --auto-correct.
103
179
  # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
104
- Style/TrailingComma:
105
- Enabled: false
180
+ # SupportedStyles: comma, consistent_comma, no_comma
181
+ Style/TrailingCommaInLiteral:
182
+ Exclude:
183
+ - 'spec/integration/pg_search_spec.rb'
184
+ - 'spec/lib/pg_search/features/dmetaphone_spec.rb'
185
+ - 'spec/lib/pg_search/features/tsearch_spec.rb'
106
186
 
107
- # Offense count: 6
187
+ # Offense count: 2
108
188
  # Cop supports --auto-correct.
109
189
  Style/UnneededPercentQ:
110
- Enabled: false
190
+ Exclude:
191
+ - 'pg_search.gemspec'
111
192
 
112
193
  # Offense count: 3
113
194
  # Cop supports --auto-correct.
114
- # Configuration parameters: WordRegex.
195
+ # Configuration parameters: SupportedStyles, WordRegex.
196
+ # SupportedStyles: percent, brackets
115
197
  Style/WordArray:
116
- MinSize: 2
198
+ EnforcedStyle: percent
199
+ MinSize: 3
data/.travis.yml CHANGED
@@ -2,10 +2,11 @@ language: ruby
2
2
  sudo: false
3
3
 
4
4
  rvm:
5
- - "1.9"
6
- - "2.0"
7
- - "2.1"
5
+ - "2.3.1"
8
6
  - "2.2"
7
+ - "2.1"
8
+ - "2.0"
9
+ - "1.9"
9
10
  - jruby-19mode
10
11
  - jruby-9.0.0.0
11
12
 
data/CHANGELOG.md CHANGED
@@ -1,9 +1,14 @@
1
1
  # pg_search changelog
2
2
 
3
+ ## 1.0.6
4
+ * Add support for highlighting the matching portion of a search result. (Jose Galisteo)
5
+ * Add `:update_if` option to control when PgSearch::Document gets updated. (Adam Becker)
6
+ * Add `:additional_attributes` option for adding additional attributes to PgSearch::Document
7
+
3
8
  ## 1.0.5
4
9
 
5
- * Clean up rank table aliasing (Adam Milligan)
6
- * Fix issue when using `#with_pg_search_rank` across a join (Reid Lynch)
10
+ * Clean up rank table aliasing. (Adam Milligan)
11
+ * Fix issue when using `#with_pg_search_rank` across a join. (Reid Lynch)
7
12
 
8
13
  ## 1.0.4
9
14
 
data/Gemfile CHANGED
@@ -12,13 +12,6 @@ end
12
12
 
13
13
  gem 'activerecord', ENV['ACTIVE_RECORD_VERSION'] if ENV['ACTIVE_RECORD_VERSION']
14
14
 
15
- group :development do
16
- gem 'guard-rspec', :require => false
17
- gem 'rb-inotify', :require => false
18
- gem 'rb-fsevent', :require => false
19
- gem 'rb-fchange', :require => false
20
- end
21
-
22
15
  group :test do
23
16
  gem "codeclimate-test-reporter", require: nil
24
17
  end
data/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  [![Dependency Status](https://img.shields.io/gemnasium/Casecommons/pg_search.svg?style=flat)](https://gemnasium.com/Casecommons/pg_search)
8
8
  [![Inline docs](http://inch-ci.org/github/Casecommons/pg_search.svg?branch=master&style=flat)](http://inch-ci.org/github/Casecommons/pg_search)
9
9
  [![Join the chat at https://gitter.im/Casecommons/pg_search](https://img.shields.io/badge/gitter-join%20chat-blue.svg)](https://gitter.im/Casecommons/pg_search?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10
+ [![Stories in Ready](https://badge.waffle.io/Casecommons/pg_search.svg?label=ready&title=Ready)](https://waffle.io/Casecommons/pg_search)
10
11
 
11
12
  ## DESCRIPTION
12
13
 
@@ -239,10 +240,12 @@ receive SQL requests when necessary.
239
240
  ```ruby
240
241
  PgSearch.multisearch("Bertha").limit(10)
241
242
  PgSearch.multisearch("Juggler").where(:searchable_type => "Occupation")
242
- PgSearch.multisearch("Alamo").page(3).per_page(30)
243
+ PgSearch.multisearch("Alamo").page(3).per(30)
243
244
  PgSearch.multisearch("Diagonal").find_each do |document|
244
245
  puts document.searchable.updated_at
245
246
  end
247
+ PgSearch.multisearch("Moro").reorder("").group(:searchable_type).count(:all)
248
+ PgSearch.multisearch("Square").includes(:searchable)
246
249
  ```
247
250
 
248
251
  #### Configuring multi-search
@@ -733,6 +736,34 @@ one_close = Person.create!(:name => 'leigh heinz')
733
736
  Person.search('ash hines') # => [exact, one_exact_one_close, one_exact]
734
737
  ```
735
738
 
739
+ ##### :highlight (PostgreSQL 9.0 and newer only)
740
+
741
+ Adding .with_pg_search_highlight after the pg_search_scope you can access to
742
+ `pg_highlight` attribute for each object.
743
+
744
+
745
+ ```ruby
746
+ class Person < ActiveRecord::Base
747
+ include PgSearch
748
+ pg_search_scope :search,
749
+ :against => :bio,
750
+ :using => {
751
+ :tsearch => {
752
+ :start_sel => '<b>',
753
+ :stop_sel => '</b>'
754
+ }
755
+ }
756
+ end
757
+
758
+ Person.create!(:bio => "Born in rural Alberta, where the buffalo roam.")
759
+
760
+ first_match = Person.search("Alberta").with_pg_search_highlight.first
761
+ first_match.pg_search_highlight # => "Born in rural <b>Alberta</b>, where the buffalo roam."
762
+ ```
763
+
764
+ By default, it will add the delimiters `<b>` and `</b>` around the matched text. You can customize these delimiters and the number of fragments returned with the `:start_sel`, `stop_sel`, and `max_fragments` options.
765
+
766
+
736
767
  #### :dmetaphone (Double Metaphone soundalike search)
737
768
 
738
769
  [Double Metaphone](http://en.wikipedia.org/wiki/Double_Metaphone) is an
@@ -804,7 +835,9 @@ Website.kinda_spelled_like("Yahoo!") # => [yahooo, yohoo]
804
835
  By default, trigram searches find records which have a similarity of at least 0.3
805
836
  using pg_trgm's calculations. You may specify a custom threshold if you prefer.
806
837
  Higher numbers match more strictly, and thus return fewer results. Lower numbers
807
- match more permissively, letting in more results.
838
+ match more permissively, letting in more results. Please note that setting a trigram
839
+ threshold will force a table scan as the derived query uses the
840
+ `similarity()` function instead of the `%` operator.
808
841
 
809
842
  ```ruby
810
843
  class Vegetable < ActiveRecord::Base
@@ -1068,7 +1101,7 @@ queried table.
1068
1101
  ```ruby
1069
1102
  shirt_brands = ShirtBrand.search_by_name("Penguin")
1070
1103
  .joins(:shirt_sizes)
1071
- .group_by('shirt_brands.id, #{PgSearch::Configuration.alias('shirt_brands')}.rank')
1104
+ .group("shirt_brands.id, #{PgSearch::Configuration.alias('shirt_brands')}.rank")
1072
1105
  ```
1073
1106
 
1074
1107
  ## ATTRIBUTIONS
data/lib/pg_search.rb CHANGED
@@ -73,6 +73,9 @@ module PgSearch
73
73
  when :pg_search_rank
74
74
  raise PgSearchRankNotSelected.new unless respond_to?(:pg_search_rank)
75
75
  read_attribute(:pg_search_rank).to_f
76
+ when :pg_search_highlight
77
+ raise PgSearchHighlightNotSelected.new unless respond_to?(:pg_search_highlight)
78
+ read_attribute(:pg_search_highlight)
76
79
  else
77
80
  super
78
81
  end
@@ -82,6 +85,8 @@ module PgSearch
82
85
  case symbol
83
86
  when :pg_search_rank
84
87
  attributes.key?(:pg_search_rank)
88
+ when :pg_search_highlight
89
+ attributes.key?(:pg_search_highlight)
85
90
  else
86
91
  super
87
92
  end
@@ -90,9 +95,15 @@ module PgSearch
90
95
  class NotSupportedForPostgresqlVersion < StandardError; end
91
96
 
92
97
  class PgSearchRankNotSelected < StandardError
98
+ def message
99
+ "You must chain .with_pg_search_rank after the pg_search_scope to access the pg_search_rank attribute on returned records" # rubocop:disable Metrics/LineLength
100
+ end
101
+ end
102
+
103
+ class PgSearchHighlightNotSelected < StandardError
93
104
  # rubocop:disable Metrics/LineLength
94
105
  def message
95
- "You must chain .with_pg_search_rank after the pg_search_scope to access the pg_search_rank attribute on returned records"
106
+ "You must chain .with_pg_search_highlight after the pg_search_scope to access the pg_search_highlight attribute on returned records"
96
107
  end
97
108
  end
98
109
  end
@@ -7,9 +7,6 @@ module PgSearch
7
7
  self.table_name = 'pg_search_documents'
8
8
  belongs_to :searchable, :polymorphic => true
9
9
 
10
- before_validation :update_content,
11
- :unless => Proc.new { |doc| doc.searchable.nil? }
12
-
13
10
  # The logger might not have loaded yet.
14
11
  # https://github.com/Casecommons/pg_search/issues/26
15
12
  def self.logger
@@ -25,13 +22,5 @@ module PgSearch
25
22
 
26
23
  {:against => :content}.merge(options)
27
24
  }
28
-
29
- private
30
-
31
- def update_content
32
- methods = Array(searchable.pg_search_multisearchable_options[:against])
33
- searchable_text = methods.map { |symbol| searchable.send(symbol) }.join(" ")
34
- self.content = searchable_text
35
- end
36
25
  end
37
26
  end
@@ -3,19 +3,15 @@ require "active_support/core_ext/module/delegation"
3
3
 
4
4
  module PgSearch
5
5
  module Features
6
- class TSearch < Feature
6
+ class TSearch < Feature # rubocop:disable Metrics/ClassLength
7
7
  def self.valid_options
8
- super + [:dictionary, :prefix, :negation, :any_word, :normalization, :tsvector_column]
8
+ super + [:dictionary, :prefix, :negation, :any_word, :normalization, :tsvector_column, :highlight]
9
9
  end
10
10
 
11
11
  def initialize(*args)
12
12
  super
13
-
14
- if options[:prefix] && model.connection.send(:postgresql_version) < 80400 # rubocop:disable Style/GuardClause
15
- raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
16
- Sorry, {:using => {:tsearch => {:prefix => true}}} only works in PostgreSQL 8.4 and above.")
17
- MESSAGE
18
- end
13
+ checks_for_highlight
14
+ checks_for_prefix
19
15
  end
20
16
 
21
17
  def conditions
@@ -28,8 +24,47 @@ module PgSearch
28
24
  arel_wrap(tsearch_rank)
29
25
  end
30
26
 
27
+ def highlight
28
+ arel_wrap(ts_headline)
29
+ end
30
+
31
31
  private
32
32
 
33
+ def checks_for_prefix
34
+ if options[:prefix] && model.connection.send(:postgresql_version) < 80400
35
+ raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
36
+ Sorry, {:using => {:tsearch => {:prefix => true}}} only works in PostgreSQL 8.4 and above.")
37
+ MESSAGE
38
+ end
39
+ end
40
+
41
+ def checks_for_highlight
42
+ if options[:highlight] && model.connection.send(:postgresql_version) < 90000
43
+ raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
44
+ Sorry, {:using => {:tsearch => {:highlight => true}}} only works in PostgreSQL 9.0 and above.")
45
+ MESSAGE
46
+ end
47
+ end
48
+
49
+ def ts_headline
50
+ "ts_headline((#{document}), (#{tsquery}), '#{ts_headline_options}')"
51
+ end
52
+
53
+ def ts_headline_options
54
+ return nil unless options[:highlight].is_a?(Hash)
55
+
56
+ headline_options = map_headline_options
57
+ headline_options.map{|key, value| "#{key} = #{value}" if value }.compact.join(", ")
58
+ end
59
+
60
+ def map_headline_options
61
+ {
62
+ "StartSel" => options[:highlight][:start_sel],
63
+ "StopSel" => options[:highlight][:stop_sel],
64
+ "MaxFragments" => options[:highlight][:max_fragments]
65
+ }
66
+ end
67
+
33
68
  DISALLOWED_TSQUERY_CHARACTERS = /['?\\:]/
34
69
 
35
70
  def tsquery_for_term(unsanitized_term) # rubocop:disable Metrics/AbcSize
@@ -14,6 +14,27 @@ module PgSearch
14
14
  end
15
15
  end
16
16
 
17
+ def searchable_text
18
+ Array(pg_search_multisearchable_options[:against])
19
+ .map { |symbol| send(symbol) }
20
+ .join(" ")
21
+ end
22
+
23
+ def pg_search_document_attrs
24
+ {
25
+ content: searchable_text
26
+ }.tap do |h|
27
+ if (attrs = pg_search_multisearchable_options[:additional_attributes])
28
+ h.merge! attrs.to_proc.call(self)
29
+ end
30
+ end
31
+ end
32
+
33
+ def should_update_pg_search_document?
34
+ conditions = Array(pg_search_multisearchable_options[:update_if])
35
+ conditions.all? { |condition| condition.to_proc.call(self) }
36
+ end
37
+
17
38
  def update_pg_search_document # rubocop:disable Metrics/AbcSize
18
39
  if_conditions = Array(pg_search_multisearchable_options[:if])
19
40
  unless_conditions = Array(pg_search_multisearchable_options[:unless])
@@ -23,10 +44,18 @@ module PgSearch
23
44
  unless_conditions.all? { |condition| !condition.to_proc.call(self) }
24
45
 
25
46
  if should_have_document
26
- pg_search_document ? pg_search_document.save : create_pg_search_document
47
+ create_or_update_pg_search_document
27
48
  else
28
49
  pg_search_document.destroy if pg_search_document
29
50
  end
30
51
  end
52
+
53
+ def create_or_update_pg_search_document
54
+ if !pg_search_document
55
+ create_pg_search_document(pg_search_document_attrs)
56
+ elsif should_update_pg_search_document?
57
+ pg_search_document.update_attributes(pg_search_document_attrs)
58
+ end
59
+ end
31
60
  end
32
61
  end
@@ -21,6 +21,7 @@ module PgSearch
21
21
  .order("#{rank_table_alias}.rank DESC, #{order_within_rank}")
22
22
  .extend(DisableEagerLoading)
23
23
  .extend(WithPgSearchRank)
24
+ .extend(WithPgSearchHighlight[feature_for(:tsearch)])
24
25
  end
25
26
 
26
27
  # workaround for https://github.com/Casecommons/pg_search/issues/14
@@ -30,6 +31,32 @@ module PgSearch
30
31
  end
31
32
  end
32
33
 
34
+ module WithPgSearchHighlight
35
+ def self.[](tsearch)
36
+ Module.new do
37
+ include WithPgSearchHighlight
38
+ define_method(:tsearch) { tsearch }
39
+ end
40
+ end
41
+
42
+ def tsearch
43
+ raise TypeError.new("You need to instantiate this module with []")
44
+ end
45
+
46
+ def with_pg_search_highlight
47
+ scope = self
48
+ scope.select(pg_search_highlight_field)
49
+ end
50
+
51
+ def pg_search_highlight_field
52
+ "(#{highlight}) AS pg_search_highlight, #{table_name}.*"
53
+ end
54
+
55
+ def highlight
56
+ tsearch.highlight.to_sql
57
+ end
58
+ end
59
+
33
60
  module WithPgSearchRank
34
61
  def with_pg_search_rank
35
62
  scope = self
@@ -103,7 +130,7 @@ module PgSearch
103
130
  end
104
131
 
105
132
  def subquery_join
106
- if config.associations.any? # rubocop:disable Style/GuardClause
133
+ if config.associations.any?
107
134
  config.associations.map do |association|
108
135
  association.join(primary_key)
109
136
  end.join(' ')
@@ -1,3 +1,3 @@
1
1
  module PgSearch
2
- VERSION = "1.0.5".freeze
2
+ VERSION = "1.0.6".freeze
3
3
  end
data/pg_search.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
3
  require "pg_search/version"
4
4
 
5
5
  Gem::Specification.new do |s|
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency 'pry'
26
26
  s.add_development_dependency 'rspec', '>= 3.3'
27
27
  s.add_development_dependency 'with_model', '>= 1.2'
28
- s.add_development_dependency 'rubocop', '>= 0.30.0'
28
+ s.add_development_dependency 'rubocop', '>= 0.36'
29
29
 
30
30
  s.required_ruby_version = ">= 1.9.2"
31
31
  end
@@ -618,6 +618,33 @@ describe "an Active Record model which includes PgSearch" do
618
618
  end
619
619
  end
620
620
 
621
+ describe "highlighting" do
622
+ before do
623
+ ["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
624
+ ModelWithPgSearch.create! :content => name
625
+ end
626
+ end
627
+
628
+ context "with highlight turned on" do
629
+ before do
630
+ ModelWithPgSearch.pg_search_scope :search_content,
631
+ :against => :content
632
+ end
633
+
634
+ it "adds a #pg_search_highlight method to each returned model record" do
635
+ result = ModelWithPgSearch.search_content("Strip Down").with_pg_search_highlight.first
636
+
637
+ expect(result.pg_search_highlight).to be_a(String)
638
+ end
639
+
640
+ it "returns excerpts of text where search match occurred" do
641
+ result = ModelWithPgSearch.search_content("Let").with_pg_search_highlight.first
642
+
643
+ expect(result.pg_search_highlight).to eq("Won't <b>Let</b> You Down")
644
+ end
645
+ end
646
+ end
647
+
621
648
  describe "ranking" do
622
649
  before do
623
650
  ["Strip Down", "Down", "Down and Out", "Won't Let You Down"].each do |name|
@@ -3,6 +3,19 @@ require "spec_helper"
3
3
  describe PgSearch::Multisearch::Rebuilder do
4
4
  with_table "pg_search_documents", {}, &DOCUMENTS_SCHEMA
5
5
 
6
+ describe 'when intialized with a model that is not multisearchable' do
7
+ with_model :not_multisearchable
8
+
9
+ it 'raises an exception' do
10
+ expect {
11
+ PgSearch::Multisearch::Rebuilder.new(NotMultisearchable)
12
+ }.to raise_exception(
13
+ PgSearch::Multisearch::ModelNotMultisearchable,
14
+ "NotMultisearchable is not multisearchable. See PgSearch::ClassMethods#multisearchable"
15
+ )
16
+ end
17
+ end
18
+
6
19
  describe "#rebuild" do
7
20
  context "when the model defines .rebuild_pg_search_documents" do
8
21
  context "and multisearchable is not conditional" do
@@ -94,6 +94,148 @@ describe PgSearch::Multisearchable do
94
94
  end
95
95
  end
96
96
  end
97
+
98
+ describe "populating the searchable text" do
99
+ let(:record) { ModelThatIsMultisearchable.new }
100
+ subject { record }
101
+
102
+ before do
103
+ ModelThatIsMultisearchable.multisearchable(multisearchable_options)
104
+ end
105
+
106
+ context "when searching against a single column" do
107
+ let(:multisearchable_options) { {:against => :some_content} }
108
+ let(:text) { "foo bar" }
109
+ before do
110
+ allow(record).to receive(:some_content) { text }
111
+ record.save
112
+ end
113
+
114
+ describe '#content' do
115
+ subject { super().pg_search_document.content }
116
+ it { is_expected.to eq(text) }
117
+ end
118
+ end
119
+
120
+ context "when searching against multiple columns" do
121
+ let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
122
+ before do
123
+ allow(record).to receive(:attr1) { '1' }
124
+ allow(record).to receive(:attr2) { '2' }
125
+ record.save
126
+ end
127
+
128
+ describe '#content' do
129
+ subject { super().pg_search_document.content }
130
+ it { is_expected.to eq("1 2") }
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "populating the searchable attributes" do
136
+ let(:record) { ModelThatIsMultisearchable.new }
137
+ subject { record }
138
+
139
+ before do
140
+ ModelThatIsMultisearchable.multisearchable(multisearchable_options)
141
+ end
142
+
143
+ context "when searching against a single column" do
144
+ let(:multisearchable_options) { {:against => :some_content} }
145
+ let(:text) { "foo bar" }
146
+ before do
147
+ allow(record).to receive(:some_content) { text }
148
+ record.save
149
+ end
150
+
151
+ describe '#content' do
152
+ subject { super().pg_search_document.content }
153
+ it { is_expected.to eq(text) }
154
+ end
155
+ end
156
+
157
+ context "when searching against multiple columns" do
158
+ let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
159
+ before do
160
+ allow(record).to receive(:attr1) { '1' }
161
+ allow(record).to receive(:attr2) { '2' }
162
+ record.save
163
+ end
164
+
165
+ describe '#content' do
166
+ subject { super().pg_search_document.content }
167
+ it { is_expected.to eq("1 2") }
168
+ end
169
+ end
170
+
171
+ context "with additional_attributes" do
172
+ let(:multisearchable_options) do
173
+ {
174
+ :additional_attributes => lambda do |record|
175
+ { foo: record.bar }
176
+ end
177
+ }
178
+ end
179
+ let(:text) { "foo bar" }
180
+
181
+ it "sets the attributes" do
182
+ allow(record).to receive(:bar).and_return(text)
183
+ expect(record)
184
+ .to receive(:create_pg_search_document)
185
+ .with(content: '', foo: text)
186
+ record.save
187
+ end
188
+ end
189
+
190
+ context "when selectively updating" do
191
+ let(:multisearchable_options) do
192
+ {
193
+ :update_if => lambda do |record|
194
+ record.bar?
195
+ end
196
+ }
197
+ end
198
+ let(:text) { "foo bar" }
199
+
200
+ it "creates the document" do
201
+ allow(record).to receive(:bar?).and_return(false)
202
+ expect(record)
203
+ .to receive(:create_pg_search_document)
204
+ .with(content: '')
205
+ record.save
206
+ end
207
+
208
+ context "the document is created" do
209
+ before { record.save }
210
+
211
+ context "update_if returns false" do
212
+ before do
213
+ allow(record).to receive(:bar?).and_return(false)
214
+ end
215
+
216
+ it "does not update the document" do
217
+ expect_any_instance_of(PgSearch::Document)
218
+ .to_not receive(:update_attributes)
219
+
220
+ record.save
221
+ end
222
+ end
223
+
224
+ context "update_if returns true" do
225
+ before do
226
+ allow(record).to receive(:bar?).and_return(true)
227
+ end
228
+
229
+ it "updates the document" do
230
+ expect_any_instance_of(PgSearch::Document)
231
+ .to receive(:update_attributes)
232
+
233
+ record.save
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
97
239
  end
98
240
 
99
241
  describe "a model which is conditionally multisearchable using a Proc" do
@@ -30,7 +30,7 @@ rescue *error_classes
30
30
  puts " createdb pg_search_test"
31
31
  puts "-" * 80
32
32
  end
33
- raise $!
33
+ raise $ERROR_INFO
34
34
  end
35
35
 
36
36
  if ENV["LOGGER"]
@@ -50,7 +50,7 @@ rescue
50
50
  else
51
51
  share_path = `pg_config --sharedir`.strip
52
52
  ActiveRecord::Base.connection.execute File.read(File.join(share_path, 'contrib', "#{name}.sql"))
53
- puts $!.message
53
+ puts $ERROR_INFO.message
54
54
  end
55
55
  rescue => exception
56
56
  at_exit do
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: 1.0.5
4
+ version: 1.0.6
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: 2015-08-30 00:00:00.000000000 Z
12
+ date: 2016-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -115,14 +115,14 @@ dependencies:
115
115
  requirements:
116
116
  - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: 0.30.0
118
+ version: '0.36'
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 0.30.0
125
+ version: '0.36'
126
126
  description: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
127
127
  full text search
128
128
  email:
@@ -184,7 +184,6 @@ files:
184
184
  - spec/lib/pg_search/configuration/association_spec.rb
185
185
  - spec/lib/pg_search/configuration/column_spec.rb
186
186
  - spec/lib/pg_search/configuration/foreign_column_spec.rb
187
- - spec/lib/pg_search/document_spec.rb
188
187
  - spec/lib/pg_search/features/dmetaphone_spec.rb
189
188
  - spec/lib/pg_search/features/trigram_spec.rb
190
189
  - spec/lib/pg_search/features/tsearch_spec.rb
@@ -222,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
221
  version: '0'
223
222
  requirements: []
224
223
  rubyforge_project:
225
- rubygems_version: 2.4.5
224
+ rubygems_version: 2.5.1
226
225
  signing_key:
227
226
  specification_version: 4
228
227
  summary: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
@@ -235,7 +234,6 @@ test_files:
235
234
  - spec/lib/pg_search/configuration/association_spec.rb
236
235
  - spec/lib/pg_search/configuration/column_spec.rb
237
236
  - spec/lib/pg_search/configuration/foreign_column_spec.rb
238
- - spec/lib/pg_search/document_spec.rb
239
237
  - spec/lib/pg_search/features/dmetaphone_spec.rb
240
238
  - spec/lib/pg_search/features/trigram_spec.rb
241
239
  - spec/lib/pg_search/features/tsearch_spec.rb
@@ -1,56 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe PgSearch::Document do
4
- with_table "pg_search_documents", {}, &DOCUMENTS_SCHEMA
5
-
6
- with_model :Searchable do
7
- table
8
- model do
9
- include PgSearch
10
- multisearchable
11
- end
12
- end
13
-
14
- it { is_expected.to be_an(ActiveRecord::Base) }
15
-
16
- describe "callbacks" do
17
- describe "before_validation" do
18
- subject { document }
19
- let(:document) { PgSearch::Document.new(:searchable => searchable) }
20
- let(:searchable) { Searchable.new }
21
-
22
- before do
23
- # Redefine the options for multisearchable
24
- Searchable.multisearchable(multisearchable_options)
25
- end
26
-
27
- context "when searching against a single column" do
28
- let(:multisearchable_options) { {:against => :some_content} }
29
- let(:text) { "foo bar" }
30
- before do
31
- allow(searchable).to receive(:some_content) { text }
32
- document.valid?
33
- end
34
-
35
- describe '#content' do
36
- subject { super().content }
37
- it { is_expected.to eq(text) }
38
- end
39
- end
40
-
41
- context "when searching against multiple columns" do
42
- let(:multisearchable_options) { {:against => [:attr1, :attr2]} }
43
- before do
44
- allow(searchable).to receive(:attr1) { '1' }
45
- allow(searchable).to receive(:attr2) { '2' }
46
- document.valid?
47
- end
48
-
49
- describe '#content' do
50
- subject { super().content }
51
- it { is_expected.to eq("1 2") }
52
- end
53
- end
54
- end
55
- end
56
- end