sunspot 1.3.3 → 2.0.0.pre.111215

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.
Files changed (38) hide show
  1. data/History.txt +7 -10
  2. data/lib/sunspot/configuration.rb +5 -0
  3. data/lib/sunspot/dsl/field_group.rb +37 -0
  4. data/lib/sunspot/dsl/field_query.rb +48 -0
  5. data/lib/sunspot/dsl/restriction_with_near.rb +17 -0
  6. data/lib/sunspot/dsl.rb +1 -1
  7. data/lib/sunspot/query/common_query.rb +10 -0
  8. data/lib/sunspot/query/dismax.rb +5 -1
  9. data/lib/sunspot/query/field_group.rb +35 -0
  10. data/lib/sunspot/query/geofilt.rb +15 -0
  11. data/lib/sunspot/query/sort.rb +14 -0
  12. data/lib/sunspot/query/sort_composite.rb +3 -2
  13. data/lib/sunspot/query.rb +2 -2
  14. data/lib/sunspot/search/abstract_search.rb +52 -64
  15. data/lib/sunspot/search/field_group.rb +32 -0
  16. data/lib/sunspot/search/group.rb +35 -0
  17. data/lib/sunspot/search/hit_enumerable.rb +72 -0
  18. data/lib/sunspot/search/paginated_collection.rb +5 -3
  19. data/lib/sunspot/search.rb +1 -1
  20. data/lib/sunspot/session_proxy.rb +0 -8
  21. data/lib/sunspot/type.rb +21 -0
  22. data/lib/sunspot/version.rb +1 -1
  23. data/spec/api/class_set_spec.rb +1 -1
  24. data/spec/api/hit_enumerable_spec.rb +47 -0
  25. data/spec/api/query/group_spec.rb +32 -0
  26. data/spec/api/query/ordering_pagination_examples.rb +7 -0
  27. data/spec/api/query/spatial_examples.rb +11 -0
  28. data/spec/api/query/standard_spec.rb +1 -0
  29. data/spec/api/search/paginated_collection_spec.rb +10 -0
  30. data/spec/api/search/results_spec.rb +6 -0
  31. data/spec/integration/field_grouping_spec.rb +65 -0
  32. data/spec/integration/geospatial_spec.rb +59 -0
  33. data/spec/integration/highlighting_spec.rb +20 -0
  34. data/spec/mocks/post.rb +1 -0
  35. data/sunspot.gemspec +2 -1
  36. metadata +54 -34
  37. data/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +0 -67
  38. data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +0 -73
data/History.txt CHANGED
@@ -1,13 +1,10 @@
1
- == 1.3.3 2012-06-11
2
-
3
- * Adds missing `more_like_this` method to `StubSessionProxy` (Patrick Van Stee)
4
-
5
- == 1.3.2
6
-
7
- * Set initialization order for Railtie (Mauro)
8
- * Removes deprecated `InstanceMethods` module (Anders Bengtsson)
9
- * Adds `Retry5xxSessionProxy` to retry requests when an internal server error
10
- occurs (Nick Zadrozny)
1
+ == 2.0.0
2
+ * Adds support for field grouping (Andy Lindeman)
3
+ * Adds support for native geospatial searches and ordering (Eric Tang, Bruno Miranda, Andy Lindeman)
4
+ * Bundled Solr installation (`sunspot_solr`) is version 3.5.0 (Chris Parker)
5
+ * Adds #query_time method to retrieve the Solr query time in
6
+ milliseconds (Jason Weathered)
7
+ * Fixes syntax of highlighting when used with nested dismax queries (Marco Crepaldi)
11
8
 
12
9
  == 1.3.0 2011-11-26
13
10
  * Requests to Solr use HTTP POST verb by default to avoid issues when the query string grows too large for GET (Johan Van Ryseghem)
@@ -8,6 +8,8 @@ module Sunspot
8
8
  # Sunspot.config.pagination.default_per_page::
9
9
  # Solr always paginates its results. This sets Sunspot's default result
10
10
  # count per page if it is not explicitly specified in the query.
11
+ # Sunspot.config.indexing.default_batch_size::
12
+ # This sets the batch size for indexing, default is 50
11
13
  #
12
14
  module Configuration
13
15
  class <<self
@@ -28,6 +30,9 @@ module Sunspot
28
30
  pagination do
29
31
  default_per_page 30
30
32
  end
