sunspot_rails 1.0.1 → 1.0.2

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.
@@ -1,7 +1,14 @@
1
- == 1.0.1
1
+ == 1.0.2 2010-03-11
2
+ * Allow use of ActiveRecord object for coordinates extraction
3
+ * Works with non-standard primary keys
4
+ * Add :include, :select options to Searchable::search()
5
+ * Allow specification of min_memory and max_memory in config/sunspot.yml
6
+ * Searchable now more considerate of model namespaces
7
+
8
+ == 1.0.1 2010-03-05
2
9
  * Fix Solr logging compatibility with RSolr 0.12.1
3
10
 
4
- == 1.0.0
11
+ == 1.0.0 2010-03-03
5
12
  * Sunspot::Rails::Server subclasses Sunspot::Server; no longer needs to shell out
6
13
  * Use Sunspot built-in session proxies in Sunspot::Rails
7
14
  * Sunspot::Rails adapter compatible with assumed inconsistency
@@ -248,6 +248,8 @@ http://outoftime.lighthouseapp.com/projects/20339-sunspot
248
248
  - Adam Salter (adam@codebright.net)
249
249
  - Brandon Keepers (brandon@opensoul.org)
250
250
  - Paul Canavese (paul@canavese.org)
251
+ - John Eberly (jeberly@elctech.com)
252
+ - Gert Thiel (gertthiel@gmail.com)
251
253
 
252
254
  == License
253
255
 
@@ -16,7 +16,7 @@ running a Sunspot-compatible Solr instance for development and test
16
16
  environments, and automatically commit Solr index changes at the end of each
17
17
  Rails request.
18
18
  TEXT
19
- s.authors = ['Mat Brown', 'Peer Allan', 'Michael Moen', 'Benjamin Krause', 'Adam Salter', 'Brandon Keepers', 'Paul Canavese']
19
+ s.authors = ['Mat Brown', 'Peer Allan', 'Michael Moen', 'Benjamin Krause', 'Adam Salter', 'Brandon Keepers', 'Paul Canavese', 'John Eberly', 'Gert Thiel']
20
20
  s.rubyforge_project = 'sunspot'
