outoftime-sunspot 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -6
- data/README.rdoc +45 -13
- data/Rakefile +5 -21
- data/VERSION.yml +4 -0
- data/bin/sunspot-solr +39 -0
- data/lib/sunspot/builder.rb +78 -0
- data/lib/sunspot/dsl/fields.rb +39 -0
- data/lib/sunspot/dsl/query.rb +32 -0
- data/lib/sunspot/dsl/scope.rb +35 -0
- data/lib/sunspot/dsl.rb +3 -0
- data/lib/sunspot/query.rb +9 -20
- data/lib/sunspot/search.rb +8 -25
- data/lib/sunspot.rb +2 -3
- data/solr/etc/jetty.xml +10 -4
- data/solr/solr/conf/{admin-extra.html → elevate.xml} +18 -13
- data/solr/solr/conf/solrconfig.xml +369 -67
- data/solr/webapps/solr.war +0 -0
- data/spec/api/build_search_spec.rb +195 -0
- data/spec/api/indexer_spec.rb +112 -0
- data/spec/api/search_retrieval_spec.rb +59 -0
- data/spec/api/session_spec.rb +44 -0
- data/spec/api/spec_helper.rb +1 -0
- data/spec/api/standard_search_builder_spec.rb +76 -0
- data/{test → spec}/custom_expectation.rb +0 -0
- data/{test/integration/test_field_types.rb → spec/integration/field_types_spec.rb} +9 -9
- data/{test/integration/test_keyword_search.rb → spec/integration/keyword_search_spec.rb} +5 -5
- data/spec/integration/spec_helper.rb +1 -0
- data/{test → spec}/integration/test_pagination.rb +5 -5
- data/{test → spec}/mocks/base_class.rb +0 -0
- data/{test → spec}/mocks/comment.rb +0 -0
- data/{test → spec}/mocks/mock_adapter.rb +0 -0
- data/{test → spec}/mocks/post.rb +0 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +6 -12
- data/tasks/gemspec.rake +18 -0
- data/tasks/rcov.rake +27 -5
- data/tasks/spec.rake +21 -0
- metadata +90 -125
- data/Manifest.txt +0 -104
- data/PostInstall.txt +0 -7
- data/config/hoe.rb +0 -74
- data/config/requirements.rb +0 -15
- data/lib/sunspot/conditions.rb +0 -50
- data/lib/sunspot/conditions_builder.rb +0 -37
- data/lib/sunspot/field_builder.rb +0 -37
- data/lib/sunspot/query_builder.rb +0 -30
- data/lib/sunspot/scope_builder.rb +0 -33
- data/lib/sunspot/version.rb +0 -10
- data/setup.rb +0 -1585
- data/solr/README.txt +0 -36
- data/solr/exampledocs/books.csv +0 -11
- data/solr/exampledocs/hd.xml +0 -46
- data/solr/exampledocs/ipod_other.xml +0 -50
- data/solr/exampledocs/ipod_video.xml +0 -35
- data/solr/exampledocs/mem.xml +0 -58
- data/solr/exampledocs/monitor.xml +0 -31
- data/solr/exampledocs/monitor2.xml +0 -30
- data/solr/exampledocs/mp500.xml +0 -39
- data/solr/exampledocs/post.jar +0 -0
- data/solr/exampledocs/post.sh +0 -28
- data/solr/exampledocs/sd500.xml +0 -33
- data/solr/exampledocs/solr.xml +0 -38
- data/solr/exampledocs/spellchecker.xml +0 -58
- data/solr/exampledocs/utf8-example.xml +0 -42
- data/solr/exampledocs/vidcard.xml +0 -52
- data/solr/solr/README.txt +0 -52
- data/solr/solr/bin/abc +0 -176
- data/solr/solr/bin/abo +0 -176
- data/solr/solr/bin/backup +0 -108
- data/solr/solr/bin/backupcleaner +0 -142
- data/solr/solr/bin/commit +0 -128
- data/solr/solr/bin/optimize +0 -129
- data/solr/solr/bin/readercycle +0 -129
- data/solr/solr/bin/rsyncd-disable +0 -77
- data/solr/solr/bin/rsyncd-enable +0 -76
- data/solr/solr/bin/rsyncd-start +0 -145
- data/solr/solr/bin/rsyncd-stop +0 -105
- data/solr/solr/bin/scripts-util +0 -83
- data/solr/solr/bin/snapcleaner +0 -148
- data/solr/solr/bin/snapinstaller +0 -168
- data/solr/solr/bin/snappuller +0 -248
- data/solr/solr/bin/snappuller-disable +0 -77
- data/solr/solr/bin/snappuller-enable +0 -77
- data/solr/solr/bin/snapshooter +0 -109
- data/solr/solr/conf/scripts.conf +0 -24
- data/tasks/deployment.rake +0 -34
- data/tasks/environment.rake +0 -7
- data/tasks/solr.rake +0 -12
- data/tasks/website.rake +0 -17
- data/test/api/test_build_search.rb +0 -216
- data/test/api/test_helper.rb +0 -4
- data/test/api/test_indexer.rb +0 -110
- data/test/api/test_retrieve_search.rb +0 -114
- data/test/api/test_session.rb +0 -46
- data/test/integration/test_helper.rb +0 -1
@@ -0,0 +1,195 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'Search' do
|
4
|
+
it 'should search by keywords' do
|
5
|
+
connection.should_receive(:query).with('(keyword search) AND (type:Post)', hash_including).twice
|
6
|
+
session.search Post, :keywords => 'keyword search'
|
7
|
+
session.search Post do
|
8
|
+
keywords 'keyword search'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should scope by exact match with a string' do
|
13
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['title_s:My\ Pet\ Post'])).twice
|
14
|
+
session.search Post, :conditions => { :title => 'My Pet Post' }
|
15
|
+
session.search Post do
|
16
|
+
with.title 'My Pet Post'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should ignore nonexistant fields in hash scope' do
|
21
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => []))
|
22
|
+
session.search Post, :conditions => { :bogus => 'Field' }
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should raise an ArgumentError for nonexistant fields in block scope' do
|
26
|
+
lambda do
|
27
|
+
session.search Post do
|
28
|
+
with.bogus 'Field'
|
29
|
+
end
|
30
|
+
end.should raise_error(ArgumentError)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should scope by exact match with time' do
|
34
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'])).twice
|
35
|
+
time = Time.parse('1983-07-08 05:00:00 -0400')
|
36
|
+
session.search Post, :conditions => { :published_at => time }
|
37
|
+
session.search Post do
|
38
|
+
with.published_at time
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should scope by less than match with float' do
|
43
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['average_rating_f:[* TO 3\.0]']))
|
44
|
+
session.search Post do
|
45
|
+
with.average_rating.less_than 3.0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should scope by greater than match with float' do
|
50
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['average_rating_f:[3\.0 TO *]']))
|
51
|
+
session.search Post do
|
52
|
+
with.average_rating.greater_than 3.0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should scope by between match with float' do
|
57
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['average_rating_f:[2\.0 TO 4\.0]']))
|
58
|
+
session.search Post do
|
59
|
+
with.average_rating.between 2.0..4.0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should scope by any match with integer' do
|
64
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['category_ids_im:(2 OR 7 OR 12)'])).twice
|
65
|
+
session.search Post, :conditions => { :category_ids => [2, 7, 12] }
|
66
|
+
session.search Post do
|
67
|
+
with.category_ids.any_of [2, 7, 12]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should scope by all match with integer' do
|
72
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:filter_queries => ['category_ids_im:(2 AND 7 AND 12)']))
|
73
|
+
session.search Post do
|
74
|
+
with.category_ids.all_of [2, 7, 12]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should paginate using default per_page when page not provided' do
|
79
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:rows => 30))
|
80
|
+
session.search Post
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should paginate using default per_page when page provided' do
|
84
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:rows => 30, :start => 30)).twice
|
85
|
+
session.search Post, :page => 2
|
86
|
+
session.search Post do
|
87
|
+
paginate :page => 2
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should paginate using provided per_page' do
|
92
|
+
connection.should_receive(:query).with('(type:Post)', :filter_queries => [], :rows => 15, :start => 45).twice
|
93
|
+
session.search Post, :page => 4, :per_page => 15
|
94
|
+
session.search Post do
|
95
|
+
paginate :page => 4, :per_page => 15
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should order' do
|
100
|
+
connection.should_receive(:query).with('(type:Post)', hash_including(:sort => [{ :average_rating_f => :descending }])).twice
|
101
|
+
session.search Post, :order => 'average_rating desc'
|
102
|
+
session.search Post do
|
103
|
+
order_by :average_rating, :desc
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should build search for multiple types' do
|
108
|
+
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_including)
|
109
|
+
session.search(Post, Comment)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should allow search on fields common to all types' do
|
113
|
+
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_including(:filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'])).twice
|
114
|
+
time = Time.parse('1983-07-08 05:00:00 -0400')
|
115
|
+
session.search Post, Comment, :conditions => { :published_at => time }
|
116
|
+
session.search Post, Comment do
|
117
|
+
with.published_at time
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should raise exception if search scoped to field not common to all types' do
|
122
|
+
lambda do
|
123
|
+
session.search Post, Comment do
|
124
|
+
with.blog_id 1
|
125
|
+
end
|
126
|
+
end.should raise_error(ArgumentError)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should raise exception if search scoped to field configured differently between types' do
|
130
|
+
lambda do
|
131
|
+
session.search Post, Comment do
|
132
|
+
with.average_rating 2.2 # this is a float in Post but an integer in Comment
|
133
|
+
end
|
134
|
+
end.should raise_error(ArgumentError)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should ignore condition if field is not common to all types' do
|
138
|
+
connection.should_receive(:query).with('(type:(Post OR Comment))', hash_including(:filter_queries => []))
|
139
|
+
session.search Post, Comment, :conditions => { :blog_id => 1 }
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should raise ArgumentError if bogus field scoped' do
|
143
|
+
lambda do
|
144
|
+
session.search Post do
|
145
|
+
with.bogus.equal_to :field
|
146
|
+
end
|
147
|
+
end.should raise_error(ArgumentError)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should raise NoMethodError if bogus operator referenced' do
|
151
|
+
lambda do
|
152
|
+
session.search Post do
|
153
|
+
with.category_ids.resembling :bogus_condition
|
154
|
+
end
|
155
|
+
end.should raise_error(NoMethodError)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should raise ArgumentError if no :page argument given to paginate' do
|
159
|
+
lambda do
|
160
|
+
session.search Post do
|
161
|
+
paginate
|
162
|
+
end
|
163
|
+
end.should raise_error(ArgumentError)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should raise ArgumentError if bogus argument given to paginate' do
|
167
|
+
lambda do
|
168
|
+
session.search Post do
|
169
|
+
paginate :page => 4, :ugly => :puppy
|
170
|
+
end
|
171
|
+
end.should raise_error(ArgumentError)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should raise NoMethodError if more than one argument passed to scope method' do # or should it?
|
175
|
+
lambda do
|
176
|
+
session.search Post do
|
177
|
+
with.category_ids 4, 5
|
178
|
+
end
|
179
|
+
end.should raise_error(NoMethodError)
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def config
|
185
|
+
@config ||= Sunspot::Configuration.build
|
186
|
+
end
|
187
|
+
|
188
|
+
def connection
|
189
|
+
@connection ||= mock('connection')
|
190
|
+
end
|
191
|
+
|
192
|
+
def session
|
193
|
+
@session ||= Sunspot::Session.new(config, connection)
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'indexer' do
|
4
|
+
describe 'when indexing an object' do
|
5
|
+
it 'should index id and type' do
|
6
|
+
connection.should_receive(:add).with(hash_including(:id => "Post #{post.id}", :type => ['Post', 'BaseClass']))
|
7
|
+
session.index post
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should index text' do
|
11
|
+
post :title => 'A Title', :body => 'A Post'
|
12
|
+
connection.should_receive(:add).with(hash_including(:title_text => 'A Title', :body_text => 'A Post'))
|
13
|
+
session.index post
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should correctly index a string attribute field' do
|
17
|
+
post :title => 'A Title'
|
18
|
+
connection.should_receive(:add).with(hash_including(:title_s => 'A Title'))
|
19
|
+
session.index post
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should correctly index an integer attribute field' do
|
23
|
+
post :blog_id => 4
|
24
|
+
connection.should_receive(:add).with(hash_including(:blog_id_i => '4'))
|
25
|
+
session.index post
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should correctly index a float attribute field' do
|
29
|
+
post :average_rating => 2.23
|
30
|
+
connection.should_receive(:add).with(hash_including(:average_rating_f => '2.23'))
|
31
|
+
session.index post
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should allow indexing by a multiple-value field' do
|
35
|
+
post :category_ids => [3, 14]
|
36
|
+
connection.should_receive(:add).with(hash_including(:category_ids_im => ['3', '14']))
|
37
|
+
session.index post
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should correctly index a time field' do
|
41
|
+
post :published_at => Time.parse('1983-07-08 05:00:00 -0400')
|
42
|
+
connection.should_receive(:add).with(hash_including(:published_at_d => '1983-07-08T09:00:00Z'))
|
43
|
+
session.index post
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should correctly index a virtual field' do
|
47
|
+
post :title => 'The Blog Post'
|
48
|
+
connection.should_receive(:add).with(hash_including(:sort_title_s => 'blog post'))
|
49
|
+
session.index post
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should correctly index a field that is defined on a superclass' do
|
53
|
+
Sunspot.setup(BaseClass) { string :author_name }
|
54
|
+
post :author_name => 'Mat Brown'
|
55
|
+
connection.should_receive(:add).with(hash_including(:author_name_s => 'Mat Brown'))
|
56
|
+
session.index post
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should remove an object from the index' do
|
60
|
+
connection.should_receive(:delete).with("Post #{post.id}")
|
61
|
+
session.remove(post)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should be able to remove everything from the index' do
|
65
|
+
connection.should_receive(:delete_by_query).with("type:[* TO *]")
|
66
|
+
session.remove_all
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should be able to remove everything of a given class from the index' do
|
70
|
+
connection.should_receive(:delete_by_query).with("type:Post")
|
71
|
+
session.remove_all(Post)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should throw a NoMethodError only if a nonexistent type is defined' do
|
76
|
+
lambda { Sunspot.setup(Post) { string :author_name }}.should_not raise_error
|
77
|
+
lambda { Sunspot.setup(Post) { bogus :journey }}.should raise_error(NoMethodError)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should throw a NoMethodError if a nonexistent field argument is passed' do
|
81
|
+
lambda { Sunspot.setup(Post) { string :author_name, :bogus => :argument }}.should raise_error(ArgumentError)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should throw an ArgumentError if an attempt is made to index an object that has no configuration' do
|
85
|
+
lambda { session.index(Time.now) }.should raise_error(ArgumentError)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should throw an ArgumentError if single-value field tries to index multiple values' do
|
89
|
+
lambda do
|
90
|
+
Sunspot.setup(Post) { string :author_name }
|
91
|
+
session.index(post(:author_name => ['Mat Brown', 'Matthew Brown']))
|
92
|
+
end.should raise_error(ArgumentError)
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def config
|
98
|
+
Sunspot::Configuration.build
|
99
|
+
end
|
100
|
+
|
101
|
+
def connection
|
102
|
+
@connection ||= mock('connection')
|
103
|
+
end
|
104
|
+
|
105
|
+
def session
|
106
|
+
@session ||= Sunspot::Session.new(config, connection)
|
107
|
+
end
|
108
|
+
|
109
|
+
def post(attrs = {})
|
110
|
+
@post ||= Post.new(attrs)
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'retrieving search' do
|
4
|
+
it 'should load search result' do
|
5
|
+
post = Post.new
|
6
|
+
stub_results(post)
|
7
|
+
session.search(Post).results.should == [post]
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should load multiple search results in order' do
|
11
|
+
post_1, post_2 = Post.new, Post.new
|
12
|
+
stub_results(post_1, post_2)
|
13
|
+
session.search(Post).results.should == [post_1, post_2]
|
14
|
+
stub_results(post_2, post_1)
|
15
|
+
session.search(Post).results.should == [post_2, post_1]
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return search total as attribute of results if pagination is provided' do
|
19
|
+
stub_results(Post.new, 4)
|
20
|
+
session.search(Post, :page => 1).results.total_entries.should == 4
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return vanilla array if pagination is provided but WillPaginate is not available' do
|
24
|
+
stub_results(Post.new)
|
25
|
+
without_class(WillPaginate) do
|
26
|
+
session.search(Post, :page => 1).results.should_not respond_to(:total_entries)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return total' do
|
31
|
+
stub_results(Post.new, Post.new, 4)
|
32
|
+
session.search(Post, :page => 1).total.should == 4
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def stub_results(*results)
|
38
|
+
total_hits = if results.last.is_a?(Integer) then results.pop
|
39
|
+
else results.length
|
40
|
+
end
|
41
|
+
response = mock('response')
|
42
|
+
response.stub!(:hits).and_return(results.map { |result| { 'id' => "#{result.class.name} #{result.id}" }})
|
43
|
+
response.stub!(:total_hits).and_return(total_hits)
|
44
|
+
connection.stub!(:query).and_return(response)
|
45
|
+
end
|
46
|
+
|
47
|
+
def config
|
48
|
+
@config ||= Sunspot::Configuration.build
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def connection
|
53
|
+
@connection ||= mock('connection')
|
54
|
+
end
|
55
|
+
|
56
|
+
def session
|
57
|
+
@session ||= Sunspot::Session.new(config, connection)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'Session' do
|
4
|
+
context 'using singleton session' do
|
5
|
+
before :each do
|
6
|
+
Sunspot.reset!
|
7
|
+
connection.should_receive(:add)
|
8
|
+
connection.should_receive(:query)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should open connection with defaults if nothing specified' do
|
12
|
+
Solr::Connection.stub!(:new).with('http://localhost:8983/solr', :autocommit => :on).and_return(connection)
|
13
|
+
Sunspot.index(Post.new)
|
14
|
+
Sunspot.search(Post)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should open a connection with custom host' do
|
18
|
+
Solr::Connection.stub!(:new).with('http://127.0.0.1:8981/solr', :autocommit => :on).and_return(connection)
|
19
|
+
Sunspot.config.solr.url = 'http://127.0.0.1:8981/solr'
|
20
|
+
Sunspot.index(Post.new)
|
21
|
+
Sunspot.search(Post)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'using custom session' do
|
26
|
+
before :each do
|
27
|
+
connection.should_receive(:add)
|
28
|
+
connection.should_receive(:query)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should open a connection with custom host' do
|
32
|
+
Solr::Connection.stub!(:new).with('http://127.0.0.1:8982/solr', :autocommit => :on).and_return(connection)
|
33
|
+
session = Sunspot::Session.new do |config|
|
34
|
+
config.solr.url = 'http://127.0.0.1:8982/solr'
|
35
|
+
end
|
36
|
+
session.index(Post.new)
|
37
|
+
session.search(Post)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def connection
|
42
|
+
@connection ||= stub_everything('Connection')
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'standard search builder' do
|
4
|
+
before :each do
|
5
|
+
stub_results
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should give access to order through hash and object' do
|
9
|
+
search = session.search(Post, :order => 'sort_title asc')
|
10
|
+
search.builder.params[:order].should == 'sort_title asc'
|
11
|
+
search.builder.order.should == 'sort_title asc'
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should give nil order if no order set' do
|
15
|
+
search = session.search(Post)
|
16
|
+
search.builder.params.should have_key(:order)
|
17
|
+
search.builder.params[:order].should be_nil
|
18
|
+
search.builder.order.should be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should give access to page and per-page through hash and object' do
|
22
|
+
search = session.search(Post, :page => 2, :per_page => 15)
|
23
|
+
search.builder.params[:page].should == 2
|
24
|
+
search.builder.params[:per_page].should == 15
|
25
|
+
search.builder.page.should == 2
|
26
|
+
search.builder.per_page.should == 15
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should give access to keywords' do
|
30
|
+
search = session.search(Post, :keywords => 'some keywords')
|
31
|
+
search.builder.params[:keywords].should == 'some keywords'
|
32
|
+
search.builder.keywords.should == 'some keywords'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should have nil keywords if no keywords given' do
|
36
|
+
search = session.search(Post)
|
37
|
+
search.builder.params.should have_key(:keywords)
|
38
|
+
search.builder.params[:keywords].should be_nil
|
39
|
+
search.builder.keywords.should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should give access to conditions' do
|
43
|
+
search = session.search(Post, :conditions => { :blog_id => 1 })
|
44
|
+
search.builder.params[:conditions][:blog_id].should == 1
|
45
|
+
search.builder.conditions.blog_id.should == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should have nil values for fields with unspecified conditions' do
|
49
|
+
search = session.search(Post)
|
50
|
+
%w(title blog_id category_ids average_rating published_at sort_title).each do |field_name|
|
51
|
+
search.builder.params[:conditions].should have_key(field_name.to_sym)
|
52
|
+
search.builder.params[:conditions][field_name.to_sym].should == nil
|
53
|
+
search.builder.conditions.should respond_to(field_name)
|
54
|
+
search.builder.conditions.send(field_name).should == nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def stub_results(*results)
|
61
|
+
response = mock('response', :hits => [], :total_hits => 0)
|
62
|
+
connection.stub!(:query).and_return(response)
|
63
|
+
end
|
64
|
+
|
65
|
+
def config
|
66
|
+
@config ||= Sunspot::Configuration.build
|
67
|
+
end
|
68
|
+
|
69
|
+
def connection
|
70
|
+
@connection ||= mock('connection')
|
71
|
+
end
|
72
|
+
|
73
|
+
def session
|
74
|
+
@session ||= Sunspot::Session.new(config, connection)
|
75
|
+
end
|
76
|
+
end
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
|
3
|
+
describe 'field types' do
|
4
4
|
def self.test_field_type(name, field, *values)
|
5
5
|
raise(ArgumentError, 'Please supply five values') unless values.length == 5
|
6
6
|
|
@@ -14,40 +14,40 @@ class TestFieldTypes < Test::Unit::TestCase
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
it 'should filter by exact match' do
|
18
18
|
Sunspot.search(Post) { with.send(field, values[2]) }.results.should == [@posts[2]]
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
it 'should filter by less than' do
|
22
22
|
results = Sunspot.search(Post) { with.send(field).less_than values[2] }.results
|
23
23
|
(0..2).each { |i| results.should include(@posts[i]) }
|
24
24
|
(3..4).each { |i| results.should_not include(@posts[i]) }
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
it 'should filter by greater than' do
|
28
28
|
results = Sunspot.search(Post) { with.send(field).greater_than values[2] }.results
|
29
29
|
(2..4).each { |i| results.should include(@posts[i]) }
|
30
30
|
(0..1).each { |i| results.should_not include(@posts[i]) }
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
it 'should filter by between' do
|
34
34
|
results = Sunspot.search(Post) { with.send(field).between(values[1]..values[3]) }.results
|
35
35
|
(1..3).each { |i| results.should include(@posts[i]) }
|
36
36
|
[0, 4].each { |i| results.should_not include(@posts[i]) }
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
it 'should filter by any of' do
|
40
40
|
results = Sunspot.search(Post) { with.send(field).any_of(values.values_at(1, 3)) }.results
|
41
41
|
[1, 3].each { |i| results.should include(@posts[i]) }
|
42
42
|
[0, 2, 4].each { |i| results.should_not include(@posts[i]) }
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
it 'should order by field ascending' do
|
46
46
|
results = Sunspot.search(Post) { order_by field, :asc }.results
|
47
47
|
results.should == @posts
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
it 'should order by field descending' do
|
51
51
|
results = Sunspot.search(Post) { order_by field, :desc }.results
|
52
52
|
results.should == @posts.reverse
|
53
53
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
|
3
|
+
describe 'keyword search' do
|
4
4
|
before :all do
|
5
5
|
Sunspot.remove_all
|
6
6
|
@posts = []
|
@@ -13,18 +13,18 @@ class TestKeywordSearch < Test::Unit::TestCase
|
|
13
13
|
Sunspot.index(*@posts)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
it 'matches a single keyword out of a single field' do
|
17
17
|
results = Sunspot.search(Post) { keywords 'toast' }.results
|
18
18
|
[0, 2].each { |i| results.should include(@posts[i]) }
|
19
19
|
[1].each { |i| results.should_not include(@posts[i]) }
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
it 'matches multiple words out of a single field' do
|
23
23
|
results = Sunspot.search(Post) { keywords 'elects toast' }.results
|
24
24
|
results.should == [@posts[0]]
|
25
25
|
end
|
26
26
|
|
27
|
-
|
27
|
+
it 'matches multiple words in multiple fields' do
|
28
28
|
results = Sunspot.search(Post) { keywords 'toast wind' }.results
|
29
29
|
[0, 2].each { |i| results.should include(@posts[i]) }
|
30
30
|
[1].each { |i| results.should_not include(@posts[i]) }
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
|
3
|
+
describe 'pagination' do
|
4
4
|
before :all do
|
5
5
|
Sunspot.remove_all
|
6
6
|
@posts = (0..19).map do |i|
|
@@ -9,12 +9,12 @@ class TestPagination < Test::Unit::TestCase
|
|
9
9
|
Sunspot.index(*@posts)
|
10
10
|
end
|
11
11
|
|
12
|
-
should
|
12
|
+
it 'should return all by default' do
|
13
13
|
results = Sunspot.search(Post) { order_by :blog_id }.results
|
14
14
|
results.should == @posts
|
15
15
|
end
|
16
16
|
|
17
|
-
should
|
17
|
+
it 'should return first page of 10' do
|
18
18
|
results = Sunspot.search(Post) do
|
19
19
|
order_by :blog_id
|
20
20
|
paginate :page => 1, :per_page => 10
|
@@ -22,7 +22,7 @@ class TestPagination < Test::Unit::TestCase
|
|
22
22
|
results.should == @posts[0,10]
|
23
23
|
end
|
24
24
|
|
25
|
-
should
|
25
|
+
it 'should return second page of 10' do
|
26
26
|
results = Sunspot.search(Post) do
|
27
27
|
order_by :blog_id
|
28
28
|
paginate :page => 2, :per_page => 10
|
File without changes
|
File without changes
|
File without changes
|
data/{test → spec}/mocks/post.rb
RENAMED
File without changes
|
@@ -1,17 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
gem 'jeremymcanally-matchy', '>= 0.0.1'
|
3
|
-
gem 'jeremymcanally-context', '>= 0.0.6'
|
4
2
|
gem 'ruby-debug', '~>0.10'
|
5
3
|
gem 'mislav-will_paginate', '~> 2.3'
|
4
|
+
gem 'rspec', '~> 1.1'
|
6
5
|
|
7
|
-
require 'matchy'
|
8
|
-
require 'context'
|
9
6
|
require 'ruby-debug'
|
7
|
+
require 'spec'
|
10
8
|
require 'will_paginate'
|
11
9
|
require 'will_paginate/collection'
|
12
10
|
|
13
|
-
require File.join(File.dirname(__FILE__), 'custom_expectation')
|
14
|
-
|
15
11
|
unless gem_name = ENV['SUNSPOT_TEST_GEM']
|
16
12
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
17
13
|
else
|
@@ -22,10 +18,8 @@ require 'sunspot'
|
|
22
18
|
require File.join(File.dirname(__FILE__), 'mocks', 'base_class.rb')
|
23
19
|
Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each { |file| require file }
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
Object.class_eval { const_set(clazz.name.to_sym, clazz) }
|
30
|
-
end
|
21
|
+
def without_class(clazz)
|
22
|
+
Object.class_eval { remove_const(clazz.name.to_sym) }
|
23
|
+
yield
|
24
|
+
Object.class_eval { const_set(clazz.name.to_sym, clazz) }
|
31
25
|
end
|
data/tasks/gemspec.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
begin
|
2
|
+
gem 'technicalpickles-jeweler', '~> 0.8.1'
|
3
|
+
require 'jeweler'
|
4
|
+
Jeweler::Tasks.new do |s|
|
5
|
+
s.name = 'sunspot'
|
6
|
+
s.executables = 'sunspot-solr'
|
7
|
+
s.summary = 'Library for expressive, powerful interaction with the Solr search engine'
|
8
|
+
s.email = 'mat@patch.com'
|
9
|
+
s.homepage = 'http://github.com/outoftime/sunspot'
|
10
|
+
s.description = 'Library for expressive, powerful interaction with the Solr search engine'
|
11
|
+
s.authors = ['Mat Brown']
|
12
|
+
s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/conf/*', 'solr/start.jar']
|
13
|
+
s.add_dependency 'solr-ruby', '>= 0.0.6'
|
14
|
+
s.add_dependency 'extlib', '>= 0.9.10'
|
15
|
+
s.add_development_dependency 'rspec', '~> 1.1'
|
16
|
+
s.add_development_dependency 'ruby-debug', '~> 0.10'
|
17
|
+
end
|
18
|
+
end
|