gojee-sunspot 2.0.3 → 2.0.4
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/.gitignore +12 -0
- data/Gemfile +5 -0
- data/History.txt +252 -0
- data/LICENSE +18 -0
- data/Rakefile +13 -0
- data/TODO +13 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot/adapters.rb +265 -0
- data/lib/sunspot/batcher.rb +62 -0
- data/lib/sunspot/class_set.rb +23 -0
- data/lib/sunspot/composite_setup.rb +202 -0
- data/lib/sunspot/configuration.rb +53 -0
- data/lib/sunspot/data_extractor.rb +50 -0
- data/lib/sunspot/dsl/adjustable.rb +47 -0
- data/lib/sunspot/dsl/field_group.rb +57 -0
- data/lib/sunspot/dsl/field_query.rb +327 -0
- data/lib/sunspot/dsl/fields.rb +103 -0
- data/lib/sunspot/dsl/fulltext.rb +243 -0
- data/lib/sunspot/dsl/function.rb +27 -0
- data/lib/sunspot/dsl/functional.rb +44 -0
- data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
- data/lib/sunspot/dsl/paginatable.rb +32 -0
- data/lib/sunspot/dsl/query_facet.rb +36 -0
- data/lib/sunspot/dsl/restriction.rb +25 -0
- data/lib/sunspot/dsl/restriction_with_near.rb +160 -0
- data/lib/sunspot/dsl/scope.rb +217 -0
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/dsl/standard_query.rb +123 -0
- data/lib/sunspot/dsl.rb +5 -0
- data/lib/sunspot/field.rb +193 -0
- data/lib/sunspot/field_factory.rb +129 -0
- data/lib/sunspot/indexer.rb +136 -0
- data/lib/sunspot/query/abstract_field_facet.rb +52 -0
- data/lib/sunspot/query/bbox.rb +15 -0
- data/lib/sunspot/query/boost_query.rb +24 -0
- data/lib/sunspot/query/common_query.rb +96 -0
- data/lib/sunspot/query/composite_fulltext.rb +36 -0
- data/lib/sunspot/query/connective.rb +206 -0
- data/lib/sunspot/query/date_field_facet.rb +14 -0
- data/lib/sunspot/query/dismax.rb +132 -0
- data/lib/sunspot/query/field_facet.rb +41 -0
- data/lib/sunspot/query/field_group.rb +36 -0
- data/lib/sunspot/query/filter.rb +38 -0
- data/lib/sunspot/query/function_query.rb +52 -0
- data/lib/sunspot/query/geo.rb +53 -0
- data/lib/sunspot/query/geofilt.rb +16 -0
- data/lib/sunspot/query/highlighting.rb +62 -0
- data/lib/sunspot/query/more_like_this.rb +61 -0
- data/lib/sunspot/query/more_like_this_query.rb +12 -0
- data/lib/sunspot/query/pagination.rb +42 -0
- data/lib/sunspot/query/query_facet.rb +16 -0
- data/lib/sunspot/query/restriction.rb +262 -0
- data/lib/sunspot/query/scope.rb +9 -0
- data/lib/sunspot/query/sort.rb +109 -0
- data/lib/sunspot/query/sort_composite.rb +34 -0
- data/lib/sunspot/query/standard_query.rb +16 -0
- data/lib/sunspot/query/text_field_boost.rb +17 -0
- data/lib/sunspot/query.rb +11 -0
- data/lib/sunspot/schema.rb +151 -0
- data/lib/sunspot/search/abstract_search.rb +281 -0
- data/lib/sunspot/search/date_facet.rb +35 -0
- data/lib/sunspot/search/facet_row.rb +27 -0
- data/lib/sunspot/search/field_facet.rb +88 -0
- data/lib/sunspot/search/field_group.rb +32 -0
- data/lib/sunspot/search/group.rb +50 -0
- data/lib/sunspot/search/highlight.rb +38 -0
- data/lib/sunspot/search/hit.rb +150 -0
- data/lib/sunspot/search/hit_enumerable.rb +72 -0
- data/lib/sunspot/search/more_like_this_search.rb +31 -0
- data/lib/sunspot/search/paginated_collection.rb +57 -0
- data/lib/sunspot/search/query_facet.rb +67 -0
- data/lib/sunspot/search/standard_search.rb +21 -0
- data/lib/sunspot/search.rb +9 -0
- data/lib/sunspot/session.rb +262 -0
- data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
- data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
- data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
- data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
- data/lib/sunspot/session_proxy/multicore_session_proxy.rb +67 -0
- data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
- data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
- data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
- data/lib/sunspot/session_proxy.rb +95 -0
- data/lib/sunspot/setup.rb +350 -0
- data/lib/sunspot/text_field_setup.rb +29 -0
- data/lib/sunspot/type.rb +393 -0
- data/lib/sunspot/util.rb +252 -0
- data/lib/sunspot/version.rb +3 -0
- data/lib/sunspot.rb +579 -0
- data/log/.gitignore +1 -0
- data/pkg/.gitignore +1 -0
- data/script/console +10 -0
- data/spec/api/adapters_spec.rb +33 -0
- data/spec/api/batcher_spec.rb +112 -0
- data/spec/api/binding_spec.rb +50 -0
- data/spec/api/class_set_spec.rb +24 -0
- data/spec/api/hit_enumerable_spec.rb +47 -0
- data/spec/api/indexer/attributes_spec.rb +149 -0
- data/spec/api/indexer/batch_spec.rb +72 -0
- data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
- data/spec/api/indexer/fixed_fields_spec.rb +57 -0
- data/spec/api/indexer/fulltext_spec.rb +43 -0
- data/spec/api/indexer/removal_spec.rb +53 -0
- data/spec/api/indexer/spec_helper.rb +1 -0
- data/spec/api/indexer_spec.rb +14 -0
- data/spec/api/query/advanced_manipulation_examples.rb +35 -0
- data/spec/api/query/connectives_examples.rb +189 -0
- data/spec/api/query/dsl_spec.rb +18 -0
- data/spec/api/query/dynamic_fields_examples.rb +165 -0
- data/spec/api/query/faceting_examples.rb +397 -0
- data/spec/api/query/fulltext_examples.rb +313 -0
- data/spec/api/query/function_spec.rb +79 -0
- data/spec/api/query/geo_examples.rb +68 -0
- data/spec/api/query/group_spec.rb +32 -0
- data/spec/api/query/highlighting_examples.rb +245 -0
- data/spec/api/query/more_like_this_spec.rb +140 -0
- data/spec/api/query/ordering_pagination_examples.rb +116 -0
- data/spec/api/query/scope_examples.rb +275 -0
- data/spec/api/query/spatial_examples.rb +27 -0
- data/spec/api/query/spec_helper.rb +1 -0
- data/spec/api/query/standard_spec.rb +29 -0
- data/spec/api/query/text_field_scoping_examples.rb +30 -0
- data/spec/api/query/types_spec.rb +20 -0
- data/spec/api/search/dynamic_fields_spec.rb +33 -0
- data/spec/api/search/faceting_spec.rb +360 -0
- data/spec/api/search/highlighting_spec.rb +69 -0
- data/spec/api/search/hits_spec.rb +131 -0
- data/spec/api/search/paginated_collection_spec.rb +36 -0
- data/spec/api/search/results_spec.rb +72 -0
- data/spec/api/search/search_spec.rb +23 -0
- data/spec/api/search/spec_helper.rb +1 -0
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
- data/spec/api/session_proxy/spec_helper.rb +9 -0
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
- data/spec/api/session_spec.rb +232 -0
- data/spec/api/spec_helper.rb +3 -0
- data/spec/api/sunspot_spec.rb +29 -0
- data/spec/ext.rb +11 -0
- data/spec/helpers/indexer_helper.rb +17 -0
- data/spec/helpers/integration_helper.rb +8 -0
- data/spec/helpers/mock_session_helper.rb +13 -0
- data/spec/helpers/query_helper.rb +26 -0
- data/spec/helpers/search_helper.rb +68 -0
- data/spec/integration/dynamic_fields_spec.rb +57 -0
- data/spec/integration/faceting_spec.rb +251 -0
- data/spec/integration/field_grouping_spec.rb +66 -0
- data/spec/integration/geospatial_spec.rb +85 -0
- data/spec/integration/highlighting_spec.rb +44 -0
- data/spec/integration/indexing_spec.rb +55 -0
- data/spec/integration/keyword_search_spec.rb +317 -0
- data/spec/integration/local_search_spec.rb +64 -0
- data/spec/integration/more_like_this_spec.rb +43 -0
- data/spec/integration/scoped_search_spec.rb +354 -0
- data/spec/integration/stored_fields_spec.rb +12 -0
- data/spec/integration/test_pagination.rb +43 -0
- data/spec/integration/unicode_spec.rb +15 -0
- data/spec/mocks/adapters.rb +32 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +21 -0
- data/spec/mocks/connection.rb +126 -0
- data/spec/mocks/mock_adapter.rb +30 -0
- data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
- data/spec/mocks/mock_record.rb +52 -0
- data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
- data/spec/mocks/photo.rb +11 -0
- data/spec/mocks/post.rb +86 -0
- data/spec/mocks/super_class.rb +2 -0
- data/spec/mocks/user.rb +13 -0
- data/spec/spec_helper.rb +40 -0
- data/sunspot.gemspec +42 -0
- data/tasks/rdoc.rake +27 -0
- data/tasks/schema.rake +19 -0
- data/tasks/todo.rake +4 -0
- metadata +261 -3
@@ -0,0 +1,354 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'scoped_search' do
|
4
|
+
def self.test_field_type(name, attribute, field, *values)
|
5
|
+
clazz =
|
6
|
+
if values.first.is_a?(Class)
|
7
|
+
values.shift
|
8
|
+
else
|
9
|
+
Post
|
10
|
+
end
|
11
|
+
raise(ArgumentError, 'Please supply five values') unless values.length == 5
|
12
|
+
|
13
|
+
context "with field of type #{name}" do
|
14
|
+
before :all do
|
15
|
+
Sunspot.remove_all
|
16
|
+
@objects = values.map do |value|
|
17
|
+
object = clazz.new(attribute => value)
|
18
|
+
Sunspot.index(object)
|
19
|
+
object
|
20
|
+
end
|
21
|
+
Sunspot.commit
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should filter by exact match' do
|
25
|
+
Sunspot.search(clazz) { with(field, values[2]) }.results.should == [@objects[2]]
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should reject by inexact match' do
|
29
|
+
results = Sunspot.search(clazz) { without(field, values[2]) }.results
|
30
|
+
[0, 1, 3, 4].each { |i| results.should include(@objects[i]) }
|
31
|
+
results.should_not include(@objects[2])
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should filter by less than' do
|
35
|
+
results = Sunspot.search(clazz) { with(field).less_than values[2] }.results
|
36
|
+
(0..2).each { |i| results.should include(@objects[i]) }
|
37
|
+
(3..4).each { |i| results.should_not include(@objects[i]) }
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should reject by less than' do
|
41
|
+
results = Sunspot.search(clazz) { without(field).less_than values[2] }.results
|
42
|
+
(0..2).each { |i| results.should_not include(@objects[i]) }
|
43
|
+
(3..4).each { |i| results.should include(@objects[i]) }
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should filter by greater than' do
|
47
|
+
results = Sunspot.search(clazz) { with(field).greater_than values[2] }.results
|
48
|
+
(2..4).each { |i| results.should include(@objects[i]) }
|
49
|
+
(0..1).each { |i| results.should_not include(@objects[i]) }
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should reject by greater than' do
|
53
|
+
results = Sunspot.search(clazz) { without(field).greater_than values[2] }.results
|
54
|
+
(2..4).each { |i| results.should_not include(@objects[i]) }
|
55
|
+
(0..1).each { |i| results.should include(@objects[i]) }
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should filter by between' do
|
59
|
+
results = Sunspot.search(clazz) { with(field).between(values[1]..values[3]) }.results
|
60
|
+
(1..3).each { |i| results.should include(@objects[i]) }
|
61
|
+
[0, 4].each { |i| results.should_not include(@objects[i]) }
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should reject by between' do
|
65
|
+
results = Sunspot.search(clazz) { without(field).between(values[1]..values[3]) }.results
|
66
|
+
(1..3).each { |i| results.should_not include(@objects[i]) }
|
67
|
+
[0, 4].each { |i| results.should include(@objects[i]) }
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should filter by any of' do
|
71
|
+
results = Sunspot.search(clazz) { with(field).any_of(values.values_at(1, 3)) }.results
|
72
|
+
[1, 3].each { |i| results.should include(@objects[i]) }
|
73
|
+
[0, 2, 4].each { |i| results.should_not include(@objects[i]) }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should reject by any of' do
|
77
|
+
results = Sunspot.search(clazz) { without(field).any_of(values.values_at(1, 3)) }.results
|
78
|
+
[1, 3].each { |i| results.should_not include(@objects[i]) }
|
79
|
+
[0, 2, 4].each { |i| results.should include(@objects[i]) }
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should order by field ascending' do
|
83
|
+
results = Sunspot.search(clazz) { order_by field, :asc }.results
|
84
|
+
results.should == @objects
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should order by field descending' do
|
88
|
+
results = Sunspot.search(clazz) { order_by field, :desc }.results
|
89
|
+
results.should == @objects.reverse
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
test_field_type 'String', :title, :title, 'apple pie', 'banana split', 'cherry tart', 'date pastry', 'eggplant a la mode'
|
95
|
+
test_field_type 'Integer', :blog_id, :blog_id, -2, 0, 3, 12, 20
|
96
|
+
test_field_type 'Long', :hash, :hash, Namespaced::Comment, 2**29, 2**30, 2**31, 2**32, 2**33
|
97
|
+
test_field_type 'Float', :ratings_average, :average_rating, -2.5, 0.0, 3.2, 3.5, 16.0
|
98
|
+
test_field_type 'Double', :average_rating, :average_rating, Namespaced::Comment, -2.5, 0.0, 3.2, 3.5, 16.0
|
99
|
+
test_field_type 'Time', :published_at, :published_at, *(['1970-01-01 00:00:00 UTC', '1983-07-08 04:00:00 UTC', '1983-07-08 02:00:00 -0500',
|
100
|
+
'2005-11-05 10:00:00 UTC', Time.now.to_s].map { |t| Time.parse(t) })
|
101
|
+
test_field_type 'Trie Integer', :size, :size, Photo, -2, 0, 3, 12, 20
|
102
|
+
test_field_type 'Trie Float', :average_rating, :average_rating, Photo, -2.5, 0.0, 3.2, 3.5, 16.0
|
103
|
+
test_field_type 'Trie Time', :created_at, :created_at, Photo, *(['1970-01-01 00:00:00 UTC', '1983-07-08 04:00:00 UTC', '1983-07-08 02:00:00 -0500',
|
104
|
+
'2005-11-05 10:00:00 UTC', Time.now.to_s].map { |t| Time.parse(t) })
|
105
|
+
|
106
|
+
describe 'Boolean field type' do
|
107
|
+
before :all do
|
108
|
+
Sunspot.remove_all
|
109
|
+
@posts = [Post.new(:featured => true), Post.new(:featured => false), Post.new]
|
110
|
+
Sunspot.index!(@posts)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should filter by exact match for true' do
|
114
|
+
Sunspot.search(Post) { with(:featured, true) }.results.should == [@posts[0]]
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should filter for exact match for false' do
|
118
|
+
Sunspot.search(Post) { with(:featured, false) }.results.should == [@posts[1]]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe 'reserved words' do
|
123
|
+
%w(AND OR NOT TO).each do |word|
|
124
|
+
it "should successfully search for #{word.inspect}" do
|
125
|
+
Sunspot.index!(post = Post.new(:title => word))
|
126
|
+
Sunspot.search(Post) { with(:title, word) }.results.should == [post]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'passing nil value to equal' do
|
132
|
+
before :all do
|
133
|
+
Sunspot.remove_all
|
134
|
+
@posts = [Post.new(:title => 'apple'), Post.new]
|
135
|
+
Sunspot.index!(@posts)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should filter results without value for field' do
|
139
|
+
Sunspot.search(Post) { with(:title, nil) }.results.should == [@posts[1]]
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should exclude results without value for field' do
|
143
|
+
Sunspot.search(Post) { without(:title, nil) }.results.should == [@posts[0]]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'prefix searching' do
|
148
|
+
before :each do
|
149
|
+
Sunspot.remove_all
|
150
|
+
@posts = ['test', 'test post', 'some test', 'bogus'].map do |title|
|
151
|
+
Post.new(:title => title)
|
152
|
+
end
|
153
|
+
Sunspot.index!(@posts)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should return results whose prefix matches' do
|
157
|
+
Sunspot.search(Post) { with(:title).starting_with('test') }.results.should == @posts[0..1]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe 'inclusion by identity' do
|
162
|
+
before do
|
163
|
+
@posts = (1..5).map do |i|
|
164
|
+
post = Post.new
|
165
|
+
Sunspot.index(post)
|
166
|
+
post
|
167
|
+
end
|
168
|
+
Sunspot.commit
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should only return included object' do
|
172
|
+
included_post = @posts.shift
|
173
|
+
Sunspot.search(Post) { with(included_post) }.results.should include(included_post)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should not return objects not included' do
|
177
|
+
included_post = @posts.shift
|
178
|
+
for excluded_post in @posts
|
179
|
+
Sunspot.search(Post) { with(included_post) }.results.should_not include(excluded_post)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should return included objects' do
|
184
|
+
included_posts = [@posts.shift, @posts.shift]
|
185
|
+
for included_post in included_posts
|
186
|
+
Sunspot.search(Post) { with(included_posts) }.results.should include(included_post)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe 'exclusion by identity' do
|
192
|
+
before do
|
193
|
+
@posts = (1..5).map do |i|
|
194
|
+
post = Post.new
|
195
|
+
Sunspot.index(post)
|
196
|
+
post
|
197
|
+
end
|
198
|
+
Sunspot.commit
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should not return excluded object' do
|
202
|
+
excluded_post = @posts.shift
|
203
|
+
Sunspot.search(Post) { without(excluded_post) }.results.should_not include(excluded_post)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should return objects not excluded' do
|
207
|
+
excluded_post = @posts.shift
|
208
|
+
for included_post in @posts
|
209
|
+
Sunspot.search(Post) { without(excluded_post) }.results.should include(included_post)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'should not return excluded objects' do
|
214
|
+
excluded_posts = [@posts.shift, @posts.shift]
|
215
|
+
for excluded_post in excluded_posts
|
216
|
+
Sunspot.search(Post) { without(excluded_posts) }.results.should_not include(excluded_post)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe 'connectives' do
|
222
|
+
before :each do
|
223
|
+
Sunspot.remove_all
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should return results that match any restriction in a disjunction' do
|
227
|
+
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
228
|
+
Sunspot.index!(posts)
|
229
|
+
Sunspot.search(Post) do
|
230
|
+
any_of do
|
231
|
+
with(:blog_id, 1)
|
232
|
+
with(:blog_id, 2)
|
233
|
+
end
|
234
|
+
end.results.should == posts[0..1]
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'should return results that match a nested conjunction in a disjunction' do
|
238
|
+
posts = [
|
239
|
+
Post.new(:title => 'No', :blog_id => 1),
|
240
|
+
Post.new(:title => 'Yes', :blog_id => 2),
|
241
|
+
Post.new(:title => 'Yes', :blog_id => 3),
|
242
|
+
Post.new(:title => 'No', :blog_id => 2)
|
243
|
+
]
|
244
|
+
Sunspot.index!(posts)
|
245
|
+
Sunspot.search(Post) do
|
246
|
+
any_of do
|
247
|
+
with(:blog_id, 1)
|
248
|
+
all_of do
|
249
|
+
with(:blog_id, 2)
|
250
|
+
with(:title, 'Yes')
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end.results.should == posts[0..1]
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should return results that match a conjunction with a negated restriction' do
|
257
|
+
posts = [
|
258
|
+
Post.new(:title => 'No', :blog_id => 1),
|
259
|
+
Post.new(:title => 'Yes', :blog_id => 2),
|
260
|
+
Post.new(:title => 'No', :blog_id => 2)
|
261
|
+
]
|
262
|
+
Sunspot.index!(posts)
|
263
|
+
search = Sunspot.search(Post) do
|
264
|
+
any_of do
|
265
|
+
with(:blog_id, 1)
|
266
|
+
without(:title, 'No')
|
267
|
+
end
|
268
|
+
end
|
269
|
+
search.results.should == posts[0..1]
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should return results that match a conjunction with a disjunction with a conjunction with a negated restriction' do
|
273
|
+
posts = [
|
274
|
+
Post.new(:title => 'Yes', :ratings_average => 2.0),
|
275
|
+
Post.new(:blog_id => 1, :category_ids => [4], :ratings_average => 2.0),
|
276
|
+
Post.new(:blog_id => 1),
|
277
|
+
Post.new(:blog_id => 2),
|
278
|
+
Post.new(:blog_id => 1, :ratings_average => 2.0)
|
279
|
+
]
|
280
|
+
Sunspot.index!(posts)
|
281
|
+
search = Sunspot.search(Post) do
|
282
|
+
any_of do
|
283
|
+
with(:title, 'Yes')
|
284
|
+
all_of do
|
285
|
+
with(:blog_id, 1)
|
286
|
+
any_of do
|
287
|
+
with(:category_ids, 4)
|
288
|
+
without(:average_rating, 2.0)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
search.results.should == posts[0..2]
|
294
|
+
end
|
295
|
+
|
296
|
+
it 'should return results that match a disjunction with a negated restriction and a nested disjunction in a conjunction with a negated restriction' do
|
297
|
+
posts = [
|
298
|
+
Post.new,
|
299
|
+
Post.new(:title => 'Yes', :blog_id => 1, :category_ids => [4], :ratings_average => 2.0),
|
300
|
+
Post.new(:title => 'Yes', :blog_id => 1),
|
301
|
+
Post.new(:title => 'Yes'),
|
302
|
+
Post.new(:title => 'Yes', :category_ids => [4], :ratings_average => 2.0),
|
303
|
+
Post.new(:title => 'Yes', :blog_id => 1, :ratings_average => 2.0)
|
304
|
+
]
|
305
|
+
Sunspot.index!(posts)
|
306
|
+
search = Sunspot.search(Post) do
|
307
|
+
any_of do
|
308
|
+
without(:title, 'Yes')
|
309
|
+
all_of do
|
310
|
+
with(:blog_id, 1)
|
311
|
+
any_of do
|
312
|
+
with(:category_ids, 4)
|
313
|
+
without(:average_rating, 2.0)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
search.results.should == posts[0..2]
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe 'multiple column ordering' do
|
323
|
+
before do
|
324
|
+
Sunspot.remove_all
|
325
|
+
@posts = [
|
326
|
+
Post.new(:ratings_average => 2, :title => 'banana'),
|
327
|
+
Post.new(:ratings_average => 2, :title => 'eggplant'),
|
328
|
+
Post.new(:ratings_average => 1, :title => 'apple')
|
329
|
+
].each { |post| Sunspot.index(post) }
|
330
|
+
Sunspot.commit
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'should order with precedence given' do
|
334
|
+
search = Sunspot.search(Post) do
|
335
|
+
order_by :average_rating, :desc
|
336
|
+
order_by :sort_title, :asc
|
337
|
+
end
|
338
|
+
search.results.should == @posts
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe 'ordering by random' do
|
343
|
+
it 'should order randomly (run this test again if it fails)' do
|
344
|
+
Sunspot.remove_all
|
345
|
+
Sunspot.index!(Array.new(100) { Post.new })
|
346
|
+
result_sets = Array.new(2) do
|
347
|
+
Sunspot.search(Post) { order_by_random }.results.map do |result|
|
348
|
+
result.id
|
349
|
+
end
|
350
|
+
end
|
351
|
+
result_sets[0].should_not == result_sets[1]
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'stored fields' do
|
4
|
+
before :all do
|
5
|
+
Sunspot.remove_all
|
6
|
+
Sunspot.index!(Post.new(:title => 'A Title'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should return stored fields' do
|
10
|
+
Sunspot.search(Post).hits.first.stored(:title).should == 'A Title'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'pagination' do
|
4
|
+
before :all do
|
5
|
+
Sunspot.remove_all
|
6
|
+
@posts = (0..19).map do |i|
|
7
|
+
Post.new(:blog_id => i)
|
8
|
+
end
|
9
|
+
Sunspot.index!(*@posts)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should return all by default' do
|
13
|
+
results = Sunspot.search(Post) { order_by :blog_id }.results
|
14
|
+
results.should == @posts
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return first page of 10' do
|
18
|
+
results = Sunspot.search(Post) do
|
19
|
+
order_by :blog_id
|
20
|
+
paginate :page => 1, :per_page => 10
|
21
|
+
end.results
|
22
|
+
results.should == @posts[0,10]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return second page of 10' do
|
26
|
+
results = Sunspot.search(Post) do
|
27
|
+
order_by :blog_id
|
28
|
+
paginate :page => 2, :per_page => 10
|
29
|
+
end.results
|
30
|
+
results.should == @posts[10,10]
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should return pages with offsets' do
|
34
|
+
results = Sunspot.search(Post) do
|
35
|
+
order_by :blog_id
|
36
|
+
paginate :page => 2, :per_page => 5, :offset => 3
|
37
|
+
end.results
|
38
|
+
|
39
|
+
# page 1 is 3, 4, 5, 6, 7
|
40
|
+
# page 2 is 8, 9, 10, 11, 12
|
41
|
+
results.should == @posts[8,5]
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
describe "unicode characters" do
|
5
|
+
before :each do
|
6
|
+
Sunspot.remove_all
|
7
|
+
|
8
|
+
@post = Post.new(:title => "Híghgrøøvé")
|
9
|
+
Sunspot.index!(@post)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "correctly retrieves the string as UTF-8" do
|
13
|
+
Sunspot.search(Post).hits.first.stored(:title).should == "Híghgrøøvé"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class AbstractModel
|
2
|
+
end
|
3
|
+
|
4
|
+
class Model < AbstractModel
|
5
|
+
end
|
6
|
+
|
7
|
+
class AbstractModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
8
|
+
end
|
9
|
+
|
10
|
+
class AbstractModelDataAccessor < Sunspot::Adapters::DataAccessor
|
11
|
+
end
|
12
|
+
|
13
|
+
Sunspot::Adapters::InstanceAdapter.register(AbstractModelInstanceAdapter, AbstractModel)
|
14
|
+
Sunspot::Adapters::DataAccessor.register(AbstractModelDataAccessor, AbstractModel)
|
15
|
+
|
16
|
+
|
17
|
+
module MixInModel
|
18
|
+
end
|
19
|
+
|
20
|
+
class MixModel
|
21
|
+
include MixInModel
|
22
|
+
end
|
23
|
+
|
24
|
+
class MixInModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
25
|
+
end
|
26
|
+
|
27
|
+
class MixInModelDataAccessor < Sunspot::Adapters::DataAccessor
|
28
|
+
end
|
29
|
+
|
30
|
+
Sunspot::Adapters::InstanceAdapter.register(MixInModelInstanceAdapter, MixInModel)
|
31
|
+
Sunspot::Adapters::DataAccessor.register(MixInModelDataAccessor, MixInModel)
|
32
|
+
|
data/spec/mocks/blog.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Namespaced
|
2
|
+
class Comment < MockRecord
|
3
|
+
attr_reader :id
|
4
|
+
attr_accessor :author_name, :published_at, :body, :average_rating, :boost,
|
5
|
+
:hash
|
6
|
+
|
7
|
+
def custom_float
|
8
|
+
@custom_float ||= {}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Sunspot.setup(Namespaced::Comment) do
|
14
|
+
text :body, :author_name
|
15
|
+
string :author_name
|
16
|
+
time :published_at, :trie => true
|
17
|
+
long :hash
|
18
|
+
double :average_rating
|
19
|
+
dynamic_float :custom_float, :multiple => true
|
20
|
+
boost :boost
|
21
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Mock
|
2
|
+
class ConnectionFactory
|
3
|
+
def connect(opts)
|
4
|
+
if @instance
|
5
|
+
raise('Factory can only create an instance once!')
|
6
|
+
else
|
7
|
+
@instance = Connection.new(opts)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def new(url = nil)
|
12
|
+
if @instance
|
13
|
+
raise('Factory can only create an instance once!')
|
14
|
+
else
|
15
|
+
@instance = Connection.new(url)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def instance
|
20
|
+
@instance ||= Connection.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Connection
|
25
|
+
attr_reader :adds, :commits, :optims, :searches, :message, :opts, :deletes_by_query
|
26
|
+
attr_accessor :response
|
27
|
+
attr_writer :expected_handler
|
28
|
+
undef_method :select # annoyingly defined on Object
|
29
|
+
|
30
|
+
def initialize(opts = {})
|
31
|
+
@opts = opts
|
32
|
+
@message = OpenStruct.new
|
33
|
+
@adds, @deletes, @deletes_by_query, @commits, @optims, @searches = Array.new(6) { [] }
|
34
|
+
@expected_handler = :select
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(documents)
|
38
|
+
@adds << Array(documents)
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_by_id(ids)
|
42
|
+
@deletes << Array(ids)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_by_query(query)
|
46
|
+
@deletes_by_query << query
|
47
|
+
end
|
48
|
+
|
49
|
+
def commit
|
50
|
+
@commits << Time.now
|
51
|
+
end
|
52
|
+
|
53
|
+
def optimize
|
54
|
+
@optims << Time.now
|
55
|
+
end
|
56
|
+
|
57
|
+
def post(path, params)
|
58
|
+
unless path == "#{@expected_handler}"
|
59
|
+
raise ArgumentError, "Expected request to #{@expected_handler} request handler"
|
60
|
+
end
|
61
|
+
@searches << @last_search = params[:data]
|
62
|
+
@response || {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def method_missing(method, *args, &block)
|
66
|
+
get("#{method}", *args)
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_add_with?(*documents)
|
70
|
+
@adds.any? do |add|
|
71
|
+
documents.all? do |document|
|
72
|
+
add.any? do |added|
|
73
|
+
if document.is_a?(Hash)
|
74
|
+
document.all? do |field, value|
|
75
|
+
added.fields_by_name(field).map do |field|
|
76
|
+
field.value.to_s
|
77
|
+
end == Array(value).map { |v| v.to_s }
|
78
|
+
end
|
79
|
+
else
|
80
|
+
!added.fields_by_name(document).empty?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def has_delete?(*ids)
|
88
|
+
@deletes.any? do |delete|
|
89
|
+
delete & ids == ids
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def has_delete_by_query?(query)
|
94
|
+
@deletes_by_query.include?(query)
|
95
|
+
end
|
96
|
+
|
97
|
+
def has_last_search_with?(params)
|
98
|
+
with?(@last_search, params) if @last_search
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_last_search_including?(key, *values)
|
102
|
+
return unless @last_search
|
103
|
+
if @last_search.has_key?(key)
|
104
|
+
if @last_search[key].is_a?(Array)
|
105
|
+
(@last_search[key] & values).length == values.length
|
106
|
+
elsif values.length == 1
|
107
|
+
@last_search[key] == values.first
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def with?(request, params)
|
115
|
+
if params.respond_to?(:all?)
|
116
|
+
params.all? do |key, value|
|
117
|
+
if request.has_key?(key)
|
118
|
+
request[key] == value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
else
|
122
|
+
request.has_key?(params)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'post')
|
2
|
+
|
3
|
+
module MockAdapter
|
4
|
+
class InstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
5
|
+
def id
|
6
|
+
@instance.id
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class DataAccessor < Sunspot::Adapters::DataAccessor
|
11
|
+
def load(id)
|
12
|
+
@clazz.get(id.to_i)
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_all(ids)
|
16
|
+
all = @clazz.get_all(ids.map { |id| id.to_i })
|
17
|
+
if @custom_title
|
18
|
+
all.each { |item| item.title = @custom_title }
|
19
|
+
end
|
20
|
+
all
|
21
|
+
end
|
22
|
+
|
23
|
+
def custom_title=(custom_title)
|
24
|
+
@custom_title = custom_title
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, MockRecord)
|
30
|
+
Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, MockRecord)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class MockClassShardingSessionProxy < Sunspot::SessionProxy::ClassShardingSessionProxy
|
2
|
+
attr_reader :post_session, :photo_session
|
3
|
+
|
4
|
+
def initialize(search_session)
|
5
|
+
super
|
6
|
+
@post_session, @photo_session = Sunspot::Session.new, Sunspot::Session.new
|
7
|
+
@post_session.config.solr.url = 'http://posts.solr.local/solr'
|
8
|
+
@photo_session.config.solr.url = 'http://photos.solr.local/solr'
|
9
|
+
@sessions = {
|
10
|
+
Post => @post_session,
|
11
|
+
Photo => @photo_session
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def session_for_class(clazz)
|
16
|
+
@sessions[clazz]
|
17
|
+
end
|
18
|
+
|
19
|
+
def all_sessions
|
20
|
+
@sessions.values.sort do |lsession, rsession|
|
21
|
+
lsession.config.solr.url <=> rsession.config.solr.url
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|