pg_search 0.2 → 0.2.1
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.
- data/CHANGELOG +4 -0
- data/README.rdoc +26 -0
- data/lib/pg_search/features/tsearch.rb +8 -4
- data/lib/pg_search/version.rb +1 -1
- data/spec/associations_spec.rb +46 -46
- data/spec/pg_search_spec.rb +185 -143
- metadata +5 -4
data/CHANGELOG
CHANGED
data/README.rdoc
CHANGED
@@ -302,6 +302,32 @@ Ignoring accents uses the {unaccent contrib package}[http://www.postgresql.org/d
|
|
302
302
|
SpanishQuestion.gringo_search("Que") # => [what]
|
303
303
|
SpanishQuestion.gringo_search("Cüåñtô") # => [how_many]
|
304
304
|
|
305
|
+
=== Using tsvector columns
|
306
|
+
|
307
|
+
PostgreSQL allows you the ability to search against a column with type tsvector instead of using an expression; this speeds up searching dramatically as it offloads creation of the tsvector that the tsquery is evaluated against.
|
308
|
+
|
309
|
+
To use this functionality you'll need to do a few things:
|
310
|
+
|
311
|
+
* Create a column of type tsvector that you'd like to search against. If you want to search using multiple search methods, for example tsearch and dmetaphone, you'll need a column for each.
|
312
|
+
* Create a trigger function that will update the column(s) using the expression appropriate for that type of search. See: http://www.postgresql.org/docs/current/static/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS
|
313
|
+
* Should you have any pre-existing data in the table, update the newly-created tsvector columns with the expression that your trigger function uses.
|
314
|
+
* Add the option to pg_search_scope, e.g:
|
315
|
+
|
316
|
+
pg_search_scope :fast_content_search,
|
317
|
+
:against => :content,
|
318
|
+
:using => {
|
319
|
+
dmetaphone: {
|
320
|
+
tsvector_column: 'tsvector_content_dmetaphone'
|
321
|
+
},
|
322
|
+
tsearch: {
|
323
|
+
dictionary: 'english',
|
324
|
+
tsvector_column: 'tsvector_content_tsearch'
|
325
|
+
}
|
326
|
+
trigram: {} # trigram does not use tsvectors
|
327
|
+
}
|
328
|
+
|
329
|
+
Please note that the :against column is only used when the tsvector_column is not present for the search type.
|
330
|
+
|
305
331
|
== REQUIREMENTS
|
306
332
|
|
307
333
|
* ActiveRecord 2 or 3
|
@@ -50,10 +50,14 @@ module PgSearch
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def tsdocument
|
53
|
-
@
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
if @options[:tsvector_column]
|
54
|
+
@options[:tsvector_column].to_s
|
55
|
+
else
|
56
|
+
@columns.map do |search_column|
|
57
|
+
tsvector = "to_tsvector(:dictionary, #{@normalizer.add_normalization(search_column.to_sql)})"
|
58
|
+
search_column.weight.nil? ? tsvector : "setweight(#{tsvector}, #{connection.quote(search_column.weight)})"
|
59
|
+
end.join(" || ")
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
63
|
def tsearch_rank
|
data/lib/pg_search/version.rb
CHANGED
data/spec/associations_spec.rb
CHANGED
@@ -5,13 +5,13 @@ describe PgSearch do
|
|
5
5
|
if defined?(ActiveRecord::Relation)
|
6
6
|
context "with Arel support" do
|
7
7
|
context "without an :against" do
|
8
|
-
with_model :
|
8
|
+
with_model :AssociatedModel do
|
9
9
|
table do |t|
|
10
10
|
t.string "title"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
with_model :
|
14
|
+
with_model :ModelWithoutAgainst do
|
15
15
|
table do |t|
|
16
16
|
t.string "title"
|
17
17
|
t.belongs_to :another_model
|
@@ -26,29 +26,29 @@ describe PgSearch do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it "returns rows that match the query in the columns of the associated model only" do
|
29
|
-
associated =
|
29
|
+
associated = AssociatedModel.create!(:title => 'abcdef')
|
30
30
|
included = [
|
31
|
-
|
32
|
-
|
31
|
+
ModelWithoutAgainst.create!(:title => 'abcdef', :another_model => associated),
|
32
|
+
ModelWithoutAgainst.create!(:title => 'ghijkl', :another_model => associated)
|
33
33
|
]
|
34
34
|
excluded = [
|
35
|
-
|
35
|
+
ModelWithoutAgainst.create!(:title => 'abcdef')
|
36
36
|
]
|
37
37
|
|
38
|
-
results =
|
38
|
+
results = ModelWithoutAgainst.with_another('abcdef')
|
39
39
|
results.map(&:title).should =~ included.map(&:title)
|
40
40
|
results.should_not include(excluded)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
context "through a belongs_to association" do
|
45
|
-
with_model :
|
45
|
+
with_model :AssociatedModel do
|
46
46
|
table do |t|
|
47
47
|
t.string 'title'
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
with_model :
|
51
|
+
with_model :ModelWithBelongsTo do
|
52
52
|
table do |t|
|
53
53
|
t.string 'title'
|
54
54
|
t.belongs_to 'another_model'
|
@@ -63,36 +63,36 @@ describe PgSearch do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
it "returns rows that match the query in either its own columns or the columns of the associated model" do
|
66
|
-
associated =
|
66
|
+
associated = AssociatedModel.create!(:title => 'abcdef')
|
67
67
|
included = [
|
68
|
-
|
69
|
-
|
68
|
+
ModelWithBelongsTo.create!(:title => 'ghijkl', :another_model => associated),
|
69
|
+
ModelWithBelongsTo.create!(:title => 'abcdef')
|
70
70
|
]
|
71
|
-
excluded =
|
72
|
-
:another_model =>
|
71
|
+
excluded = ModelWithBelongsTo.create!(:title => 'mnopqr',
|
72
|
+
:another_model => AssociatedModel.create!(:title => 'stuvwx'))
|
73
73
|
|
74
|
-
results =
|
74
|
+
results = ModelWithBelongsTo.with_associated('abcdef')
|
75
75
|
results.map(&:title).should =~ included.map(&:title)
|
76
76
|
results.should_not include(excluded)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
80
|
context "through a has_many association" do
|
81
|
-
with_model :
|
81
|
+
with_model :AssociatedModelWithHasMany do
|
82
82
|
table do |t|
|
83
83
|
t.string 'title'
|
84
|
-
t.belongs_to '
|
84
|
+
t.belongs_to 'ModelWithHasMany'
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
with_model :
|
88
|
+
with_model :ModelWithHasMany do
|
89
89
|
table do |t|
|
90
90
|
t.string 'title'
|
91
91
|
end
|
92
92
|
|
93
93
|
model do
|
94
94
|
include PgSearch
|
95
|
-
has_many :other_models, :class_name => 'AssociatedModelWithHasMany', :foreign_key => '
|
95
|
+
has_many :other_models, :class_name => 'AssociatedModelWithHasMany', :foreign_key => 'ModelWithHasMany_id'
|
96
96
|
|
97
97
|
pg_search_scope :with_associated, :against => [:title], :associated_against => {:other_models => :title}
|
98
98
|
end
|
@@ -100,21 +100,21 @@ describe PgSearch do
|
|
100
100
|
|
101
101
|
it "returns rows that match the query in either its own columns or the columns of the associated model" do
|
102
102
|
included = [
|
103
|
-
|
104
|
-
|
105
|
-
|
103
|
+
ModelWithHasMany.create!(:title => 'abcdef', :other_models => [
|
104
|
+
AssociatedModelWithHasMany.create!(:title => 'foo'),
|
105
|
+
AssociatedModelWithHasMany.create!(:title => 'bar')
|
106
106
|
]),
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
ModelWithHasMany.create!(:title => 'ghijkl', :other_models => [
|
108
|
+
AssociatedModelWithHasMany.create!(:title => 'foo bar'),
|
109
|
+
AssociatedModelWithHasMany.create!(:title => 'mnopqr')
|
110
110
|
]),
|
111
|
-
|
111
|
+
ModelWithHasMany.create!(:title => 'foo bar')
|
112
112
|
]
|
113
|
-
excluded =
|
114
|
-
|
113
|
+
excluded = ModelWithHasMany.create!(:title => 'stuvwx', :other_models => [
|
114
|
+
AssociatedModelWithHasMany.create!(:title => 'abcdef')
|
115
115
|
])
|
116
116
|
|
117
|
-
results =
|
117
|
+
results = ModelWithHasMany.with_associated('foo bar')
|
118
118
|
results.map(&:title).should =~ included.map(&:title)
|
119
119
|
results.should_not include(excluded)
|
120
120
|
end
|
@@ -122,7 +122,7 @@ describe PgSearch do
|
|
122
122
|
|
123
123
|
context "across multiple associations" do
|
124
124
|
context "on different tables" do
|
125
|
-
with_model :
|
125
|
+
with_model :FirstAssociatedModel do
|
126
126
|
table do |t|
|
127
127
|
t.string 'title'
|
128
128
|
t.belongs_to 'model_with_many_associations'
|
@@ -130,14 +130,14 @@ describe PgSearch do
|
|
130
130
|
model {}
|
131
131
|
end
|
132
132
|
|
133
|
-
with_model :
|
133
|
+
with_model :SecondAssociatedModel do
|
134
134
|
table do |t|
|
135
135
|
t.string 'title'
|
136
136
|
end
|
137
137
|
model {}
|
138
138
|
end
|
139
139
|
|
140
|
-
with_model :
|
140
|
+
with_model :ModelWithManyAssociations do
|
141
141
|
table do |t|
|
142
142
|
t.string 'title'
|
143
143
|
t.belongs_to 'model_of_second_type'
|
@@ -154,24 +154,24 @@ describe PgSearch do
|
|
154
154
|
end
|
155
155
|
|
156
156
|
it "returns rows that match the query in either its own columns or the columns of the associated model" do
|
157
|
-
matching_second =
|
158
|
-
unmatching_second =
|
157
|
+
matching_second = SecondAssociatedModel.create!(:title => "foo bar")
|
158
|
+
unmatching_second = SecondAssociatedModel.create!(:title => "uiop")
|
159
159
|
|
160
160
|
included = [
|
161
161
|
ModelWithManyAssociations.create!(:title => 'abcdef', :models_of_first_type => [
|
162
|
-
|
163
|
-
|
162
|
+
FirstAssociatedModel.create!(:title => 'foo'),
|
163
|
+
FirstAssociatedModel.create!(:title => 'bar')
|
164
164
|
]),
|
165
165
|
ModelWithManyAssociations.create!(:title => 'ghijkl', :models_of_first_type => [
|
166
|
-
|
167
|
-
|
166
|
+
FirstAssociatedModel.create!(:title => 'foo bar'),
|
167
|
+
FirstAssociatedModel.create!(:title => 'mnopqr')
|
168
168
|
]),
|
169
169
|
ModelWithManyAssociations.create!(:title => 'foo bar'),
|
170
170
|
ModelWithManyAssociations.create!(:title => 'qwerty', :model_of_second_type => matching_second)
|
171
171
|
]
|
172
172
|
excluded = [
|
173
173
|
ModelWithManyAssociations.create!(:title => 'stuvwx', :models_of_first_type => [
|
174
|
-
|
174
|
+
FirstAssociatedModel.create!(:title => 'abcdef')
|
175
175
|
]),
|
176
176
|
ModelWithManyAssociations.create!(:title => 'qwerty', :model_of_second_type => unmatching_second)
|
177
177
|
]
|
@@ -183,7 +183,7 @@ describe PgSearch do
|
|
183
183
|
end
|
184
184
|
|
185
185
|
context "on the same table" do
|
186
|
-
with_model :
|
186
|
+
with_model :DoublyAssociatedModel do
|
187
187
|
table do |t|
|
188
188
|
t.string 'title'
|
189
189
|
t.belongs_to 'model_with_double_association'
|
@@ -237,16 +237,16 @@ describe PgSearch do
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
end
|
240
|
-
|
240
|
+
|
241
241
|
context "against multiple attributes on one association" do
|
242
|
-
with_model :
|
242
|
+
with_model :AssociatedModel do
|
243
243
|
table do |t|
|
244
244
|
t.string 'title'
|
245
245
|
t.text 'author'
|
246
246
|
end
|
247
247
|
end
|
248
248
|
|
249
|
-
with_model :
|
249
|
+
with_model :ModelWithAssociation do
|
250
250
|
table do |t|
|
251
251
|
t.belongs_to 'another_model'
|
252
252
|
end
|
@@ -258,7 +258,7 @@ describe PgSearch do
|
|
258
258
|
pg_search_scope :with_associated, :associated_against => {:another_model => [:title, :author]}
|
259
259
|
end
|
260
260
|
end
|
261
|
-
|
261
|
+
|
262
262
|
it "should only do one join" do
|
263
263
|
included = [
|
264
264
|
ModelWithAssociation.create!(
|
@@ -289,12 +289,12 @@ describe PgSearch do
|
|
289
289
|
included.each { |object| results.should include(object) }
|
290
290
|
excluded.each { |object| results.should_not include(object) }
|
291
291
|
end
|
292
|
-
|
292
|
+
|
293
293
|
end
|
294
294
|
end
|
295
295
|
else
|
296
296
|
context "without Arel support" do
|
297
|
-
with_model :
|
297
|
+
with_model :Model do
|
298
298
|
table do |t|
|
299
299
|
t.string 'title'
|
300
300
|
end
|
data/spec/pg_search_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "an ActiveRecord model which includes PgSearch" do
|
4
4
|
|
5
|
-
with_model :
|
5
|
+
with_model :ModelWithPgSearch do
|
6
6
|
table do |t|
|
7
7
|
t.string 'title'
|
8
8
|
t.text 'content'
|
@@ -16,18 +16,18 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
16
16
|
|
17
17
|
describe ".pg_search_scope" do
|
18
18
|
it "builds a scope" do
|
19
|
-
|
19
|
+
ModelWithPgSearch.class_eval do
|
20
20
|
pg_search_scope "matching_query", :against => []
|
21
21
|
end
|
22
22
|
|
23
23
|
lambda {
|
24
|
-
|
24
|
+
ModelWithPgSearch.scoped({}).matching_query("foo").scoped({})
|
25
25
|
}.should_not raise_error
|
26
26
|
end
|
27
27
|
|
28
28
|
context "when passed a lambda" do
|
29
29
|
it "builds a dynamic scope" do
|
30
|
-
|
30
|
+
ModelWithPgSearch.class_eval do
|
31
31
|
pg_search_scope :search_title_or_content, lambda { |query, pick_content|
|
32
32
|
{
|
33
33
|
:query => query.gsub("-remove-", ""),
|
@@ -36,31 +36,31 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
36
36
|
}
|
37
37
|
end
|
38
38
|
|
39
|
-
included =
|
40
|
-
excluded =
|
39
|
+
included = ModelWithPgSearch.create!(:title => 'foo', :content => 'bar')
|
40
|
+
excluded = ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
41
41
|
|
42
|
-
|
43
|
-
|
42
|
+
ModelWithPgSearch.search_title_or_content('fo-remove-o', false).should == [included]
|
43
|
+
ModelWithPgSearch.search_title_or_content('b-remove-ar', true).should == [included]
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
context "when an unknown option is passed in" do
|
48
48
|
it "raises an exception when invoked" do
|
49
49
|
lambda {
|
50
|
-
|
50
|
+
ModelWithPgSearch.class_eval do
|
51
51
|
pg_search_scope :with_unknown_option, :against => :content, :foo => :bar
|
52
52
|
end
|
53
|
-
|
53
|
+
ModelWithPgSearch.with_unknown_option("foo")
|
54
54
|
}.should raise_error(ArgumentError, /foo/)
|
55
55
|
end
|
56
56
|
|
57
57
|
context "dynamically" do
|
58
58
|
it "raises an exception when invoked" do
|
59
59
|
lambda {
|
60
|
-
|
60
|
+
ModelWithPgSearch.class_eval do
|
61
61
|
pg_search_scope :with_unknown_option, lambda { |*| {:against => :content, :foo => :bar} }
|
62
62
|
end
|
63
|
-
|
63
|
+
ModelWithPgSearch.with_unknown_option("foo")
|
64
64
|
}.should raise_error(ArgumentError, /foo/)
|
65
65
|
end
|
66
66
|
end
|
@@ -69,20 +69,20 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
69
69
|
context "when an unknown :using is passed" do
|
70
70
|
it "raises an exception when invoked" do
|
71
71
|
lambda {
|
72
|
-
|
72
|
+
ModelWithPgSearch.class_eval do
|
73
73
|
pg_search_scope :with_unknown_using, :against => :content, :using => :foo
|
74
74
|
end
|
75
|
-
|
75
|
+
ModelWithPgSearch.with_unknown_using("foo")
|
76
76
|
}.should raise_error(ArgumentError, /foo/)
|
77
77
|
end
|
78
78
|
|
79
79
|
context "dynamically" do
|
80
80
|
it "raises an exception when invoked" do
|
81
81
|
lambda {
|
82
|
-
|
82
|
+
ModelWithPgSearch.class_eval do
|
83
83
|
pg_search_scope :with_unknown_using, lambda { |*| {:against => :content, :using => :foo} }
|
84
84
|
end
|
85
|
-
|
85
|
+
ModelWithPgSearch.with_unknown_using("foo")
|
86
86
|
}.should raise_error(ArgumentError, /foo/)
|
87
87
|
end
|
88
88
|
end
|
@@ -91,20 +91,20 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
91
91
|
context "when an unknown :ignoring is passed" do
|
92
92
|
it "raises an exception when invoked" do
|
93
93
|
lambda {
|
94
|
-
|
94
|
+
ModelWithPgSearch.class_eval do
|
95
95
|
pg_search_scope :with_unknown_ignoring, :against => :content, :ignoring => :foo
|
96
96
|
end
|
97
|
-
|
97
|
+
ModelWithPgSearch.with_unknown_ignoring("foo")
|
98
98
|
}.should raise_error(ArgumentError, /ignoring.*foo/)
|
99
99
|
end
|
100
100
|
|
101
101
|
context "dynamically" do
|
102
102
|
it "raises an exception when invoked" do
|
103
103
|
lambda {
|
104
|
-
|
104
|
+
ModelWithPgSearch.class_eval do
|
105
105
|
pg_search_scope :with_unknown_ignoring, lambda { |*| {:against => :content, :ignoring => :foo} }
|
106
106
|
end
|
107
|
-
|
107
|
+
ModelWithPgSearch.with_unknown_ignoring("foo")
|
108
108
|
}.should raise_error(ArgumentError, /ignoring.*foo/)
|
109
109
|
end
|
110
110
|
end
|
@@ -112,19 +112,19 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
112
112
|
context "when :against is not passed in" do
|
113
113
|
it "raises an exception when invoked" do
|
114
114
|
lambda {
|
115
|
-
|
115
|
+
ModelWithPgSearch.class_eval do
|
116
116
|
pg_search_scope :with_unknown_ignoring, {}
|
117
117
|
end
|
118
|
-
|
118
|
+
ModelWithPgSearch.with_unknown_ignoring("foo")
|
119
119
|
}.should raise_error(ArgumentError, /against/)
|
120
120
|
end
|
121
121
|
context "dynamically" do
|
122
122
|
it "raises an exception when invoked" do
|
123
123
|
lambda {
|
124
|
-
|
124
|
+
ModelWithPgSearch.class_eval do
|
125
125
|
pg_search_scope :with_unknown_ignoring, lambda { |*| {} }
|
126
126
|
end
|
127
|
-
|
127
|
+
ModelWithPgSearch.with_unknown_ignoring("foo")
|
128
128
|
}.should raise_error(ArgumentError, /against/)
|
129
129
|
end
|
130
130
|
end
|
@@ -135,33 +135,33 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
135
135
|
describe "a search scope" do
|
136
136
|
context "against a single column" do
|
137
137
|
before do
|
138
|
-
|
138
|
+
ModelWithPgSearch.class_eval do
|
139
139
|
pg_search_scope :search_content, :against => :content
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
143
|
it "returns an empty array when a blank query is passed in" do
|
144
|
-
|
144
|
+
ModelWithPgSearch.create!(:content => 'foo')
|
145
145
|
|
146
|
-
results =
|
146
|
+
results = ModelWithPgSearch.search_content('')
|
147
147
|
results.should == []
|
148
148
|
end
|
149
149
|
|
150
150
|
it "returns rows where the column contains the term in the query" do
|
151
|
-
included =
|
152
|
-
excluded =
|
151
|
+
included = ModelWithPgSearch.create!(:content => 'foo')
|
152
|
+
excluded = ModelWithPgSearch.create!(:content => 'bar')
|
153
153
|
|
154
|
-
results =
|
154
|
+
results = ModelWithPgSearch.search_content('foo')
|
155
155
|
results.should include(included)
|
156
156
|
results.should_not include(excluded)
|
157
157
|
end
|
158
158
|
|
159
159
|
it "returns rows where the column contains all the terms in the query in any order" do
|
160
|
-
included = [
|
161
|
-
|
162
|
-
excluded =
|
160
|
+
included = [ModelWithPgSearch.create!(:content => 'foo bar'),
|
161
|
+
ModelWithPgSearch.create!(:content => 'bar foo')]
|
162
|
+
excluded = ModelWithPgSearch.create!(:content => 'foo')
|
163
163
|
|
164
|
-
results =
|
164
|
+
results = ModelWithPgSearch.search_content('foo bar')
|
165
165
|
results.should =~ included
|
166
166
|
results.should_not include(excluded)
|
167
167
|
end
|
@@ -170,10 +170,10 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
170
170
|
# \303\241 is a with acute accent
|
171
171
|
# \303\251 is e with acute accent
|
172
172
|
|
173
|
-
included = [
|
174
|
-
|
173
|
+
included = [ModelWithPgSearch.create!(:content => "foo"),
|
174
|
+
ModelWithPgSearch.create!(:content => "FOO")]
|
175
175
|
|
176
|
-
results =
|
176
|
+
results = ModelWithPgSearch.search_content("Foo")
|
177
177
|
results.should =~ included
|
178
178
|
end
|
179
179
|
|
@@ -181,97 +181,97 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
181
181
|
# \303\241 is a with acute accent
|
182
182
|
# \303\251 is e with acute accent
|
183
183
|
|
184
|
-
included =
|
185
|
-
excluded =
|
184
|
+
included = ModelWithPgSearch.create!(:content => "abcd\303\251f")
|
185
|
+
excluded = ModelWithPgSearch.create!(:content => "\303\241bcdef")
|
186
186
|
|
187
|
-
results =
|
187
|
+
results = ModelWithPgSearch.search_content("abcd\303\251f")
|
188
188
|
results.should == [included]
|
189
189
|
results.should_not include(excluded)
|
190
190
|
end
|
191
191
|
|
192
192
|
it "returns rows that match the query but not rows that are prefixed by the query" do
|
193
|
-
included =
|
194
|
-
excluded =
|
193
|
+
included = ModelWithPgSearch.create!(:content => 'pre')
|
194
|
+
excluded = ModelWithPgSearch.create!(:content => 'prefix')
|
195
195
|
|
196
|
-
results =
|
196
|
+
results = ModelWithPgSearch.search_content("pre")
|
197
197
|
results.should == [included]
|
198
198
|
results.should_not include(excluded)
|
199
199
|
end
|
200
200
|
|
201
201
|
it "returns rows that match the query exactly and not those that match the query when stemmed by the default english dictionary" do
|
202
|
-
included =
|
203
|
-
excluded = [
|
204
|
-
|
202
|
+
included = ModelWithPgSearch.create!(:content => "jumped")
|
203
|
+
excluded = [ModelWithPgSearch.create!(:content => "jump"),
|
204
|
+
ModelWithPgSearch.create!(:content => "jumping")]
|
205
205
|
|
206
|
-
results =
|
206
|
+
results = ModelWithPgSearch.search_content("jumped")
|
207
207
|
results.should == [included]
|
208
208
|
end
|
209
209
|
|
210
210
|
it "returns rows that match sorted by rank" do
|
211
|
-
loser =
|
212
|
-
winner =
|
211
|
+
loser = ModelWithPgSearch.create!(:content => 'foo')
|
212
|
+
winner = ModelWithPgSearch.create!(:content => 'foo foo')
|
213
213
|
|
214
|
-
results =
|
214
|
+
results = ModelWithPgSearch.search_content("foo")
|
215
215
|
results[0].rank.should > results[1].rank
|
216
216
|
results.should == [winner, loser]
|
217
217
|
end
|
218
218
|
|
219
219
|
it "returns results that match sorted by primary key for records that rank the same" do
|
220
|
-
sorted_results = [
|
221
|
-
|
220
|
+
sorted_results = [ModelWithPgSearch.create!(:content => 'foo'),
|
221
|
+
ModelWithPgSearch.create!(:content => 'foo')].sort_by(&:id)
|
222
222
|
|
223
|
-
results =
|
223
|
+
results = ModelWithPgSearch.search_content("foo")
|
224
224
|
results.should == sorted_results
|
225
225
|
end
|
226
226
|
|
227
227
|
it "returns results that match a query with multiple space-separated search terms" do
|
228
228
|
included = [
|
229
|
-
|
230
|
-
|
231
|
-
|
229
|
+
ModelWithPgSearch.create!(:content => 'foo bar'),
|
230
|
+
ModelWithPgSearch.create!(:content => 'bar foo'),
|
231
|
+
ModelWithPgSearch.create!(:content => 'bar foo baz'),
|
232
232
|
]
|
233
233
|
excluded = [
|
234
|
-
|
235
|
-
|
234
|
+
ModelWithPgSearch.create!(:content => 'foo'),
|
235
|
+
ModelWithPgSearch.create!(:content => 'foo baz')
|
236
236
|
]
|
237
237
|
|
238
|
-
results =
|
238
|
+
results = ModelWithPgSearch.search_content('foo bar')
|
239
239
|
results.should =~ included
|
240
240
|
results.should_not include(excluded)
|
241
241
|
end
|
242
242
|
|
243
243
|
it "returns rows that match a query with characters that are invalid in a tsquery expression" do
|
244
|
-
included =
|
244
|
+
included = ModelWithPgSearch.create!(:content => "(:Foo.) Bar?, \\")
|
245
245
|
|
246
|
-
results =
|
246
|
+
results = ModelWithPgSearch.search_content("foo :bar .,?() \\")
|
247
247
|
results.should == [included]
|
248
248
|
end
|
249
249
|
|
250
250
|
it "accepts non-string queries and calls #to_s on them" do
|
251
|
-
foo =
|
251
|
+
foo = ModelWithPgSearch.create!(:content => "foo")
|
252
252
|
not_a_string = stub(:to_s => "foo")
|
253
|
-
|
253
|
+
ModelWithPgSearch.search_content(not_a_string).should == [foo]
|
254
254
|
end
|
255
255
|
end
|
256
256
|
|
257
257
|
context "against multiple columns" do
|
258
258
|
before do
|
259
|
-
|
259
|
+
ModelWithPgSearch.class_eval do
|
260
260
|
pg_search_scope :search_title_and_content, :against => [:title, :content]
|
261
261
|
end
|
262
262
|
end
|
263
263
|
|
264
264
|
it "returns rows whose columns contain all of the terms in the query across columns" do
|
265
265
|
included = [
|
266
|
-
|
267
|
-
|
266
|
+
ModelWithPgSearch.create!(:title => 'foo', :content => 'bar'),
|
267
|
+
ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
268
268
|
]
|
269
269
|
excluded = [
|
270
|
-
|
271
|
-
|
270
|
+
ModelWithPgSearch.create!(:title => 'foo', :content => 'foo'),
|
271
|
+
ModelWithPgSearch.create!(:title => 'bar', :content => 'bar')
|
272
272
|
]
|
273
273
|
|
274
|
-
results =
|
274
|
+
results = ModelWithPgSearch.search_title_and_content('foo bar')
|
275
275
|
|
276
276
|
results.should =~ included
|
277
277
|
excluded.each do |result|
|
@@ -280,37 +280,37 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
280
280
|
end
|
281
281
|
|
282
282
|
it "returns rows where at one column contains all of the terms in the query and another does not" do
|
283
|
-
in_title =
|
284
|
-
in_content =
|
283
|
+
in_title = ModelWithPgSearch.create!(:title => 'foo', :content => 'bar')
|
284
|
+
in_content = ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
285
285
|
|
286
|
-
results =
|
286
|
+
results = ModelWithPgSearch.search_title_and_content('foo')
|
287
287
|
results.should =~ [in_title, in_content]
|
288
288
|
end
|
289
289
|
|
290
290
|
# Searching with a NULL column will prevent any matches unless we coalesce it.
|
291
291
|
it "returns rows where at one column contains all of the terms in the query and another is NULL" do
|
292
|
-
included =
|
293
|
-
results =
|
292
|
+
included = ModelWithPgSearch.create!(:title => 'foo', :content => nil)
|
293
|
+
results = ModelWithPgSearch.search_title_and_content('foo')
|
294
294
|
results.should == [included]
|
295
295
|
end
|
296
296
|
end
|
297
297
|
|
298
298
|
context "using trigram" do
|
299
299
|
before do
|
300
|
-
|
300
|
+
ModelWithPgSearch.class_eval do
|
301
301
|
pg_search_scope :with_trigrams, :against => [:title, :content], :using => :trigram
|
302
302
|
end
|
303
303
|
end
|
304
304
|
|
305
305
|
it "returns rows where one searchable column and the query share enough trigrams" do
|
306
|
-
included =
|
307
|
-
results =
|
306
|
+
included = ModelWithPgSearch.create!(:title => 'abcdefghijkl', :content => nil)
|
307
|
+
results = ModelWithPgSearch.with_trigrams('cdefhijkl')
|
308
308
|
results.should == [included]
|
309
309
|
end
|
310
310
|
|
311
311
|
it "returns rows where multiple searchable columns and the query share enough trigrams" do
|
312
|
-
included =
|
313
|
-
results =
|
312
|
+
included = ModelWithPgSearch.create!(:title => 'abcdef', :content => 'ghijkl')
|
313
|
+
results = ModelWithPgSearch.with_trigrams('cdefhijkl')
|
314
314
|
results.should == [included]
|
315
315
|
end
|
316
316
|
end
|
@@ -318,7 +318,7 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
318
318
|
context "using tsearch" do
|
319
319
|
context "with :prefix => true" do
|
320
320
|
before do
|
321
|
-
|
321
|
+
ModelWithPgSearch.class_eval do
|
322
322
|
pg_search_scope :search_title_with_prefixes,
|
323
323
|
:against => :title,
|
324
324
|
:using => {
|
@@ -328,22 +328,22 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
328
328
|
end
|
329
329
|
|
330
330
|
it "returns rows that match the query and that are prefixed by the query" do
|
331
|
-
included =
|
332
|
-
excluded =
|
331
|
+
included = ModelWithPgSearch.create!(:title => 'prefix')
|
332
|
+
excluded = ModelWithPgSearch.create!(:title => 'postfix')
|
333
333
|
|
334
|
-
results =
|
334
|
+
results = ModelWithPgSearch.search_title_with_prefixes("pre")
|
335
335
|
results.should == [included]
|
336
336
|
results.should_not include(excluded)
|
337
337
|
end
|
338
338
|
|
339
339
|
it "returns rows that match the query when the query has a hyphen" do
|
340
340
|
included = [
|
341
|
-
|
342
|
-
|
341
|
+
ModelWithPgSearch.create!(:title => 'foo bar'),
|
342
|
+
ModelWithPgSearch.create!(:title => 'foo-bar')
|
343
343
|
]
|
344
|
-
excluded =
|
344
|
+
excluded = ModelWithPgSearch.create!(:title => 'baz quux')
|
345
345
|
|
346
|
-
results =
|
346
|
+
results = ModelWithPgSearch.search_title_with_prefixes("foo-bar")
|
347
347
|
results.should =~ included
|
348
348
|
results.should_not include(excluded)
|
349
349
|
end
|
@@ -351,7 +351,7 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
351
351
|
|
352
352
|
context "with the english dictionary" do
|
353
353
|
before do
|
354
|
-
|
354
|
+
ModelWithPgSearch.class_eval do
|
355
355
|
pg_search_scope :search_content_with_english,
|
356
356
|
:against => :content,
|
357
357
|
:using => {
|
@@ -361,27 +361,27 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
361
361
|
end
|
362
362
|
|
363
363
|
it "returns rows that match the query when stemmed by the english dictionary" do
|
364
|
-
included = [
|
365
|
-
|
366
|
-
|
364
|
+
included = [ModelWithPgSearch.create!(:content => "jump"),
|
365
|
+
ModelWithPgSearch.create!(:content => "jumped"),
|
366
|
+
ModelWithPgSearch.create!(:content => "jumping")]
|
367
367
|
|
368
|
-
results =
|
368
|
+
results = ModelWithPgSearch.search_content_with_english("jump")
|
369
369
|
results.should =~ included
|
370
370
|
end
|
371
371
|
end
|
372
372
|
|
373
373
|
context "against columns ranked with arrays" do
|
374
374
|
before do
|
375
|
-
|
375
|
+
ModelWithPgSearch.class_eval do
|
376
376
|
pg_search_scope :search_weighted_by_array_of_arrays, :against => [[:content, 'B'], [:title, 'A']]
|
377
377
|
end
|
378
378
|
end
|
379
379
|
|
380
380
|
it "returns results sorted by weighted rank" do
|
381
|
-
loser =
|
382
|
-
winner =
|
381
|
+
loser = ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
382
|
+
winner = ModelWithPgSearch.create!(:title => 'foo', :content => 'bar')
|
383
383
|
|
384
|
-
results =
|
384
|
+
results = ModelWithPgSearch.search_weighted_by_array_of_arrays('foo')
|
385
385
|
results[0].rank.should > results[1].rank
|
386
386
|
results.should == [winner, loser]
|
387
387
|
end
|
@@ -389,16 +389,16 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
389
389
|
|
390
390
|
context "against columns ranked with a hash" do
|
391
391
|
before do
|
392
|
-
|
392
|
+
ModelWithPgSearch.class_eval do
|
393
393
|
pg_search_scope :search_weighted_by_hash, :against => {:content => 'B', :title => 'A'}
|
394
394
|
end
|
395
395
|
end
|
396
396
|
|
397
397
|
it "returns results sorted by weighted rank" do
|
398
|
-
loser =
|
399
|
-
winner =
|
398
|
+
loser = ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
399
|
+
winner = ModelWithPgSearch.create!(:title => 'foo', :content => 'bar')
|
400
400
|
|
401
|
-
results =
|
401
|
+
results = ModelWithPgSearch.search_weighted_by_hash('foo')
|
402
402
|
results[0].rank.should > results[1].rank
|
403
403
|
results.should == [winner, loser]
|
404
404
|
end
|
@@ -406,16 +406,16 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
406
406
|
|
407
407
|
context "against columns of which only some are ranked" do
|
408
408
|
before do
|
409
|
-
|
409
|
+
ModelWithPgSearch.class_eval do
|
410
410
|
pg_search_scope :search_weighted, :against => [:content, [:title, 'A']]
|
411
411
|
end
|
412
412
|
end
|
413
413
|
|
414
414
|
it "returns results sorted by weighted rank using an implied low rank for unranked columns" do
|
415
|
-
loser =
|
416
|
-
winner =
|
415
|
+
loser = ModelWithPgSearch.create!(:title => 'bar', :content => 'foo')
|
416
|
+
winner = ModelWithPgSearch.create!(:title => 'foo', :content => 'bar')
|
417
417
|
|
418
|
-
results =
|
418
|
+
results = ModelWithPgSearch.search_weighted('foo')
|
419
419
|
results[0].rank.should > results[1].rank
|
420
420
|
results.should == [winner, loser]
|
421
421
|
end
|
@@ -424,46 +424,46 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
424
424
|
|
425
425
|
context "using dmetaphone" do
|
426
426
|
before do
|
427
|
-
|
427
|
+
ModelWithPgSearch.class_eval do
|
428
428
|
pg_search_scope :with_dmetaphones, :against => [:title, :content], :using => :dmetaphone
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
432
432
|
it "returns rows where one searchable column and the query share enough dmetaphones" do
|
433
|
-
included =
|
434
|
-
excluded =
|
435
|
-
results =
|
433
|
+
included = ModelWithPgSearch.create!(:title => 'Geoff', :content => nil)
|
434
|
+
excluded = ModelWithPgSearch.create!(:title => 'Bob', :content => nil)
|
435
|
+
results = ModelWithPgSearch.with_dmetaphones('Jeff')
|
436
436
|
results.should == [included]
|
437
437
|
end
|
438
438
|
|
439
439
|
it "returns rows where multiple searchable columns and the query share enough dmetaphones" do
|
440
|
-
included =
|
441
|
-
excluded =
|
442
|
-
results =
|
440
|
+
included = ModelWithPgSearch.create!(:title => 'Geoff', :content => 'George')
|
441
|
+
excluded = ModelWithPgSearch.create!(:title => 'Bob', :content => 'Jones')
|
442
|
+
results = ModelWithPgSearch.with_dmetaphones('Jeff Jorge')
|
443
443
|
results.should == [included]
|
444
444
|
end
|
445
445
|
|
446
446
|
it "returns rows that match dmetaphones that are English stopwords" do
|
447
|
-
included =
|
448
|
-
excluded =
|
449
|
-
results =
|
447
|
+
included = ModelWithPgSearch.create!(:title => 'White', :content => nil)
|
448
|
+
excluded = ModelWithPgSearch.create!(:title => 'Black', :content => nil)
|
449
|
+
results = ModelWithPgSearch.with_dmetaphones('Wight')
|
450
450
|
results.should == [included]
|
451
451
|
end
|
452
452
|
|
453
453
|
it "can handle terms that do not have a dmetaphone equivalent" do
|
454
454
|
term_with_blank_metaphone = "w"
|
455
455
|
|
456
|
-
included =
|
457
|
-
excluded =
|
456
|
+
included = ModelWithPgSearch.create!(:title => 'White', :content => nil)
|
457
|
+
excluded = ModelWithPgSearch.create!(:title => 'Black', :content => nil)
|
458
458
|
|
459
|
-
results =
|
459
|
+
results = ModelWithPgSearch.with_dmetaphones('Wight W')
|
460
460
|
results.should == [included]
|
461
461
|
end
|
462
462
|
end
|
463
463
|
|
464
464
|
context "using multiple features" do
|
465
465
|
before do
|
466
|
-
|
466
|
+
ModelWithPgSearch.class_eval do
|
467
467
|
pg_search_scope :with_tsearch,
|
468
468
|
:against => :title,
|
469
469
|
:using => [
|
@@ -483,19 +483,19 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
483
483
|
end
|
484
484
|
|
485
485
|
it "returns rows that match using any of the features" do
|
486
|
-
record =
|
486
|
+
record = ModelWithPgSearch.create!(:title => "tiling is grouty")
|
487
487
|
|
488
488
|
# matches trigram only
|
489
489
|
trigram_query = "ling is grouty"
|
490
|
-
|
491
|
-
|
492
|
-
|
490
|
+
ModelWithPgSearch.with_trigram(trigram_query).should include(record)
|
491
|
+
ModelWithPgSearch.with_tsearch(trigram_query).should_not include(record)
|
492
|
+
ModelWithPgSearch.with_tsearch_and_trigram_using_array(trigram_query).should == [record]
|
493
493
|
|
494
494
|
# matches tsearch only
|
495
495
|
tsearch_query = "til"
|
496
|
-
|
497
|
-
|
498
|
-
|
496
|
+
ModelWithPgSearch.with_tsearch(tsearch_query).should include(record)
|
497
|
+
ModelWithPgSearch.with_trigram(tsearch_query).should_not include(record)
|
498
|
+
ModelWithPgSearch.with_tsearch_and_trigram_using_array(tsearch_query).should == [record]
|
499
499
|
end
|
500
500
|
|
501
501
|
context "with feature-specific configuration" do
|
@@ -503,7 +503,7 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
503
503
|
@tsearch_config = tsearch_config = {:dictionary => 'english'}
|
504
504
|
@trigram_config = trigram_config = {:foo => 'bar'}
|
505
505
|
|
506
|
-
|
506
|
+
ModelWithPgSearch.class_eval do
|
507
507
|
pg_search_scope :with_tsearch_and_trigram_using_hash,
|
508
508
|
:against => :title,
|
509
509
|
:using => {
|
@@ -518,14 +518,56 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
518
518
|
PgSearch::Features::TSearch.should_receive(:new).with(anything, @tsearch_config, anything, anything, anything).at_least(:once).and_return(stub_feature)
|
519
519
|
PgSearch::Features::Trigram.should_receive(:new).with(anything, @trigram_config, anything, anything, anything).at_least(:once).and_return(stub_feature)
|
520
520
|
|
521
|
-
|
521
|
+
ModelWithPgSearch.with_tsearch_and_trigram_using_hash("foo")
|
522
522
|
end
|
523
523
|
end
|
524
524
|
end
|
525
525
|
|
526
|
+
context "using a tsvector column" do
|
527
|
+
with_model :ModelWithPgSearchUsingTsVectorColumn do
|
528
|
+
table do |t|
|
529
|
+
t.text 'content'
|
530
|
+
t.column 'content_tsvector', :tsvector
|
531
|
+
end
|
532
|
+
|
533
|
+
model { include PgSearch }
|
534
|
+
end
|
535
|
+
|
536
|
+
let!(:expected) { ModelWithPgSearchUsingTsVectorColumn.create!(:content => 'tiling is grouty') }
|
537
|
+
let!(:unexpected) { ModelWithPgSearchUsingTsVectorColumn.create!(:content => 'longcat is looooooooong') }
|
538
|
+
|
539
|
+
before do
|
540
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
541
|
+
UPDATE #{ModelWithPgSearchUsingTsVectorColumn.table_name}
|
542
|
+
SET content_tsvector = to_tsvector('english'::regconfig, "#{ModelWithPgSearchUsingTsVectorColumn.table_name}"."content")
|
543
|
+
SQL
|
544
|
+
|
545
|
+
ModelWithPgSearchUsingTsVectorColumn.class_eval do
|
546
|
+
pg_search_scope :search_by_content_with_tsvector,
|
547
|
+
:against => :content,
|
548
|
+
:using => {
|
549
|
+
:tsearch => {
|
550
|
+
:tsvector_column => 'content_tsvector',
|
551
|
+
:dictionary => 'english'
|
552
|
+
}
|
553
|
+
}
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
if defined?(ActiveRecord::Relation)
|
558
|
+
it "should not use to_tsvector in the query" do
|
559
|
+
ModelWithPgSearchUsingTsVectorColumn.search_by_content_with_tsvector("tiles").to_sql.should_not =~ /to_tsvector/
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
it "should find the expected result" do
|
564
|
+
ModelWithPgSearchUsingTsVectorColumn.search_by_content_with_tsvector("tiles").map(&:id).should == [expected.id]
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
526
568
|
context "ignoring accents" do
|
527
569
|
before do
|
528
|
-
|
570
|
+
ModelWithPgSearch.class_eval do
|
529
571
|
pg_search_scope :search_title_without_accents, :against => :title, :ignoring => :accents
|
530
572
|
end
|
531
573
|
end
|
@@ -534,16 +576,16 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
534
576
|
# \303\241 is a with acute accent
|
535
577
|
# \303\251 is e with acute accent
|
536
578
|
|
537
|
-
included =
|
579
|
+
included = ModelWithPgSearch.create!(:title => "\303\241bcdef")
|
538
580
|
|
539
|
-
results =
|
581
|
+
results = ModelWithPgSearch.search_title_without_accents("abcd\303\251f")
|
540
582
|
results.should == [included]
|
541
583
|
end
|
542
584
|
end
|
543
585
|
|
544
586
|
context "when passed a :ranked_by expression" do
|
545
587
|
before do
|
546
|
-
|
588
|
+
ModelWithPgSearch.class_eval do
|
547
589
|
pg_search_scope :search_content_with_default_rank,
|
548
590
|
:against => :content
|
549
591
|
pg_search_scope :search_content_with_importance_as_rank,
|
@@ -556,28 +598,28 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
556
598
|
end
|
557
599
|
|
558
600
|
it "should return records with a rank attribute equal to the :ranked_by expression" do
|
559
|
-
|
560
|
-
results =
|
601
|
+
ModelWithPgSearch.create!(:content => 'foo', :importance => 10)
|
602
|
+
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo")
|
561
603
|
results.first.rank.should == 10
|
562
604
|
end
|
563
605
|
|
564
606
|
it "should substitute :tsearch with the tsearch rank expression in the :ranked_by expression" do
|
565
|
-
|
607
|
+
ModelWithPgSearch.create!(:content => 'foo', :importance => 10)
|
566
608
|
|
567
|
-
tsearch_rank =
|
568
|
-
multiplied_rank =
|
609
|
+
tsearch_rank = ModelWithPgSearch.search_content_with_default_rank("foo").first.rank
|
610
|
+
multiplied_rank = ModelWithPgSearch.search_content_with_importance_as_rank_multiplier("foo").first.rank
|
569
611
|
|
570
612
|
multiplied_rank.should be_within(0.001).of(tsearch_rank * 10)
|
571
613
|
end
|
572
614
|
|
573
615
|
it "should return results in descending order of the value of the rank expression" do
|
574
616
|
records = [
|
575
|
-
|
576
|
-
|
577
|
-
|
617
|
+
ModelWithPgSearch.create!(:content => 'foo', :importance => 1),
|
618
|
+
ModelWithPgSearch.create!(:content => 'foo', :importance => 3),
|
619
|
+
ModelWithPgSearch.create!(:content => 'foo', :importance => 2)
|
578
620
|
]
|
579
621
|
|
580
|
-
results =
|
622
|
+
results = ModelWithPgSearch.search_content_with_importance_as_rank("foo")
|
581
623
|
results.should == records.sort_by(&:importance).reverse
|
582
624
|
end
|
583
625
|
|
@@ -586,7 +628,7 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
586
628
|
context "using the #{feature} ranking algorithm" do
|
587
629
|
before do
|
588
630
|
@scope_name = scope_name = :"search_content_ranked_by_#{feature}"
|
589
|
-
|
631
|
+
ModelWithPgSearch.class_eval do
|
590
632
|
pg_search_scope scope_name,
|
591
633
|
:against => :content,
|
592
634
|
:ranked_by => ":#{feature}"
|
@@ -594,9 +636,9 @@ describe "an ActiveRecord model which includes PgSearch" do
|
|
594
636
|
end
|
595
637
|
|
596
638
|
it "should return results with a rank" do
|
597
|
-
|
639
|
+
ModelWithPgSearch.create!(:content => 'foo')
|
598
640
|
|
599
|
-
results =
|
641
|
+
results = ModelWithPgSearch.send(@scope_name, 'foo')
|
600
642
|
results.first.rank.should_not be_nil
|
601
643
|
end
|
602
644
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Case Commons, LLC
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-
|
18
|
+
date: 2011-12-15 00:00:00 Z
|
18
19
|
dependencies: []
|
19
20
|
|
20
21
|
description: PgSearch builds ActiveRecord named scopes that take advantage of PostgreSQL's full text search
|
@@ -89,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
90
|
requirements: []
|
90
91
|
|
91
92
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.8.
|
93
|
+
rubygems_version: 1.8.10
|
93
94
|
signing_key:
|
94
95
|
specification_version: 3
|
95
96
|
summary: PgSearch builds ActiveRecord named scopes that take advantage of PostgreSQL's full text search
|