21
21
  s.files = FileList['[A-Z]*',
22
22
  '{lib,tasks,dev_tasks}/**/*',
@@ -1,7 +1,24 @@
1
- require 'rake/rdoctask'
1
+ begin
2
+ require 'hanna/rdoctask'
3
+ rescue LoadError
4
+ if require 'rubygems'
5
+ retry
6
+ end
7
+ # It's OK if hanna isn't installed.
8
+ end
2
9
 
3
10
  Rake::RDocTask.new(:doc) do |rdoc|
4
11
  rdoc.main = 'README.rdoc'
5
- rdoc.rdoc_files.include('README.rdoc', 'lib/sunspot/rails/**/*.rb')
12
+ rdoc.rdoc_files.include('README.rdoc', 'lib/sunspot/rails/**/*.rb', 'lib/sunspot/rails.rb')
6
13
  rdoc.rdoc_dir = 'doc'
7
14
  end
15
+
16
+ namespace :doc do
17
+ desc 'Generate rdoc and move into pages directory'
18
+ task :publish => :redoc do
19
+ doc_dir = File.join(File.dirname(__FILE__), '..', 'doc')
20
+ publish_dir = File.join(File.dirname(__FILE__), '..', '..', 'pages', 'rails', 'docs')
21
+ FileUtils.rm_rf(publish_dir) if File.exist?(publish_dir)
22
+ FileUtils.cp_r(doc_dir, publish_dir)
23
+ end
24
+ end
@@ -47,7 +47,9 @@ module Sunspot #:nodoc:
47
47
  # ActiveRecord::Base:: ActiveRecord model
48
48
  #
49
49
  def load(id)
50
- @clazz.find_by_id(id.to_i, options_for_find)
50
+ @clazz.first(options_for_find.merge(
51
+ :conditions => { @clazz.primary_key => id.to_i}
52
+ ))
51
53
  end
52
54
 
53
55
  #
@@ -62,7 +64,9 @@ module Sunspot #:nodoc:
62
64
  # Array:: Collection of ActiveRecord models
63
65
  #
64
66
  def load_all(ids)
65
- @clazz.find_all_by_id(ids.map { |id| id.to_i }, options_for_find)
67
+ @clazz.all(options_for_find.merge(
68
+ :conditions => { @clazz.primary_key => ids.map { |id| id.to_i }}
69
+ ))
66
70
  end
67
71
 
68
72
  private
@@ -9,6 +9,8 @@ module Sunspot #:nodoc:
9
9
  # solr:
10
10
  # hostname: localhost
11
11
  # port: 8982
12
+ # min_memory: 512M
13
+ # max_memory: 1G
12
14
  # test:
13
15
  # solr:
14
16
  # hostname: localhost
@@ -194,6 +196,20 @@ module Sunspot #:nodoc:
194
196
  File.join(::Rails.root, 'solr')
195
197
  end
196
198
  end
199
+
200
+ #
201
+ # Minimum java heap size for Solr instance
202
+ #
203
+ def min_memory
204
+ @min_memory ||= user_configuration_from_key('solr', 'min_memory')
205
+ end
206
+
207
+ #
208
+ # Maximum java heap size for Solr instance
209
+ #
210
+ def max_memory
211
+ @max_memory ||= user_configuration_from_key('solr', 'max_memory')
212
+ end
197
213
 
198
214
  private
199
215
 
@@ -9,7 +9,9 @@ module Sunspot #:nodoc:
9
9
  module Searchable
10
10
  class <<self
11
11
  def included(base) #:nodoc:
12
- base.module_eval { extend(ActsAsMethods) }
12
+ base.module_eval do
13
+ extend(ActsAsMethods)
14
+ end
13
15
  end
14
16
  end
15
17
 
@@ -89,6 +91,18 @@ module Sunspot #:nodoc:
89
91
  end
90
92
 
91
93
  module ClassMethods
94
+ def self.extended(base) #:nodoc:
95
+ class <<base
96
+ alias_method :search, :solr_search unless method_defined? :search
97
+ alias_method :search_ids, :solr_search_ids unless method_defined? :search_ids
98
+ alias_method :remove_all_from_index, :solr_remove_all_from_index unless method_defined? :remove_all_from_index
99
+ alias_method :remove_all_from_index!, :solr_remove_all_from_index! unless method_defined? :remove_all_from_index!
100
+ alias_method :reindex, :solr_reindex unless method_defined? :reindex
101
+ alias_method :index, :solr_index unless method_defined? :index
102
+ alias_method :index_orphans, :solr_index_orphans unless method_defined? :index_orphans
103
+ alias_method :clean_index_orphans, :solr_clean_index_orphans unless method_defined? :clean_index_orphans
104
+ end
105
+ end
92
106
  #
93
107
  # Search for instances of this class in Solr. The block is delegated to
94
108
  # the Sunspot.search method - see the Sunspot documentation for the full
@@ -96,20 +110,36 @@ module Sunspot #:nodoc:
96
110
  #
97
111
  # ==== Example
98
112
  #
99
- # Post.search do
113
+ # Post.search(:include => [:blog]) do
100
114
  # keywords 'best pizza'
101
115
  # with :blog_id, 1
102
116
  # order :updated_at, :desc
103
117
  # facet :category_ids
104
118
  # end
105
119
  #
120
+ # ==== Options
121
+ #
122
+ # :include:: Specify associations to eager load
123
+ # :select:: Specify columns to select from database when loading results
106
124
  #
107
125
  # ==== Returns
108
126
  #
109
127
  # Sunspot::Search:: Object containing results, totals, facets, etc.
110
128
  #
111
- def search(&block)
112
- Sunspot.search(self, &block)
129
+ def solr_search(options = {}, &block)
130
+ options.assert_valid_keys(:include, :select)
131
+ search = Sunspot.new_search(self, &block)
132
+ unless options.empty?
133
+ search.build do |query|
134
+ if options[:include]
135
+ query.data_accessor_for(self).include = options[:include]
136
+ end
137
+ if options[:select]
138
+ query.data_accessor_for(self).select = options[:select]
139
+ end
140
+ end
141
+ end
142
+ search.execute
113
143
  end
114
144
 
115
145
  #
@@ -122,14 +152,14 @@ module Sunspot #:nodoc:
122
152
  #
123
153
  # Array:: Array of IDs, in the order returned by the search
124
154
  #
125
- def search_ids(&block)
126
- search(&block).raw_results.map { |raw_result| raw_result.primary_key.to_i }
155
+ def solr_search_ids(&block)
156
+ solr_search(&block).raw_results.map { |raw_result| raw_result.primary_key.to_i }
127
157
  end
128
158
 
129
159
  #
130
160
  # Remove instances of this class from the Solr index.
131
161
  #
132
- def remove_all_from_index
162
+ def solr_remove_all_from_index
133
163
  Sunspot.remove_all(self)
134
164
  end
135
165
 
@@ -138,7 +168,7 @@ module Sunspot #:nodoc:
138
168
  # commit.
139
169
  #
140
170
  #
141
- def remove_all_from_index!
171
+ def solr_remove_all_from_index!
142
172
  Sunspot.remove_all!(self)
143
173
  end
144
174
 
@@ -148,9 +178,9 @@ module Sunspot #:nodoc:
148
178
  #
149
179
  # See #index for information on options, etc.
150
180
  #
151
- def reindex(options = {})
152
- remove_all_from_index
153
- index(options)
181
+ def solr_reindex(options = {})
182
+ solr_remove_all_from_index
183
+ solr_index(options)
154
184
  end
155
185
 
156
186
  #
@@ -191,7 +221,7 @@ module Sunspot #:nodoc:
191
221
  # # include the associated +author+ object when loading to index
192
222
  # Post.index(:include => :author)
193
223
  #
194
- def index(opts={})
224
+ def solr_index(opts={})
195
225
  options = { :batch_size => 500, :batch_commit => true, :include => [], :first_id => 0}.merge(opts)
196
226
  unless options[:batch_size]
197
227
  Sunspot.index!(all(:include => options[:include]))
@@ -201,7 +231,7 @@ module Sunspot #:nodoc:
201
231
  record_count = count
202
232
  last_id = options[:first_id]
203
233
  while(offset < record_count)
204
- benchmark options[:batch_size], counter do
234
+ solr_benchmark options[:batch_size], counter do
205
235
  records = all(:include => options[:include], :conditions => ["#{table_name}.#{primary_key} > ?", last_id], :limit => options[:batch_size], :order => primary_key)
206
236
  Sunspot.index(records)
207
237
  last_id = records.last.id
@@ -224,9 +254,9 @@ module Sunspot #:nodoc:
224
254
  # ==== Returns
225
255
  #
226
256
  # Array:: Collection of IDs that exist in Solr but not in the database
227
- def index_orphans
257
+ def solr_index_orphans
228
258
  count = self.count
229
- indexed_ids = search_ids { paginate(:page => 1, :per_page => count) }.to_set
259
+ indexed_ids = solr_search_ids { paginate(:page => 1, :per_page => count) }.to_set
230
260
  all(:select => 'id').each do |object|
231
261
  indexed_ids.delete(object.id)
232
262
  end
@@ -239,11 +269,11 @@ module Sunspot #:nodoc:
239
269
  # circumstances, this should not be necessary; this method is provided
240
270
  # in case something goes wrong.
241
271
  #
242
- def clean_index_orphans
243
- index_orphans.each do |id|
272
+ def solr_clean_index_orphans
273
+ solr_index_orphans.each do |id|
244
274
  new do |fake_instance|
245
275
  fake_instance.id = id
246
- end.remove_from_index
276
+ end.solr_remove_from_index
247
277
  end
248
278
  end
249
279
 
@@ -264,7 +294,7 @@ module Sunspot #:nodoc:
264
294
  #
265
295
  # Does some logging for benchmarking indexing performance
266
296
  #
267
- def benchmark(batch_size, counter, &block)
297
+ def solr_benchmark(batch_size, counter, &block)
268
298
  start = Time.now
269
299
  logger.info("[#{Time.now}] Start Indexing")
270
300
  yield
@@ -275,6 +305,14 @@ module Sunspot #:nodoc:
275
305
  end
276
306
 
277
307
  module InstanceMethods
308
+ def self.included(base) #:nodoc:
309
+ base.module_eval do
310
+ alias_method :index, :solr_index unless method_defined? :index
311
+ alias_method :index!, :solr_index! unless method_defined? :index!
312
+ alias_method :remove_from_index, :solr_remove_from_index unless method_defined? :remove_from_index
313
+ alias_method :remove_from_index!, :solr_remove_from_index! unless method_defined? :remove_from_index!
314
+ end
315
+ end
278
316
  #
279
317
  # Index the model in Solr. If the model is already indexed, it will be
280
318
  # updated. Using the defaults, you will usually not need to call this
@@ -283,14 +321,14 @@ module Sunspot #:nodoc:
283
321
  # ClassMethods#searchable), this method allows you to manage indexing
284
322
  # manually.
285
323
  #
286
- def index
324
+ def solr_index
287
325
  Sunspot.index(self)
288
326
  end
289
327
 
290
328
  #
291
329
  # Index the model in Solr and immediately commit. See #index
292
330
  #
293
- def index!
331
+ def solr_index!
294
332
  Sunspot.index!(self)
295
333
  end
296
334
 
@@ -301,7 +339,7 @@ module Sunspot #:nodoc:
301
339
  # (which is not recommended!), you can use this method to manage removal
302
340
  # manually.
303
341
  #
304
- def remove_from_index
342
+ def solr_remove_from_index
305
343
  Sunspot.remove(self)
306
344
  end
307
345
 
@@ -309,7 +347,7 @@ module Sunspot #:nodoc:
309
347
  # Remove the model from the Solr index and commit immediately. See
310
348
  # #remove_from_index
311
349
  #
312
- def remove_from_index!
350
+ def solr_remove_from_index!
313
351
  Sunspot.remove!(self)
314
352
  end
315
353
 
@@ -327,7 +365,7 @@ module Sunspot #:nodoc:
327
365
 
328
366
  def maybe_auto_index
329
367
  if @marked_for_auto_indexing
330
- index
368
+ solr_index
331
369
  remove_instance_variable(:@marked_for_auto_indexing)
332
370
  end
333
371
  end
@@ -91,6 +91,20 @@ module Sunspot
91
91
  File.join(::Rails.root, 'log', "sunspot-solr-#{::Rails.env}.log")
92
92
  end
93
93
 
94
+ #
95
+ # Minimum Java heap size for Solr
96
+ #
97
+ def min_memory
98
+ configuration.min_memory
99
+ end
100
+
101
+ #
102
+ # Maximum Java heap size for Solr
103
+ #
104
+ def max_memory
105
+ configuration.max_memory
106
+ end
107
+
94
108
  private
95
109
 
96
110
  #
@@ -28,10 +28,10 @@ namespace :sunspot do
28
28
  task :reindex => :environment do
29
29
  all_files = Dir.glob(File.join(RAILS_ROOT, 'app', 'models', '*.rb'))
30
30
  all_models = all_files.map { |path| File.basename(path, '.rb').camelize.constantize }
31
- sunspot_models = all_models.select { |m| m < ActiveRecord::Base and m.searchable? }
31
+ sunspot_models = all_models.select { |m| m < ActiveRecord::Base and m.solr_searchable? }
32
32
 
33
33
  sunspot_models.each do |model|
34
- model.reindex :batch_commit => false
34
+ model.solr_reindex :batch_commit => false
35
35
  end
36
36
  end
37
37
  end
@@ -1,5 +1,5 @@
1
1
  module Sunspot
2
2
  module Rails
3
- VERSION = '1.0.1'
3
+ VERSION = '1.0.2'
4
4
  end
5
5
  end
@@ -0,0 +1,2 @@
1
+ class Location < ActiveRecord::Base
2
+ end
@@ -1,5 +1,8 @@
1
1
  class Post < ActiveRecord::Base
2
+ belongs_to :location
3
+
2
4
  searchable :auto_index => false, :auto_remove => false do
3
5
  string :title
6
+ coordinates :location
4
7
  end
5
8
  end
@@ -16,4 +16,4 @@ config_test:
16
16
  pid_path: /my_superior_path/pids
17
17
  solr_home: /my_superior_path
18
18
  auto_commit_after_request: false
19
- auto_commit_after_delete_request: true
19
+ auto_commit_after_delete_request: true
@@ -2,11 +2,17 @@ ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :posts, :force => true do |t|
3
3
  t.string :title
4
4
  t.string :type
5
+ t.integer :location_id
5
6
  t.text :body
6
7
  t.references :blog
7
8
  t.timestamps
8
9
  end
9
10
 
11
+ create_table :locations, :force => true do |t|
12
+ t.float :lat
13
+ t.float :lng
14
+ end
15
+
10
16
  create_table :blogs, :force => true do |t|
11
17
  t.string :name
12
18
  t.string :subdomain
@@ -26,14 +26,14 @@ describe 'searchable with lifecycle' do
26
26
  it "should index model if relevant attribute changed" do
27
27
  @post = PostWithAuto.create!
28
28
  @post.title = 'new title'
29
- @post.should_receive :index
29
+ @post.should_receive :solr_index
30
30
  @post.save!
31
31
  end
32
32
 
33
33
  it "should not index model if relevant attribute not changed" do
34
34
  @post = PostWithAuto.create!
35
35
  @post.updated_at = Date.tomorrow
36
- @post.should_not_receive :index
36
+ @post.should_not_receive :solr_index
37
37
  @post.save!
38
38
  end
39
39
  end
@@ -116,7 +116,7 @@ describe 'ActiveRecord mixin' do
116
116
  end
117
117
 
118
118
  it 'should find ActiveRecord objects with an integer, not a string' do
119
- Post.should_receive(:find_all_by_id).with([@post.id.to_i], anything).and_return([@post])
119
+ Post.should_receive(:all).with(hash_including(:conditions => { "id" => [@post.id.to_i] })).and_return([@post])
120
120
  Post.search do
121
121
  with :title, 'Test Post'
122
122
  end.results.should == [@post]
@@ -129,6 +129,24 @@ describe 'ActiveRecord mixin' do
129
129
  data_accessor_for(Post).include = [:blog]
130
130
  end.results.should == [@post]
131
131
  end
132
+
133
+ it 'should pass :include option from search call to data accessor' do
134
+ Post.should_receive(:find).with(anything(), hash_including(:include => [:blog])).and_return([@post])
135
+ Post.search(:include => [:blog]) do
136
+ with :title, 'Test Post'
137
+ end.results.should == [@post]
138
+ end
139
+
140
+ it 'should use the select option from search call to data accessor' do
141
+ Post.should_receive(:find).with(anything(), hash_including(:select => 'title, published_at')).and_return([@post])
142
+ Post.search(:select => 'title, published_at') do
143
+ with :title, 'Test Post'
144
+ end.results.should == [@post]
145
+ end
146
+
147
+ it 'should not allow bogus options to search' do
148
+ lambda { Post.search(:bogus => :option) }.should raise_error(ArgumentError)
149
+ end
132
150
 
133
151
  it 'should use the select option on the data accessor when specified' do
134
152
  Post.should_receive(:find).with(anything(), hash_including(:select => 'title, published_at')).and_return([@post])
@@ -154,6 +172,14 @@ describe 'ActiveRecord mixin' do
154
172
  end.results.should == [@post]
155
173
  end
156
174
 
175
+ it 'should use an ActiveRecord object for coordinates' do
176
+ post = Post.new(:title => 'Test Post')
177
+ post.location = Location.create!(:lat => 40.0, :lng => -70.0)
178
+ post.save
179
+ post.index!
180
+ Post.search { near([40.0, -70.0], :distance => 1) }.results.should == [post]
181
+ end
182
+
157
183
  end
158
184
 
159
185
  describe 'search_ids()' do
@@ -2,11 +2,17 @@ ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :posts, :force => true do |t|
3
3
  t.string :title
4
4
  t.string :type
5
+ t.integer :location_id
5
6
  t.text :body
6
7
  t.references :blog
7
8
  t.timestamps
8
9
  end
9
10
 
11
+ create_table :locations, :force => true do |t|
12
+ t.float :lat
13
+ t.float :lng
14
+ end
15
+
10
16
  create_table :blogs, :force => true do |t|
11
17
  t.string :name
12
18
  t.string :subdomain
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 1
9
- version: 1.0.1
8
+ - 2
9
+ version: 1.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mat Brown
@@ -16,11 +16,13 @@ authors:
16
16
  - Adam Salter
17
17
  - Brandon Keepers
18
18
  - Paul Canavese
19
+ - John Eberly
20
+ - Gert Thiel
19
21
  autorequire:
20
22
  bindir: bin
21
23
  cert_chain: []
22
24
 
23
- date: 2010-03-05 00:00:00 -05:00
25
+ date: 2010-03-11 00:00:00 -05:00
24
26
  default_executable:
25
27
  dependencies:
26
28
  - !ruby/object:Gem::Dependency
@@ -33,8 +35,8 @@ dependencies:
33
35
  segments:
34
36
  - 1
35
37
  - 0
36
- - 1
37
- version: 1.0.1
38
+ - 2
39
+ version: 1.0.2
38
40
  type: :runtime
39
41
  version_requirements: *id001
40
42
  - !ruby/object:Gem::Dependency
@@ -117,6 +119,7 @@ files:
117
119
  - spec/mock_app/app/controllers/posts_controller.rb
118
120
  - spec/mock_app/app/controllers/application_controller.rb
119
121
  - spec/mock_app/app/controllers/application.rb
122
+ - spec/mock_app/app/models/location.rb
120
123
  - spec/mock_app/app/models/photo_post.rb
121
124
  - spec/mock_app/app/models/blog.rb
122
125
  - spec/mock_app/app/models/post_with_auto.rb