sunspot_activerecord 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -126,7 +126,7 @@ module SunspotActiveRecord #:nodoc:
126
126
  #
127
127
  # ==== Options
128
128
  #
129
- # :include:: Specify associations to eager load
129
+ # :include :: Specify associations to eager load
130
130
  # :select:: Specify columns to select from database when loading results
131
131
  #
132
132
  # ==== Returns
@@ -231,9 +231,9 @@ module SunspotActiveRecord #:nodoc:
231
231
  if options[:batch_size]
232
232
  counter = 0
233
233
  find_in_batches(:include => options[:include], :batch_size => options[:batch_size]) do |records|
234
- solr_benchmark options[:batch_size], counter do
234
+ #solr_benchmark options[:batch_size], counter do
235
235
  Sunspot.index(records)
236
- end
236
+ #end
237
237
  Sunspot.commit if options[:batch_commit]
238
238
  counter += 1
239
239
  end
@@ -316,10 +316,10 @@ module SunspotActiveRecord #:nodoc:
316
316
  #
317
317
  def solr_benchmark(batch_size, counter, &block)
318
318
  start = Time.now
319
- logger.info("[#{Time.now}] Start Indexing")
319
+ #logger.info("[#{Time.now}] Start Indexing")
320
320
  yield
321
321
  elapsed = Time.now-start
322
- logger.info("[#{Time.now}] Completed Indexing. Rows indexed #{counter * batch_size}. Rows/sec: #{batch_size/elapsed.to_f} (Elapsed: #{elapsed} sec.)")
322
+ #logger.info("[#{Time.now}] Completed Indexing. Rows indexed #{counter * batch_size}. Rows/sec: #{batch_size/elapsed.to_f} (Elapsed: #{elapsed} sec.)")
323
323
  end
324
324
 
325
325
  end