33
+ indexing do
34
+ default_batch_size 50
35
+ end
31
36
  end
32
37
  end
33
38
 
@@ -0,0 +1,37 @@
1
+ module Sunspot
2
+ module DSL
3
+ class FieldGroup
4
+ def initialize(query, setup, group)
5
+ @query, @setup, @group = query, setup, group
6
+ end
7
+
8
+ #
9
+ # Sets the number of results (documents) to return for each group.
10
+ # Defaults to 1.
11
+ #
12
+ def limit(num)
13
+ @group.limit = num
14
+ end
15
+
16
+ # Specify the order that results should be returned in. This method can
17
+ # be called multiple times; precedence will be in the order given.
18
+ #
19
+ # ==== Parameters
20
+ #
21
+ # field_name<Symbol>:: the field to use for ordering
22
+ # direction<Symbol>:: :asc or :desc (default :asc)
23
+ #
24
+ def order_by(field_name, direction = nil)
25
+ sort =
26
+ if special = Sunspot::Query::Sort.special(field_name)
27
+ special.new(direction)
28
+ else
29
+ Sunspot::Query::Sort::FieldSort.new(
30
+ @setup.field(field_name), direction
31
+ )
32
+ end
33
+ @group.add_sort(sort)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -31,6 +31,27 @@ module Sunspot
31
31
  @query.add_sort(sort)
32
32
  end
33
33
 
34
+ #
35
+ # Specify that the results should be ordered based on their
36
+ # distance from a given point.
37
+ #
38
+ # ==== Parameters
39
+ #
40
+ # field_name<Symbol>::
41
+ # the field that stores the location (declared as `latlon`)
42
+ # lat<Numeric>::
43
+ # the reference latitude
44
+ # lon<Numeric>::
45
+ # the reference longitude
46
+ # direction<Symbol>::
47
+ # :asc or :desc (default :asc)
48
+ #
49
+ def order_by_geodist(field_name, lat, lon, direction = nil)
50
+ @query.add_sort(
51
+ Sunspot::Query::Sort::GeodistSort.new(@setup.field(field_name), lat, lon, direction)
52
+ )
53
+ end
54
+
34
55
  #
35
56
  # DEPRECATED Use <code>order_by(:random)</code>
36
57
  #
@@ -38,6 +59,33 @@ module Sunspot
38
59
  order_by(:random)
39
60
  end
40
61
 
62
+ # Specify a field for result grouping. Grouping groups documents
63
+ # with a common field value, return only the top document per
64
+ # group.
65
+ #
66
+ # More information in the Solr documentation:
67
+ # <http://wiki.apache.org/solr/FieldCollapsing>
68
+ #
69
+ # ==== Parameters
70
+ #
71
+ # field_name<Symbol>:: the field to use for grouping
72
+ def group(*field_names, &block)
73
+ options = Sunspot::Util.extract_options_from(field_names)
74
+
75
+ field_names.each do |field_name|
76
+ field = @setup.field(field_name)
77
+ group = @query.add_group(Sunspot::Query::FieldGroup.new(field))
78
+ @search.add_field_group(field)
79
+
80
+ if block
81
+ Sunspot::Util.instance_eval_or_call(
82
+ FieldGroup.new(@query, @setup, group),
83
+ &block
84
+ )
85
+ end
86
+ end
87
+ end
88
+
41
89
  #
42
90
  # Request a facet on the search query. A facet is a feature of Solr that
43
91
  # determines the number of documents that match the existing search *and*
@@ -116,6 +116,23 @@ module Sunspot
116
116
  def near(lat, lng, options = {})
117
117
  @query.fulltext.add_location(@field, lat, lng, options)
118
118
  end
119
+
120
+ #
121
+ # Performs a query that is filtered by a radius around a given
122
+ # latitude and longitude.
123
+ #
124
+ # ==== Parameters
125
+ #
126
+ # :lat<Numeric>::
127
+ # Latitude (in degrees)
128
+ # :lon<Numeric>::
129
+ # Longitude (in degrees)
130
+ # :radius<Numeric>::
131
+ # Radius (in kilometers)
132
+ #
133
+ def in_radius(lat, lon, radius)
134
+ @query.add_geo(Sunspot::Query::Geofilt.new(@field, lat, lon, radius))
135
+ end
119
136
  end
120
137
  end
121
138
  end
