sunspot 1.3.3 → 2.0.0.pre.111215

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