@@ -1,3 +1,3 @@
1
1
  module SunspotActiverecord
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/spec/app/boot.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'sunspot'
4
+ require 'sunspot_activerecord'
5
+
6
+ ENV['APP_ROOT'] ||= File.dirname(__FILE__)
7
+ env = ENV['APP_ENV'] || 'development'
8
+
9
+ db = YAML.load_file(File.join(ENV['APP_ROOT'], 'db', 'database.yml'))
10
+ db[env][:database] = ENV['APP_ROOT'] + '/' + db[env][:database]
11
+ ActiveRecord::Base.establish_connection(db[env])
12
+
13
+
14
+ $LOAD_PATH.unshift("#{ENV['APP_ROOT']}/models")
15
+ Dir.glob("#{ENV['APP_ROOT']}/models/*.rb") { |model| require File.basename(model, '.*') }
@@ -0,0 +1,5 @@
1
+ test: &test
2
+ :adapter: sqlite3
3
+ :database: db/test.sqlite3
4
+
5
+ development: *test
@@ -0,0 +1,27 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :posts, :force => true do |t|
3
+ t.string :title
4
+ t.string :type
5
+ t.integer :location_id
6
+ t.text :body
7
+ t.references :blog
8
+ t.timestamps
9
+ end
10
+
11
+ create_table :locations, :force => true do |t|
12
+ t.float :lat
13
+ t.float :lng
14
+ end
15
+
16
+ create_table :blogs, :force => true do |t|
17
+ t.string :name
18
+ t.string :subdomain
19
+ t.timestamps
20
+ end
21
+
22
+ create_table :writers, :force => true, :primary_key => :writer_id do |t|
23
+ t.string :name
24
+ t.timestamps
25
+ end
26
+
27
+ end
Binary file
@@ -0,0 +1,8 @@
1
+ class Author < ActiveRecord::Base
2
+ set_table_name :writers
3
+ set_primary_key :writer_id
4
+
5
+ searchable do
6
+ string :name
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ class Blog < ActiveRecord::Base
2
+ has_many :posts
3
+ has_many :comments, :through => :posts
4
+
5
+ searchable :include => { :posts => :author } do
6
+ string :subdomain
7
+ text :name
8
+ end
9
+
10
+ # Make sure that includes are added to with multiple searchable calls
11
+ searchable(:include => :comments) {}
12
+ end
@@ -0,0 +1,2 @@
1
+ class Location < ActiveRecord::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class PhotoPost < PostWithAuto
2
+ end
@@ -0,0 +1,11 @@
1
+ class Post < ActiveRecord::Base
2
+ belongs_to :location
3
+ belongs_to :author
4
+ has_many :comments
5
+
6
+ searchable :auto_index => false, :auto_remove => false do
7
+ string :title
8
+ text :body, :more_like_this => true
9
+ location :location
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ class PostWithAuto < ActiveRecord::Base
2
+ def self.table_name
3
+ 'posts'
4
+ end
5
+
6
+ searchable :ignore_attribute_changes_of => [ :updated_at ] do
7
+ string :title
8
+ text :body, :more_like_this => true
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class PostWithDefaultScope < ActiveRecord::Base
2
+ def self.table_name
3
+ 'posts'
4
+ end
5
+
6
+ default_scope :order => :title
7
+
8
+ searchable :auto_index => false, :auto_remove => false do
9
+ string :title
10
+ end
11
+ end
@@ -0,0 +1,357 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'ActiveRecord mixin' do
4
+ describe 'index()' do
5
+ before :each do
6
+ @post = Post.create!
7
+ #@post = Post.create!(:title => 'title', :body => 'body')
8
+ @post.index
9
+ end
10
+
11
+ it 'should not commit the model' do
12
+ Post.search.results.should be_empty
13
+ end
14
+
15
+ it 'should index the model' do
16
+ Sunspot.commit
17
+ Post.search.results.should == [@post]
18
+ end
19
+
20
+ it "should not blow up if there's a default scope specifying order" do
21
+ posts = Array.new(2) { |j| PostWithDefaultScope.create! :title => (10-j).to_s }
22
+ lambda { PostWithDefaultScope.index(:batch_size => 1) }.should_not raise_error
23
+ end
24
+ end
25
+
26
+ describe 'single table inheritence' do
27
+ before :each do
28
+ @post = PhotoPost.create!
29
+ end
30
+
31
+ it 'should not break auto-indexing' do
32
+ @post.title = 'Title'
33
+ lambda { @post.save! }.should_not raise_error
34
+ end
35
+ end
36
+
37
+ describe 'index!()' do
38
+ before :each do
39
+ @post = Post.create!
40
+ @post.index!
41
+ end
42
+
43
+ it 'should immediately index and commit' do
44
+ Post.search.results.should == [@post]
45
+ end
46
+ end
47
+
48
+ describe 'remove_from_index()' do
49
+ before :each do
50
+ @post = Post.create!
51
+ @post.index!
52
+ @post.remove_from_index
53
+ end
54
+
55
+ it 'should not commit immediately' do
56
+ Post.search.results.should == [@post]
57
+ end
58
+
59
+ it 'should remove the model from the index' do
60
+ Sunspot.commit
61
+ Post.search.results.should be_empty
62
+ end
63
+ end
64
+
65
+ describe 'remove_from_index!()' do
66
+ before :each do
67
+ @post = Post.create!
68
+ @post.index!
69
+ @post.remove_from_index!
70
+ end
71
+
72
+ it 'should immediately remove the model and commit' do
73
+ Post.search.results.should be_empty
74
+ end
75
+ end
76
+
77
+ describe 'remove_all_from_index' do
78
+ before :each do
79
+ @posts = Array.new(2) { Post.create! }.each { |post| Sunspot.index(post) }
80
+ Sunspot.commit
81
+ Post.remove_all_from_index
82
+ end
83
+
84
+ it 'should not commit immediately' do
85
+ Post.search.results.to_set.should == @posts.to_set
86
+ end
87
+
88
+ it 'should remove all instances from the index' do
89
+ Sunspot.commit
90
+ Post.search.results.should be_empty
91
+ end
92
+ end
93
+
94
+ describe 'remove_all_from_index!' do
95
+ before :each do
96
+ Array.new(2) { Post.create! }.each { |post| Sunspot.index(post) }
97
+ Sunspot.commit
98
+ Post.remove_all_from_index!
99
+ end
100
+
101
+ it 'should remove all instances from the index and commit immediately' do
102
+ Post.search.results.should be_empty
103
+ end
104
+ end
105
+
106
+ describe 'search()' do
107
+ before :each do
108
+ @post = Post.create!(:title => 'Test Post')
109
+ @post.index!
110
+ end
111
+
112
+ it 'should return results specified by search' do
113
+ Post.search do
114
+ with :title, 'Test Post'
115
+ end.results.should == [@post]
116
+ end
117
+
118
+ it 'should not return results excluded by search' do
119
+ Post.search do
120
+ with :title, 'Bogus Post'
121
+ end.results.should be_empty
122
+ end
123
+
124
+ it 'should use the include option on the data accessor when specified' do
125
+ Post.should_receive(:all).with(hash_including(:include => [:blog])).and_return([@post])
126
+ Post.search do
127
+ with :title, 'Test Post'
128
+ data_accessor_for(Post).include = [:blog]
129
+ end.results.should == [@post]
130
+ end
131
+
132
+ it 'should pass :include option from search call to data accessor' do
133
+ Post.should_receive(:all).with(hash_including(:include => [:blog])).and_return([@post])
134
+ Post.search(:include => [:blog]) do
135
+ with :title, 'Test Post'
136
+ end.results.should == [@post]
137
+ end
138
+
139
+ it 'should use the select option from search call to data accessor' do
140
+ Post.should_receive(:all).with(hash_including(:select => 'title, published_at')).and_return([@post])
141
+ Post.search(:select => 'title, published_at') do
142
+ with :title, 'Test Post'
143
+ end.results.should == [@post]
144
+ end
145
+
146
+ it 'should not allow bogus options to search' do
147
+ lambda { Post.search(:bogus => :option) }.should raise_error(ArgumentError)
148
+ end
149
+
150
+ it 'should use the select option on the data accessor when specified' do
151
+ Post.should_receive(:all).with(hash_including(:select => 'title, published_at')).and_return([@post])
152
+ Post.search do
153
+ with :title, 'Test Post'
154
+ data_accessor_for(Post).select = [:title, :published_at]
155
+ end.results.should == [@post]
156
+ end
157
+
158
+ it 'should not use the select option on the data accessor when not specified' do
159
+ Post.should_receive(:all).with(hash_not_including(:select)).and_return([@post])
160
+ Post.search do
161
+ with :title, 'Test Post'
162
+ end.results.should == [@post]
163
+ end
164
+
165
+ it 'should gracefully handle nonexistent records' do
166
+ post2 = Post.create!(:title => 'Test Post')
167
+ post2.index!
168
+ post2.destroy
169
+ Post.search do
170
+ with :title, 'Test Post'
171
+ end.results.should == [@post]
172
+ end
173
+
174
+ it 'should use an ActiveRecord object for coordinates' do
175
+ post = Post.new(:title => 'Test Post')
176
+ post.location = Location.create!(:lat => 40.0, :lng => -70.0)
177
+ post.save
178
+ post.index!
179
+ Post.search { with(:location).near(40.0, -70.0) }.results.should == [post]
180
+ end
181
+
182
+ end
183
+
184
+ describe 'search_ids()' do
185
+ before :each do
186
+ @posts = Array.new(2) { Post.create! }.each { |post| post.index }
187
+ Sunspot.commit
188
+ end
189
+
190
+ it 'should return IDs' do
191
+ Post.search_ids.to_set.should == @posts.map { |post| post.id }.to_set
192
+ end
193
+ end
194
+
195
+ describe 'searchable?()' do
196
+ it 'should not be true for models that have not been configured for search' do
197
+ Location.should_not be_searchable
198
+ end
199
+
200
+ it 'should be true for models that have been configured for search' do
201
+ Post.should be_searchable
202
+ end
203
+ end
204
+
205
+ describe 'index_orphans()' do
206
+ before :each do
207
+ @posts = Array.new(2) { Post.create }.each { |post| post.index }
208
+ Sunspot.commit
209
+ @posts.first.destroy
210
+ end
211
+
212
+ it 'should return IDs of objects that are in the index but not the database' do
213
+ Post.index_orphans.should == [@posts.first.id]
214
+ end
215
+ end
216
+
217
+ describe 'clean_index_orphans()' do
218
+ before :each do
219
+ @posts = Array.new(2) { Post.create }.each { |post| post.index }
220
+ Sunspot.commit
221
+ @posts.first.destroy
222
+ end
223
+
224
+ it 'should remove orphans from the index' do
225
+ Post.clean_index_orphans
226
+ Sunspot.commit
227
+ Post.search.results.should == [@posts.last]
228
+ end
229
+ end
230
+
231
+ describe 'reindex()' do
232
+ before :each do
233
+ @posts = Array.new(2) { Post.create }
234
+ end
235
+
236
+ it 'should index all instances' do
237
+ Post.reindex(:batch_size => nil)
238
+ Sunspot.commit
239
+ Post.search.results.to_set.should == @posts.to_set
240
+ end
241
+
242
+ it 'should remove all currently indexed instances' do
243
+ old_post = Post.create!
244
+ old_post.index!
245
+ old_post.destroy
246
+ Post.reindex
247
+ Sunspot.commit
248
+ Post.search.results.to_set.should == @posts.to_set
249
+ end
250
+
251
+ end
252
+
253
+ describe 'reindex() with real data' do
254
+ before :each do
255
+ @posts = Array.new(2) { Post.create }
256
+ end
257
+
258
+ it 'should index all instances' do
259
+ Post.reindex(:batch_size => nil)
260
+ Sunspot.commit
261
+ Post.search.results.to_set.should == @posts.to_set
262
+ end
263
+
264
+ it 'should remove all currently indexed instances' do
265
+ old_post = Post.create!
266
+ old_post.index!
267
+ old_post.destroy
268
+ Post.reindex
269
+ Sunspot.commit
270
+ Post.search.results.to_set.should == @posts.to_set
271
+ end
272
+
273
+ describe "using batch sizes" do
274
+ it 'should index with a specified batch size' do
275
+ Post.reindex(:batch_size => 1)
276
+ Sunspot.commit
277
+ Post.search.results.to_set.should == @posts.to_set
278
+ end
279
+ end
280
+ end
281
+
282
+
283
+
284
+ describe "reindex()" do
285
+
286
+ before(:each) do
287
+ @posts = Array.new(2) { Post.create }
288
+ end
289
+
290
+ describe "when not using batches" do
291
+
292
+ it "should select all if the batch_size is nil" do
293
+ Post.should_receive(:all).with(:include => []).and_return([])
294
+ Post.reindex(:batch_size => nil)
295
+ end
296
+
297
+ it "should search for models with includes" do
298
+ Post.should_receive(:all).with(:include => :author).and_return([])
299
+ Post.reindex(:batch_size => nil, :include => :author)
300
+ end
301
+
302
+ end
303
+
304
+ describe "when using batches" do
305
+ it "should commit after indexing each batch" do
306
+ Sunspot.should_receive(:commit).twice
307
+ Post.reindex(:batch_size => 1)
308
+ end
309
+
310
+ it "should commit after indexing everything" do
311
+ Sunspot.should_receive(:commit).once
312
+ Post.reindex(:batch_commit => false)
313
+ end
314
+ end
315
+ end
316
+
317
+ describe "more_like_this()" do
318
+ before(:each) do
319
+ @posts = [
320
+ Post.create!(:title => 'Post123', :body => "one two three"),
321
+ Post.create!(:title => 'Post345', :body => "three four five"),
322
+ Post.create!(:title => 'Post456', :body => "four five six"),
323
+ Post.create!(:title => 'Post234', :body => "two three four"),
324
+ ]
325
+ @posts_with_auto = [
326
+ PostWithAuto.create!(:body => "one two three"),
327
+ PostWithAuto.create!(:body => "four five six")
328
+ ]
329
+ @posts.each { |p| p.index! }
330
+ end
331
+
332
+ it "should return results" do
333
+ @posts.first.more_like_this.results.should == [@posts[3], @posts[1]]
334
+ end
335
+
336
+ it "should return results for specified classes" do
337
+ @posts.first.more_like_this(Post, PostWithAuto).results.to_set.should ==
338
+ Set[@posts_with_auto[0], @posts[1], @posts[3]]
339
+ end
340
+ end
341
+
342
+ describe 'more_like_this_ids()' do
343
+ before :each do
344
+ @posts = [
345
+ Post.create!(:title => 'Post123', :body => "one two three"),
346
+ Post.create!(:title => 'Post345', :body => "three four five"),
347
+ Post.create!(:title => 'Post456', :body => "four five six"),
348
+ Post.create!(:title => 'Post234', :body => "two three four"),
349
+ ]
350
+ @posts.each { |p| p.index! }
351
+ end
352
+
353
+ it 'should return IDs' do
354
+ @posts.first.more_like_this_ids.to_set.should == [@posts[3], @posts[1]].map { |post| post.id }.to_set
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,57 @@
1
+ ENV['APP_ROOT'] ||= File.join(File.dirname(__FILE__), 'app')
2
+ ENV['APP_ENV'] ||= 'test'
3
+
4
+ if rsolr_version = ENV['RSOLR_GEM_VERSION']
5
+ STDERR.puts("Forcing RSolr version #{rsolr_version}")
6
+ gem "rsolr", rsolr_version
7
+ end
8
+
9
+ begin
10
+ require 'rspec'
11
+ # require 'rspec/rails'
12
+ rescue LoadError => e
13
+ require 'spec'
14
+ # require 'spec/rails'
15
+ end
16
+ require 'rake'
17
+ require 'rubygems'
18
+ require 'sqlite3'
19
+
20
+ #`sunspot-solr start`
21
+ require File.join(ENV['APP_ROOT'], 'boot.rb')
22
+ #require File.join('sunspot', 'rails', 'solr_logging')
23
+
24
+ def load_db
25
+ # stdout = $stdout
26
+ # $stdout = StringIO.new # suppress output while building the schema
27
+ # db = YAML.load_file(File.join(ENV['APP_ROOT'], 'db', 'database.yml'))
28
+ # ActiveRecord::Base.establish_connection(db['test'])
29
+
30
+ #load File.join(ENV['APP_ROOT'], 'schema.rb')
31
+ # $stdout = stdout
32
+ end
33
+
34
+ def silence_stderr(&block)
35
+ stderr = $stderr
36
+ $stderr = StringIO.new
37
+ yield
38
+ $stderr = stderr
39
+ end
40
+
41
+ rspec =
42
+ begin
43
+ RSpec
44
+ rescue NameError, ArgumentError
45
+ Spec::Runner
46
+ end
47
+
48
+ rspec.configure do |config|
49
+ config.before(:each) do
50
+ load_db
51
+ Sunspot.remove_all!
52
+ Location.delete_all
53
+ Author.delete_all
54
+ Blog.delete_all
55
+ Post.delete_all
56
+ end
57
+ end
@@ -20,4 +20,5 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
  s.add_dependency 'sunspot'