data/lib/sunspot/dsl.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  %w(fields scope paginatable adjustable field_query standard_query query_facet
2
2
  functional fulltext restriction restriction_with_near search
3
- more_like_this_query function).each do |file|
3
+ more_like_this_query function field_group).each do |file|
4
4
  require File.join(File.dirname(__FILE__), 'dsl', file)
5
5
  end
@@ -20,6 +20,11 @@ module Sunspot
20
20
  @sort << sort
21
21
  end
22
22
 
23
+ def add_group(group)
24
+ @components << group
25
+ group
26
+ end
27
+
23
28
  def add_field_facet(facet)
24
29
  @components << facet
25
30
  facet
@@ -35,6 +40,11 @@ module Sunspot
35
40
  function
36
41
  end
37
42
 
43
+ def add_geo(geo)
44
+ @components << geo
45
+ geo
46
+ end
47
+
38
48
  def paginate(page, per_page, offset = nil)
39
49
  if @pagination
40
50
  @pagination.offset = offset
@@ -64,7 +64,7 @@ module Sunspot
64
64
  params.delete :defType
65
65
  params.delete :fl
66
66
  keywords = params.delete(:q)
67
- options = params.map { |key, value| "#{key}='#{escape_quotes(value)}'"}.join(' ')
67
+ options = params.map { |key, value| escape_param(key, value) }.join(' ')
68
68
  "_query_:\"{!dismax #{options}}#{escape_quotes(keywords)}\""
69
69
  end
70
70
 
@@ -117,6 +117,10 @@ module Sunspot
117
117
 
118
118
 
119
119
  private
120
+
121
+ def escape_param(key, value)
122
+ "#{key}='#{escape_quotes(Array(value).join(" "))}'"
123
+ end
120
124
 
121
125
  def escape_quotes(value)
122
126
  return value unless value.is_a? String
@@ -0,0 +1,35 @@
1
+ module Sunspot
2
+ module Query
3
+ #
4
+ # A FieldGroup groups by the unique values of a given field.
5
+ #
6
+ class FieldGroup
7
+ attr_accessor :limit
8
+
9
+ def initialize(field)
10
+ if field.multiple?
11
+ raise(ArgumentError, "#{field.name} cannot be used for grouping because it is a multiple-value field")
12
+ end
13
+ @field = field
14
+
15
+ @sort = SortComposite.new
16
+ end
17
+
18
+ def add_sort(sort)
19
+ @sort << sort
20
+ end
21
+
22
+ def to_params
23
+ params = {
24
+ :group => "true",
25
+ :"group.field" => @field.indexed_name,
26
+ }
27
+
28
+ params.merge!(@sort.to_params("group."))
29
+ params[:"group.limit"] = @limit if @limit
30
+
31
+ params
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ module Sunspot
2
+ module Query
3
+ class Geofilt
4
+ def initialize(field, lat, lon, radius)
5
+ @field, @lat, @lon, @radius = field, lat, lon, radius
6
+ end
7
+
8
+ def to_params
9
+ filter = "{!geofilt sfield=#{@field.indexed_name} pt=#{@lat},#{@lon} d=#{@radius}}"
10
+
11
+ {:fq => filter}
12
+ end
13
+ end
14
+ end
15
+ end
@@ -90,6 +90,20 @@ module Sunspot
90
90
  "score #{direction_for_solr}"
91
91
  end
92
92
  end
93
+
94
+ #
95
+ # A GeodistSort sorts by distance from a given point.
96
+ #
97
+ class GeodistSort < FieldSort
98
+ def initialize(field, lat, lon, direction)
99
+ @lat, @lon = lat, lon
100
+ super(field, direction)
101
+ end
102
+
103
+ def to_param
104
+ "geodist(#{@field.indexed_name.to_sym},#{@lat},#{@lon}) #{direction_for_solr}"
105
+ end
106
+ end
93
107
  end
94
108
  end
95
109
  end
@@ -21,9 +21,10 @@ module Sunspot
21
21
  #
22
22
  # Combine the sorts into a single param by joining them
23
23
  #
24
- def to_params
24
+ def to_params(prefix = "")
25
25
  unless @sorts.empty?
26
- { :sort => @sorts.map { |sort| sort.to_param } * ', ' }
26
+ key = "#{prefix}sort".to_sym
27
+ { key => @sorts.map { |sort| sort.to_param } * ', ' }
27
28
  else
