pg_search 1.0.5 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +111 -28
- data/.travis.yml +4 -3
- data/CHANGELOG.md +7 -2
- data/Gemfile +0 -7
- data/README.md +36 -3
- data/lib/pg_search.rb +12 -1
- data/lib/pg_search/document.rb +0 -11
- data/lib/pg_search/features/tsearch.rb +43 -8
- data/lib/pg_search/multisearchable.rb +30 -1
- data/lib/pg_search/scope_options.rb +28 -1
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +2 -2
- data/spec/integration/pg_search_spec.rb +27 -0
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +13 -0
- data/spec/lib/pg_search/multisearchable_spec.rb +142 -0
- data/spec/support/database.rb +2 -2
- metadata +5 -7
- data/spec/lib/pg_search/document_spec.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55ed2cdc0eaecdb0dcb05ee5fcf7e7460556669d
|
4
|
+
data.tar.gz: 8ff17add1a0a7c7a16dd6501b6335e5d364b07b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1acf5bc208de87a781c1c2ddaa3b44b33609afb8927cd8bbbb256a9a9caf099f3c2507232a0d9f2a9ad45acaf997e3590bbcbac6d3cb4936515e6874c3cb4ea1
|
7
|
+
data.tar.gz: d569da3e3f8aa7b205596fbce5d1bd72e0db4dab9576ac9331b810b4dbcefd80f77918a8ce51cfb3e944f63520f4166e86bd5db883b01c0e2b8f97e3bff7018d
|
data/.rubocop_todo.yml
CHANGED
@@ -1,37 +1,84 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
#
|
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:
|
26
|
+
# Offense count: 3
|
13
27
|
# Cop supports --auto-correct.
|
14
|
-
|
15
|
-
|
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:
|
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:
|
20
|
-
|
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
|
-
|
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
|
-
|
76
|
+
Exclude:
|
77
|
+
- 'lib/pg_search/document.rb'
|
32
78
|
|
33
|
-
# Offense count:
|
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
|
-
|
89
|
+
Exclude:
|
90
|
+
- 'lib/pg_search/scope_options.rb'
|
43
91
|
|
44
|
-
# Offense count:
|
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
|
-
|
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
|
-
|
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:
|
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:
|
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
|
-
|
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
|
-
|
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
|
-
|
161
|
+
Exclude:
|
162
|
+
- 'lib/pg_search/features/feature.rb'
|
163
|
+
- 'lib/pg_search/multisearch/rebuilder.rb'
|
94
164
|
|
95
|
-
# Offense count:
|
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
|
-
|
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
|
-
|
105
|
-
|
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:
|
187
|
+
# Offense count: 2
|
108
188
|
# Cop supports --auto-correct.
|
109
189
|
Style/UnneededPercentQ:
|
110
|
-
|
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
|
-
|
198
|
+
EnforcedStyle: percent
|
199
|
+
MinSize: 3
|
data/.travis.yml
CHANGED
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).
|
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
|
-
.
|
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 .
|
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
|
data/lib/pg_search/document.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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?
|
133
|
+
if config.associations.any?
|
107
134
|
config.associations.map do |association|
|
108
135
|
association.join(primary_key)
|
109
136
|
end.join(' ')
|
data/lib/pg_search/version.rb
CHANGED
data/pg_search.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
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.
|
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
|
data/spec/support/database.rb
CHANGED
@@ -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
|
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.
|
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:
|
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.
|
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.
|
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.
|
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
|