sunspot_matchers 1.1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +33 -0
- data/README.markdown +229 -0
- data/Rakefile +2 -0
- data/lib/sunspot_matchers/matchers.rb +237 -0
- data/lib/sunspot_matchers/sunspot_session_spy.rb +111 -0
- data/lib/sunspot_matchers/version.rb +3 -0
- data/lib/sunspot_matchers.rb +2 -0
- data/spec/sunspot_matchers_spec.rb +651 -0
- data/sunspot_matchers.gemspec +22 -0
- metadata +128 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sunspot_matchers (1.1.0.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
builder (3.0.0)
|
10
|
+
diff-lcs (1.1.2)
|
11
|
+
escape (0.0.4)
|
12
|
+
rsolr (0.12.1)
|
13
|
+
builder (>= 2.1.2)
|
14
|
+
rspec (2.1.0)
|
15
|
+
rspec-core (~> 2.1.0)
|
16
|
+
rspec-expectations (~> 2.1.0)
|
17
|
+
rspec-mocks (~> 2.1.0)
|
18
|
+
rspec-core (2.1.0)
|
19
|
+
rspec-expectations (2.1.0)
|
20
|
+
diff-lcs (~> 1.1.2)
|
21
|
+
rspec-mocks (2.1.0)
|
22
|
+
sunspot (1.1.0)
|
23
|
+
escape (= 0.0.4)
|
24
|
+
rsolr (= 0.12.1)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
bundler (>= 1.0.0)
|
31
|
+
rspec (~> 2.1.0)
|
32
|
+
sunspot (~> 1.1.0)
|
33
|
+
sunspot_matchers!
|
data/README.markdown
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
# Sunspot Matchers
|
2
|
+
|
3
|
+
[Sunspot](http://outoftime.github.com/sunspot/) is a great Ruby library for constructing searches against Solr. However,
|
4
|
+
because of the way the Sunspot DSL is constructed, it can be difficult to do simple assertions about your searches
|
5
|
+
without doing full integration tests.
|
6
|
+
|
7
|
+
The goal of these matchers are to make it easier to unit test search logic without having to construct the individual
|
8
|
+
fixture scenarios inside of Solr and then actually perform a search against Solr.
|
9
|
+
|
10
|
+
# Installation
|
11
|
+
|
12
|
+
You will need to replace the Sunspot Session object with the spy provided. You can do this globally by putting the
|
13
|
+
following in your spec_helper.
|
14
|
+
|
15
|
+
config.before do
|
16
|
+
Sunspot.session = SunspotMatchers::SunspotSessionSpy.new(Sunspot.session)
|
17
|
+
end
|
18
|
+
|
19
|
+
Keep in mind, this will prevent any test from actually hitting Solr, so if you have integration tests, you'll either
|
20
|
+
need to be more careful which tests you replace the session for, or you'll need to restore the original session before
|
21
|
+
those tests
|
22
|
+
|
23
|
+
Sunspot.session = Sunspot.session.original_session
|
24
|
+
|
25
|
+
You will also need to include the matchers in your specs. Again, this can be done globally in your spec_helper.
|
26
|
+
|
27
|
+
config.include SunspotMatchers
|
28
|
+
|
29
|
+
Alternately, you could include them into individual tests if needed.
|
30
|
+
|
31
|
+
# Matchers
|
32
|
+
|
33
|
+
## be_a_search_for
|
34
|
+
|
35
|
+
If you perform a search against your Post model, you could write this expectation:
|
36
|
+
|
37
|
+
`Sunspot.session.should be_a_search_for(Post)`
|
38
|
+
|
39
|
+
Individual searches are stored in an array, so if you perform multiple, you'll have to match against them manually. Without
|
40
|
+
an explicit search specified, it will use the last one.
|
41
|
+
|
42
|
+
`Sunspot.session.searches.first.should be_a_search_for(Post)`
|
43
|
+
|
44
|
+
## have_search_params
|
45
|
+
|
46
|
+
This is where the bulk of the functionality lies. There are seven types of search matches you can perform: `keywords`,
|
47
|
+
`with`, `without`, `paginate`, `order_by`, `facet`, and `boost`.
|
48
|
+
|
49
|
+
In all of the examples below, the expectation fully matches the search terms. This is not expected or required. You can
|
50
|
+
have a dozen `with` restrictions on a search and still write an expectation on a single one of them.
|
51
|
+
|
52
|
+
Negative expectations also work correctly. `should_not` will fail if the search actually includes the expectation.
|
53
|
+
|
54
|
+
With all matchers, you can specify a `Proc` as the second argument, and perform multi statement expectations inside the
|
55
|
+
Proc. Keep in mind, that only the expectation type specified in the first argument will actually be checked. So if
|
56
|
+
you specify `keywords` and `with` restrictions in the same Proc, but you said `have_search_params(:keywords, ...`
|
57
|
+
the `with` restrictions are simply ignored.
|
58
|
+
|
59
|
+
### wildcard matching
|
60
|
+
|
61
|
+
keywords, with, and without support wildcard expectations using the `any_param` parameter:
|
62
|
+
|
63
|
+
Sunspot.search(Post) do
|
64
|
+
with :blog_id, 4
|
65
|
+
end
|
66
|
+
|
67
|
+
Sunspot.session.should have_search_params(:with, :blog_id, any_param)
|
68
|
+
|
69
|
+
### :keywords
|
70
|
+
|
71
|
+
You can match against a keyword search:
|
72
|
+
|
73
|
+
Sunspot.search(Post) do
|
74
|
+
keywords 'great pizza'
|
75
|
+
end
|
76
|
+
|
77
|
+
Sunspot.session.should have_search_params(:keywords, 'great pizza')
|
78
|
+
|
79
|
+
### :with
|
80
|
+
|
81
|
+
You can match against a with restriction:
|
82
|
+
|
83
|
+
Sunspot.search(Post) do
|
84
|
+
with :author_name, 'Mark Twain'
|
85
|
+
end
|
86
|
+
|
87
|
+
Sunspot.session.should have_search_params(:with, :author_name, 'Mark Twain')
|
88
|
+
|
89
|
+
Complex conditions can be matched by using a Proc instead of a value. Be aware that order does matter, not for
|
90
|
+
the actual results that would come out of Solr, but the matcher will fail of the order of `with` restrictions is
|
91
|
+
different.
|
92
|
+
|
93
|
+
Sunspot.search(Post) do
|
94
|
+
any_of do
|
95
|
+
with :category_ids, 1
|
96
|
+
with :category_ids, 2
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Sunspot.session.should have_search_params(:with, Proc.new {
|
101
|
+
any_of do
|
102
|
+
with :category_ids, 1
|
103
|
+
with :category_ids, 2
|
104
|
+
end
|
105
|
+
})
|
106
|
+
|
107
|
+
### :without
|
108
|
+
|
109
|
+
Without is nearly identical to with:
|
110
|
+
|
111
|
+
Sunspot.search(Post) do
|
112
|
+
without :author_name, 'Mark Twain'
|
113
|
+
end
|
114
|
+
|
115
|
+
Sunspot.session.should have_search_params(:without, :author_name, 'Mark Twain')
|
116
|
+
|
117
|
+
### :paginate
|
118
|
+
|
119
|
+
You can also specify only page or per_page, both are not required.
|
120
|
+
|
121
|
+
Sunspot.search(Post) do
|
122
|
+
paginate :page => 3, :per_page => 15
|
123
|
+
end
|
124
|
+
|
125
|
+
Sunspot.session.should have_search_params(:paginate, :page => 3, :per_page => 15)
|
126
|
+
|
127
|
+
### :order_by
|
128
|
+
|
129
|
+
Expectations on multiple orderings are supported using using the Proc format mentioned above.
|
130
|
+
|
131
|
+
Sunspot.search(Post) do
|
132
|
+
order_by :published_at, :desc
|
133
|
+
end
|
134
|
+
|
135
|
+
Sunspot.session.should have_search_params(:order_by, :published_at, :desc)
|
136
|
+
|
137
|
+
### :facet
|
138
|
+
|
139
|
+
Standard faceting expectation:
|
140
|
+
|
141
|
+
Sunspot.search(Post) do
|
142
|
+
facet :category_ids
|
143
|
+
end
|
144
|
+
|
145
|
+
Sunspot.session.should have_search_params(:facet, :category_ids)
|
146
|
+
|
147
|
+
Faceting where a query is excluded:
|
148
|
+
|
149
|
+
Sunspot.search(Post) do
|
150
|
+
category_filter = with(:category_ids, 2)
|
151
|
+
facet(:category_ids, :exclude => category_filter)
|
152
|
+
end
|
153
|
+
|
154
|
+
Sunspot.session.should have_search_params(:facet, Proc.new {
|
155
|
+
category_filter = with(:category_ids, 2)
|
156
|
+
facet(:category_ids, :exclude => category_filter)
|
157
|
+
})
|
158
|
+
|
159
|
+
Query faceting:
|
160
|
+
|
161
|
+
Sunspot.search(Post) do
|
162
|
+
facet(:average_rating) do
|
163
|
+
row(1.0..2.0) do
|
164
|
+
with(:average_rating, 1.0..2.0)
|
165
|
+
end
|
166
|
+
row(2.0..3.0) do
|
167
|
+
with(:average_rating, 2.0..3.0)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
Sunspot.session.should have_search_params(:facet, Proc.new {
|
173
|
+
facet(:average_rating) do
|
174
|
+
row(1.0..2.0) do
|
175
|
+
with(:average_rating, 1.0..2.0)
|
176
|
+
end
|
177
|
+
row(2.0..3.0) do
|
178
|
+
with(:average_rating, 2.0..3.0)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
})
|
182
|
+
|
183
|
+
### :boost
|
184
|
+
|
185
|
+
Field boost matching:
|
186
|
+
|
187
|
+
Sunspot.search(Post) do
|
188
|
+
keywords 'great pizza' do
|
189
|
+
boost_fields :body => 2.0
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
Sunspot.session.should have_search_params(:boost, Proc.new {
|
194
|
+
keywords 'great pizza' do
|
195
|
+
boost_fields :body => 2.0
|
196
|
+
end
|
197
|
+
})
|
198
|
+
|
199
|
+
Boost query matching:
|
200
|
+
|
201
|
+
Sunspot.search(Post) do
|
202
|
+
keywords 'great pizza' do
|
203
|
+
boost(2.0) do
|
204
|
+
with :blog_id, 4
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
Sunspot.session.should have_search_params(:boost, Proc.new {
|
210
|
+
keywords 'great pizza' do
|
211
|
+
boost(2.0) do
|
212
|
+
with :blog_id, 4
|
213
|
+
end
|
214
|
+
end
|
215
|
+
})
|
216
|
+
|
217
|
+
Boost function matching:
|
218
|
+
|
219
|
+
Sunspot.search(Post) do
|
220
|
+
keywords 'great pizza' do
|
221
|
+
boost(function { sum(:average_rating, product(:popularity, 10)) })
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
Sunspot.session.should have_search_params(:boost, Proc.new {
|
226
|
+
keywords 'great pizza' do
|
227
|
+
boost(function { sum(:average_rating, product(:popularity, 10)) })
|
228
|
+
end
|
229
|
+
})
|
data/Rakefile
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
module SunspotMatchers
|
2
|
+
class BaseMatcher
|
3
|
+
def initialize(actual_search, comparison_search, args)
|
4
|
+
@args = args
|
5
|
+
@actual_search, @comparison_search = actual_search, comparison_search
|
6
|
+
end
|
7
|
+
|
8
|
+
def search_tuple
|
9
|
+
search_tuple = @actual.is_a?(Array) ? @actual : @actual.searches.last
|
10
|
+
raise 'no search found' unless search_tuple
|
11
|
+
search_tuple
|
12
|
+
end
|
13
|
+
|
14
|
+
def actual_search
|
15
|
+
search_tuple.last
|
16
|
+
end
|
17
|
+
|
18
|
+
def search_types
|
19
|
+
search_tuple.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def wildcard?
|
23
|
+
@args && @args.last == any_param
|
24
|
+
end
|
25
|
+
|
26
|
+
def field
|
27
|
+
@args && @args.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_params_for_search(search)
|
31
|
+
search.instance_variable_get(:@query).to_params
|
32
|
+
end
|
33
|
+
|
34
|
+
def actual_params
|
35
|
+
@actual_params ||= query_params_for_search(@actual_search)
|
36
|
+
end
|
37
|
+
|
38
|
+
def comparison_params
|
39
|
+
@comparison_params ||= query_params_for_search(@comparison_search)
|
40
|
+
end
|
41
|
+
|
42
|
+
def match?
|
43
|
+
differences.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def missing_param_error_message
|
47
|
+
missing_params = differences
|
48
|
+
actual_values = missing_params.keys.collect {|key| "#{key} => #{actual_params[key]}"}
|
49
|
+
missing_values = missing_params.collect{ |key, value| "#{key} => #{value}"}
|
50
|
+
"expected search params: #{actual_values.join(' and ')} to match expected: #{missing_values.join(' and ')}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def unexpected_match_error_message
|
54
|
+
actual_values = keys_to_compare.collect {|key| "#{key} => #{actual_params[key]}"}
|
55
|
+
comparison_values = keys_to_compare.collect {|key| "#{key} => #{comparison_params[key]}"}
|
56
|
+
"expected search params: #{actual_values.join(' and ')} NOT to match expected: #{comparison_values.join(' and ')}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def differences
|
60
|
+
keys_to_compare.inject({}) do |hsh, key|
|
61
|
+
result = compare_key(key)
|
62
|
+
hsh[key] = result unless result.empty?
|
63
|
+
hsh
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def compare_key(key)
|
68
|
+
if(actual_params[key].is_a?(Array) || comparison_params[key].is_a?(Array))
|
69
|
+
compare_multi_value(actual_params[key], comparison_params[key])
|
70
|
+
else
|
71
|
+
compare_single_value(actual_params[key], comparison_matcher_for_key(key))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def comparison_matcher_for_key(key)
|
76
|
+
if wildcard? && wildcard_matcher_for_keys.has_key?(key)
|
77
|
+
wildcard_matcher_for_keys[key]
|
78
|
+
else
|
79
|
+
comparison_params[key]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def compare_single_value(actual, comparison)
|
84
|
+
if comparison.is_a?(Regexp)
|
85
|
+
return [] if comparison =~ actual
|
86
|
+
return [comparison]
|
87
|
+
end
|
88
|
+
return [comparison] unless actual == comparison
|
89
|
+
[]
|
90
|
+
end
|
91
|
+
|
92
|
+
def compare_multi_value(actual, comparison)
|
93
|
+
filter_values(comparison).reject do |value|
|
94
|
+
next false unless actual
|
95
|
+
value_matcher = Regexp.new(Regexp.escape(value))
|
96
|
+
actual.any?{ |actual_value| actual_value =~ value_matcher }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def normalize_value(value)
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
def filter_values(values)
|
105
|
+
return values unless wildcard?
|
106
|
+
field_matcher = Regexp.new(field.to_s)
|
107
|
+
values.select{ |value| field_matcher =~ value }.collect{|value| value.gsub(/:.*/, '')}
|
108
|
+
end
|
109
|
+
|
110
|
+
def wildcard_matcher_for_keys
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class HaveSearchParams < BaseMatcher
|
116
|
+
def initialize(method, *args)
|
117
|
+
@method = method
|
118
|
+
@args = args
|
119
|
+
end
|
120
|
+
|
121
|
+
def matches?(actual)
|
122
|
+
@actual = actual
|
123
|
+
@matcher = build_matcher
|
124
|
+
@matcher.match?
|
125
|
+
end
|
126
|
+
|
127
|
+
def failure_message_for_should
|
128
|
+
@matcher.missing_param_error_message
|
129
|
+
end
|
130
|
+
|
131
|
+
def failure_message_for_should_not
|
132
|
+
@matcher.unexpected_match_error_message
|
133
|
+
end
|
134
|
+
|
135
|
+
def build_matcher
|
136
|
+
comparison_search = if(@args.last.is_a?(Proc))
|
137
|
+
SunspotMatchers::SunspotSessionSpy.new(nil).build_search(search_types, &@args.last)
|
138
|
+
else
|
139
|
+
method = @method
|
140
|
+
args = @args
|
141
|
+
SunspotMatchers::SunspotSessionSpy.new(nil).build_search(search_types) do
|
142
|
+
send(method, *args)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
get_matcher.new(actual_search, comparison_search, @args)
|
147
|
+
end
|
148
|
+
|
149
|
+
def get_matcher
|
150
|
+
case @method
|
151
|
+
when :with, :without
|
152
|
+
WithMatcher
|
153
|
+
when :keywords
|
154
|
+
KeywordsMatcher
|
155
|
+
when :boost
|
156
|
+
BoostMatcher
|
157
|
+
when :facet
|
158
|
+
FacetMatcher
|
159
|
+
when :order_by
|
160
|
+
SortMatcher
|
161
|
+
when :paginate
|
162
|
+
PaginationMatcher
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def have_search_params(method, *args)
|
168
|
+
HaveSearchParams.new(method, *args)
|
169
|
+
end
|
170
|
+
|
171
|
+
class WithMatcher < BaseMatcher
|
172
|
+
def keys_to_compare
|
173
|
+
[:fq]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class KeywordsMatcher < BaseMatcher
|
178
|
+
def keys_to_compare
|
179
|
+
[:q, :qf]
|
180
|
+
end
|
181
|
+
|
182
|
+
def wildcard_matcher_for_keys
|
183
|
+
{:q => /./, :qf => /./}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class BoostMatcher < BaseMatcher
|
188
|
+
def keys_to_compare
|
189
|
+
[:qf, :bq, :bf]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
class FacetMatcher < BaseMatcher
|
194
|
+
def keys_to_compare
|
195
|
+
comparison_params.keys.select {|key| /facet/ =~ key.to_s}
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class SortMatcher < BaseMatcher
|
200
|
+
def keys_to_compare
|
201
|
+
[:sort]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class PaginationMatcher < BaseMatcher
|
206
|
+
def keys_to_compare
|
207
|
+
[:rows, :start]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
class BeASearchFor < BaseMatcher
|
212
|
+
def initialize(expected_class)
|
213
|
+
@expected_class = expected_class
|
214
|
+
end
|
215
|
+
|
216
|
+
def matches?(actual)
|
217
|
+
@actual = actual
|
218
|
+
search_types.include?(@expected_class)
|
219
|
+
end
|
220
|
+
|
221
|
+
def failure_message_for_should
|
222
|
+
"expected search class: #{search_types.join(' and ')} to match expected class: #{@expected_class}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def failure_message_for_should_not
|
226
|
+
"expected search class: #{search_types.join(' and ')} NOT to match expected class: #{@expected_class}"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def be_a_search_for(expected_class)
|
231
|
+
BeASearchFor.new(expected_class)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def any_param
|
236
|
+
"ANY_PARAM"
|
237
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module SunspotMatchers
|
2
|
+
class SunspotSearchSpy < Sunspot::Search::StandardSearch
|
3
|
+
def execute
|
4
|
+
self
|
5
|
+
end
|
6
|
+
def solr_response
|
7
|
+
{}
|
8
|
+
end
|
9
|
+
def facet_response
|
10
|
+
{'facet_queries' => {}}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SunspotSessionSpy < Sunspot::Session
|
15
|
+
attr_reader :original_session
|
16
|
+
attr_reader :current_search_class
|
17
|
+
|
18
|
+
attr_accessor :searches
|
19
|
+
|
20
|
+
def initialize(original_session)
|
21
|
+
@searches = []
|
22
|
+
@original_session = original_session
|
23
|
+
@config = Sunspot::Configuration.build
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
'Solr Search'
|
28
|
+
end
|
29
|
+
|
30
|
+
def index(*objects)
|
31
|
+
end
|
32
|
+
|
33
|
+
def index!(*objects)
|
34
|
+
end
|
35
|
+
|
36
|
+
def remove(*objects)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove!(*objects)
|
40
|
+
end
|
41
|
+
|
42
|
+
def remove_by_id(clazz, id)
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_by_id!(clazz, id)
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove_all(clazz = nil)
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove_all!(clazz = nil)
|
52
|
+
end
|
53
|
+
|
54
|
+
def dirty?
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete_dirty?
|
59
|
+
false
|
60
|
+
end
|
61
|
+
|
62
|
+
def commit_if_dirty
|
63
|
+
end
|
64
|
+
|
65
|
+
def commit_if_delete_dirty
|
66
|
+
end
|
67
|
+
|
68
|
+
def commit
|
69
|
+
end
|
70
|
+
|
71
|
+
def search(*types, &block)
|
72
|
+
new_search(*types, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def new_search(*types, &block)
|
76
|
+
search = build_search(*types, &block)
|
77
|
+
@searches << [types, search]
|
78
|
+
search
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_search(*types, &block)
|
82
|
+
types.flatten!
|
83
|
+
search = SunspotSearchSpy.new(
|
84
|
+
nil,
|
85
|
+
setup_for_types(types),
|
86
|
+
Sunspot::Query::StandardQuery.new(types),
|
87
|
+
@config
|
88
|
+
)
|
89
|
+
search.build(&block) if block
|
90
|
+
search
|
91
|
+
end
|
92
|
+
|
93
|
+
def setup_for_types(types)
|
94
|
+
if types.empty?
|
95
|
+
raise(ArgumentError, "You must specify at least one type to search")
|
96
|
+
end
|
97
|
+
if types.length == 1
|
98
|
+
Sunspot::Setup.for(types.first)
|
99
|
+
else
|
100
|
+
CompositeSetup.for(types)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Support Sunspot random field in test -- Sunspot originally generate a random number for the field
|
107
|
+
class Sunspot::Query::Sort::RandomSort < Sunspot::Query::Sort::Abstract
|
108
|
+
def to_param
|
109
|
+
"random #{direction_for_solr}"
|
110
|
+
end
|
111
|
+
end
|