28
29
  {}
29
30
  end
data/lib/sunspot/query.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  %w(filter abstract_field_facet connective boost_query date_field_facet dismax
2
2
  field_facet highlighting pagination restriction common_query
3
- standard_query more_like_this more_like_this_query geo query_facet scope
3
+ standard_query more_like_this more_like_this_query geo geofilt query_facet scope
4
4
  sort sort_composite text_field_boost function_query
5
- composite_fulltext).each do |file|
5
+ composite_fulltext field_group).each do |file|
6
6
  require(File.join(File.dirname(__FILE__), 'query', file))
7
7
  end
8
8
  module Sunspot
@@ -1,4 +1,5 @@
1
1
  require 'sunspot/search/paginated_collection'
2
+ require 'sunspot/search/hit_enumerable'
2
3
 
3
4
  module Sunspot
4
5
  module Search #:nodoc:
@@ -14,15 +15,21 @@ module Sunspot
14
15
  # Retrieve all facet objects defined for this search, in order they were
15
16
  # defined. To retrieve an individual facet by name, use #facet()
16
17
  #
17
- attr_reader :facets
18
+ attr_reader :facets, :groups
18
19
  attr_reader :query #:nodoc:
19
20
  attr_accessor :request_handler
21
+
22
+ include HitEnumerable
20
23
 
21
24
  def initialize(connection, setup, query, configuration) #:nodoc:
22
25
  @connection, @setup, @query = connection, setup, query
23
26
  @query.paginate(1, configuration.pagination.default_per_page)
27
+
24
28
  @facets = []
25
29
  @facets_by_name = {}
30
+
31
+ @groups_by_name = {}
32
+ @groups = []
26
33
  end
27
34
 
28
35
  #
@@ -78,44 +85,33 @@ module Sunspot
78
85
  #
79
86
  def hits(options = {})
80
87
  if options[:verify]
81
- verified_hits
88
+ super
82
89
  else
83
- @hits ||=
84
- begin
85
- hits = if solr_response && solr_response['docs']
86
- solr_response['docs'].map do |doc|
87
- Hit.new(doc, highlights_for(doc), self)
88
- end
89
- end
90
- paginate_collection(hits || [])
91
- end
90
+ @hits ||= paginate_collection(super)
92
91
  end
93
92
  end
94
93
  alias_method :raw_results, :hits
95
-
94
+
95
+ #
96
+ # The total number of documents matching the query parameters
96
97
  #
97
- # Convenience method to iterate over hit and result objects. Block is
98
- # yielded a Sunspot::Server::Hit instance and a Sunspot::Server::Result
99
- # instance.
98
+ # ==== Returns
100
99
  #
101
- # Note that this method iterates over verified hits (see #hits method
102
- # for more information).
100
+ # Integer:: Total matching documents
103
101
  #
104
- def each_hit_with_result
105
- verified_hits.each do |hit|
106
- yield(hit, hit.result)
107
- end
102
+ def total
103
+ @total ||= solr_response['numFound'] || 0
108
104
  end
109
105
 
110
106
  #
111
- # The total number of documents matching the query parameters
107
+ # The time elapsed to generate the Solr response
112
108
  #
113
109
  # ==== Returns
114
110
  #
115
- # Integer:: Total matching documents
111
+ # Integer:: Query runtime in milliseconds
116
112
  #
117
- def total
118
- @total ||= solr_response['numFound'] || 0
113
+ def query_time
114
+ @query_time ||= solr_response_header['QTime']
119
115
  end
120
116
 
121
117
  #
@@ -167,6 +163,12 @@ module Sunspot
167
163
  end
168
164
  end
169
165
  end
166
+
167
+ def group(name)
168
+ if name
169
+ @groups_by_name[name.to_sym]
170
+ end
171
+ end
170
172
 
171
173
  #
172
174
  # Deprecated in favor of optional second argument to #facet
@@ -178,19 +180,9 @@ module Sunspot
178
180
  def facet_response #:nodoc:
179
181
  @solr_result['facet_counts']
180
182
  end