22
22
  s.add_dependency 'activerecord', "~> 2.3.8"
23
+ s.add_development_dependency 'rspec', '~> 1.2'
23
24
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunspot_activerecord
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Olga Gorun
@@ -48,6 +48,21 @@ dependencies:
48
48
  version: 2.3.8
49
49
  type: :runtime
50
50
  version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rspec
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 11
60
+ segments:
61
+ - 1
62
+ - 2
63
+ version: "1.2"
64
+ type: :development
65
+ version_requirements: *id003
51
66
  description: Simplified version of sunspot_rails gem to enable usage of sunspot+active_record -based models in not Rails projects
52
67
  email:
53
68
  - ogorun@gmail.com
@@ -66,6 +81,19 @@ files:
66
81
  - lib/sunspot_activerecord/adapters.rb
67
82
  - lib/sunspot_activerecord/searchable.rb
68
83
  - lib/sunspot_activerecord/version.rb
84
+ - spec/app/boot.rb
85
+ - spec/app/db/database.yml
86
+ - spec/app/db/schema.rb
87
+ - spec/app/db/test.sqlite3
88
+ - spec/app/models/author.rb
89
+ - spec/app/models/blog.rb
90
+ - spec/app/models/location.rb
91
+ - spec/app/models/photo_post.rb
92
+ - spec/app/models/post.rb
93
+ - spec/app/models/post_with_auto.rb
94
+ - spec/app/models/post_with_default_scope.rb
95
+ - spec/model_spec.rb
96
+ - spec/spec_helper.rb
69
97
  - sunspot_activerecord.gemspec
70
98
  has_rdoc: true
71
99
  homepage: ""