sunspot_rails 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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