181
-
182
- #
183
- # Get the data accessor that will be used to load a particular class out of
184
- # persistent storage. Data accessors can implement any methods that may be
185
- # useful for refining how data is loaded out of storage. When building a
186
- # search manually (e.g., using the Sunspot#new_search method), this should
187
- # be used before calling #execute(). Use the
188
- # Sunspot::DSL::Search#data_accessor_for method when building searches using
189
- # the block DSL.
190
- #
191
- def data_accessor_for(clazz) #:nodoc:
192
- (@data_accessors ||= {})[clazz.name.to_sym] ||=
193
- Adapters::DataAccessor.create(clazz)
183
+
184
+ def group_response #:nodoc:
185
+ @solr_result['grouped']
194
186
  end
195
187
 
196
188
  #
@@ -211,31 +203,14 @@ module Sunspot
211
203
  self
212
204
  end
213
205
 
214
- #
215
- # Populate the Hit objects with their instances. This is invoked the first
216
- # time any hit has its instance requested, and all hits are loaded as a
217
- # batch.
218
- #
219
- def populate_hits #:nodoc:
220
- id_hit_hash = Hash.new { |h, k| h[k] = {} }
221
- hits.each do |hit|
222
- id_hit_hash[hit.class_name][hit.primary_key] = hit
223
- end
224
- id_hit_hash.each_pair do |class_name, hits|
225
- ids = hits.map { |id, hit| hit.primary_key }
226
- data_accessor = data_accessor_for(Util.full_const_get(class_name))
227
- hits_for_class = id_hit_hash[class_name]
228
- data_accessor.load_all(ids).each do |result|
229
- hit = hits_for_class.delete(Adapters::InstanceAdapter.adapt(result).id.to_s)
230
- hit.result = result
231
- end
232
- hits_for_class.values.each { |hit| hit.result = nil }
233
- end
234
- end
235
206
 
236
207
  def inspect #:nodoc:
237
208
  "<Sunspot::Search:#{query.to_params.inspect}>"
238
209
  end
210
+
211
+ def add_field_group(field, options = {}) #:nodoc:
212
+ add_group(field.name, FieldGroup.new(field, self, options))
213
+ end
239
214
 
240
215
  def add_field_facet(field, options = {}) #:nodoc:
241
216
  name = (options[:name] || field.name)
@@ -250,6 +225,12 @@ module Sunspot
250
225
  name = (options[:name] || field.name)
251
226
  add_facet(name, DateFacet.new(field, self, options))
252
227
  end
228
+
229
+ def highlights_for(doc) #:nodoc:
230
+ if @solr_result['highlighting']
231
+ @solr_result['highlighting'][doc['id']]
232
+ end
233
+ end
253
234
 
254
235
  private
255
236
 
@@ -265,14 +246,16 @@ module Sunspot
265
246
  @solr_response ||= @solr_result['response'] || {}
266
247
  end
267
248
 
268
- def highlights_for(doc)
269
- if @solr_result['highlighting']
270
- @solr_result['highlighting'][doc['id']]
271
- end
249
+ def solr_response_header
250
+ @solr_response_header ||= @solr_result['responseHeader'] || {}
251
+ end
252
+
253
+ def solr_docs
254
+ solr_response['docs']
272
255
  end
273
256
 
274
257
  def verified_hits
275
- @verified_hits ||= paginate_collection(hits.select { |hit| hit.instance })
258
+ @verified_hits ||= paginate_collection(super)
276
259
  end
277
260
 
278
261
  def paginate_collection(collection)
@@ -283,6 +266,11 @@ module Sunspot
283
266
  @facets << facet
284
267
  @facets_by_name[name.to_sym] = facet
285
268
  end
269
+
270
+ def add_group(name, group)
271
+ @groups << group
272
+ @groups_by_name[name.to_sym] = group
273
+ end
286
274
 
287
275
  # Clear out all the cached ivars so the search can be called again.
288
276
  def reset
@@ -0,0 +1,32 @@
1
+ module Sunspot
2
+ module Search
3
+ class FieldGroup
4
+ def initialize(field, search, options) #:nodoc:
5
+ @field, @search, @options = field, search, options
6
+ end
7
+
8
+ def groups
9
+ @groups ||=
10
+ begin
11
+ if solr_response
12
+ solr_response['groups'].map do |group|
13
+ Group.new(group['groupValue'], group['doclist'], @search)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def matches
20
+ if solr_response
21
+ solr_response['matches'].to_i
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def solr_response
28
+ @search.group_response[@field.indexed_name.to_s]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ require 'sunspot/search/hit_enumerable'
2
+
3
+ module Sunspot
4
+ module Search
5
+ class Group
6
+ attr_reader :value
7
+
8
+ include HitEnumerable
9
+
10
+ def initialize(value, doclist, search)
11
+ @value, @doclist, @search = value, doclist, search
12
+ end
13
+
14
+ def hits(options = {})
15
+ if options[:verify]
16
+ super
17
+ else
18
+ @hits ||= super
19
+ end
20
+ end
21
+
22
+ def verified_hits
23
+ @verified_hits ||= super
24
+ end
25
+
26
+ def highlights_for(doc)
27
+ @search.highlights_for(doc)
28
+ end
29
+
30
+ def solr_docs
31
+ @doclist['docs']
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,72 @@
1
+ module Sunspot
2
+ module Search
3
+ module HitEnumerable #:nodoc:
4
+ def hits(options = {})
5
+ if options[:verify]
6
+ verified_hits
7
+ elsif solr_docs
8
+ solr_docs.map { |d| Hit.new(d, highlights_for(d), self) }
9
+ else
10
+ []
11
+ end
12
+ end
13
+
14
+ def verified_hits
15
+ hits.select { |h| h.result }
16
+ end
17
+
18
+ #
19
+ # Populate the Hit objects with their instances. This is invoked the first
20
+ # time any hit has its instance requested, and all hits are loaded as a
21
+ # batch.
22
+ #
23
+ def populate_hits #:nodoc:
24
+ id_hit_hash = Hash.new { |h, k| h[k] = {} }
25
+ hits.each do |hit|
26
+ id_hit_hash[hit.class_name][hit.primary_key] = hit
27
+ end
28
+ id_hit_hash.each_pair do |class_name, hits|
29
+ ids = hits.map { |id, hit| hit.primary_key }
30
+ data_accessor = data_accessor_for(Util.full_const_get(class_name))
31
+ hits_for_class = id_hit_hash[class_name]
32
+ data_accessor.load_all(ids).each do |result|
33
+ hit = hits_for_class.delete(Adapters::InstanceAdapter.adapt(result).id.to_s)
34
+ hit.result = result
35
+ end
36
+ hits_for_class.values.each { |hit| hit.result = nil }
37
+ end
38
+ end
39
+
40
+ #
41
+ # Convenience method to iterate over hit and result objects. Block is
42
+ # yielded a Sunspot::Server::Hit instance and a Sunspot::Server::Result
43
+ # instance.
44
+ #
45
+ # Note that this method iterates over verified hits (see #hits method
46
+ # for more information).
47
+ #
48
+ def each_hit_with_result
49
+ verified_hits.each do |hit|
50
+ yield(hit, hit.result)
51
+ end
52
+ end
53
+
54
+ #
55
+ # Get the data accessor that will be used to load a particular class out of
56
+ # persistent storage. Data accessors can implement any methods that may be
57
+ # useful for refining how data is loaded out of storage. When building a
58
+ # search manually (e.g., using the Sunspot#new_search method), this should
59
+ # be used before calling #execute(). Use the
60
+ # Sunspot::DSL::Search#data_accessor_for method when building searches using
61
+ # the block DSL.
62
+ #
63
+ def data_accessor_for(clazz) #:nodoc:
64
+ # FIXME: This method does not belong here, but I was getting bogged
65
+ # down trying to figure out where it should go. Punted for now.
66
+ # - AL 27 Nov 2011
67
+ (@data_accessors ||= {})[clazz.name.to_sym] ||=
68
+ Adapters::DataAccessor.create(clazz)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -4,8 +4,10 @@ module Sunspot
4
4
  class PaginatedCollection
5
5
  instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval|object_id/ }
6
6
 
7
- attr_reader :total_count, :current_page, :per_page
7
+ attr_reader :current_page, :per_page
8
+ attr_accessor :total_count
8
9
  alias :total_entries :total_count
10
+ alias :total_entries= :total_count=
9
11
  alias :limit_value :per_page
10
12
 
11
13
  def initialize(collection, page, per_page, total)
@@ -34,12 +36,12 @@ module Sunspot
34
36
 
35
37
  def next_page
36
38
  current_page < total_pages ? (current_page + 1) : nil
37
- end
39
+ end
38
40
 
39
41
  def out_of_bounds?
40
42
  current_page > total_pages
41
43
  end
42
-
44
+
43
45
  def offset
44
46
  (current_page - 1) * per_page
45
47
  end