Project: acts_as_ferret
Revision: 351
Author: jk
Date: 09 Jul 2008 05:18:10
Diff at Trac: http://projects.jkraemer.net/acts_as_ferret/changeset/351
Changes:fix sorting bug when using ferret sort along with pagination options
Files:modified: /trunk/demo/test/unit/content_test.rb (
try)
modified: /trunk/plugin/acts_as_ferret/lib/acts_as_ferret.rb (
try)
modified: /trunk/plugin/acts_as_ferret/lib/class_methods.rb (
try)
modified: /trunk/plugin/acts_as_ferret/lib/ferret_find_methods.rb (
try)
added: /trunk/demo/.gitignore (
try)
modified: /trunk/plugin/acts_as_ferret/lib/local_index.rb (
try)
Diff:
| ... | ...@@ -605,6 +605,36 @@ |
| 605 | 605 | assert_equal 3, r.page_count |
| 606 | 606 | end |
| 607 | 607 | |
| 608 | def test_pagination_with_ar_conditions_and_ferret_sort |
| 609 | more_contents |
| 610 | |
| 611 | # r = Content.find_with_ferret 'title', { :page => 1, :per_page => 10, |
| 612 | # :sort => Ferret::Search::SortField.new(:id, |
| 613 | # :type => :integer, |
| 614 | # :reverse => true ) }, |
| 615 | # { :conditions => "description != '0'" } |
| 616 | r = ActsAsFerret::find 'title', Content, { :page => 1, :per_page => 10, |
| 617 | :sort => Ferret::Search::SortField.new(:id, |
| 618 | :type => :integer, |
| 619 | :reverse => true ) }, |
| 620 | { :conditions => "description != '29'" } |
| 621 | assert_equal 29, r.total_hits |
| 622 | assert_equal 10, r.size |
| 623 | assert_equal "28", r.first.description |
| 624 | assert_equal "19", r.last.description |
| 625 | assert_equal 1, r.current_page |
| 626 | assert_equal 3, r.page_count |
| 627 | |
| 628 | r = Content.find_with_ferret 'title', { :page => 3, :per_page => 10 }, |
| 629 | { :conditions => "description != '0'", :order => 'title ASC' } |
| 630 | assert_equal 9, r.size |
| 631 | assert_equal 29, r.total_hits |
| 632 | assert_equal "21", r.first.description |
| 633 | assert_equal "29", r.last.description |
| 634 | assert_equal 3, r.current_page |
| 635 | assert_equal 3, r.page_count |
| 636 | end |
| 637 | |
| 608 | 638 | def test_pagination_with_more_conditions |
| 609 | 639 | more_contents |
| 610 | 640 | |
| ... | ...@@ -299,29 +299,35 @@ |
| 299 | 299 | # maybe put pagination stuff in a module to be included by all index |
| 300 | 300 | # implementations |
| 301 | 301 | models = [ models_or_index_name ] if Class === models_or_index_name |
| 302 | | if models && models.size == 1 |
| 303 | | return models.shift.find_with_ferret query, options, ar_options |
| 304 | | end |
| 302 | # if models && models.size == 1 |
| 303 | # return models.shift.find_with_ferret query, options, ar_options |
| 304 | # end |
| 305 | 305 | index = find_index(models_or_index_name) |
| 306 | 306 | multi = (MultiIndex === index or index.shared?) |
| 307 | 307 | if options[:per_page] |
| 308 | # need pagination |
| 308 | 309 | options[:page] = options[:page] ? options[:page].to_i : 1 |
| 309 | 310 | limit = options[:per_page] |
| 310 | 311 | offset = (options[:page] - 1) * limit |
| 311 | | if ar_options[:conditions] && !multi |
| 312 | |
| 313 | if multi or ((ar_options[:conditions] || ar_options[:order]) && options[:sort]) |
| 314 | # do pagination as the last step after everything has been fetched |
| 315 | options[:late_pagination] = { :limit => limit, :offset => offset } |
| 316 | options[:offset] = nil |
| 317 | options[:limit] = :all |
| 318 | elsif ar_options[:conditions] or ar_options[:order] |
| 319 | # do pagination right in AR call (faster but only works in this case) |
| 312 | 320 | ar_options[:limit] = limit |
| 313 | 321 | ar_options[:offset] = offset |
| 314 | 322 | options[:limit] = :all |
| 315 | 323 | options.delete :offset |
| 316 | 324 | else |
| 317 | | # do pagination with ferret (or after everything is done in the case |
| 318 | | # of multi_search) |
| 319 | 325 | options[:limit] = limit |
| 320 | 326 | options[:offset] = offset |
| 321 | 327 | end |
| 322 | 328 | elsif ar_options[:conditions] |
| 323 | 329 | if multi |
| 324 | | # multisearch ignores ar_options limit and offset |
| 330 | # multisearch does not use ar_options limit and offset directly but applies them later |
| 325 | 331 | options[:limit] ||= ar_options.delete(:limit) |
| 326 | 332 | options[:offset] ||= ar_options.delete(:offset) |
| 327 | 333 | else |
| ... | ...@@ -333,9 +339,9 @@ |
| 333 | 339 | options[:limit] = :all |
| 334 | 340 | end |
| 335 | 341 | end |
| 336 | | |
| 342 | ActsAsFerret::logger.debug "$$$$$$$$$ options: #{options.inspect}\nar_options: #{ar_options.inspect}" |
| 337 | 343 | total_hits, result = index.find_records query, options.merge(:models => models), ar_options |
| 338 | | logger.debug "Query: #{query}\ntotal hits: #{total_hits}, results delivered: #{result.size}" |
| 344 | ActsAsFerret::logger.debug "Query: #{query}\ntotal hits: #{total_hits}, results delivered: #{result.size}" |
| 339 | 345 | SearchResults.new(result, total_hits, options[:page], options[:per_page]) |
| 340 | 346 | end |
| 341 | 347 | |
| ... | ...@@ -152,30 +152,7 @@ |
| 152 | 152 | find_options[:conditions] = scope(:find, :conditions) |
| 153 | 153 | end |
| 154 | 154 | end |
| 155 | | |
| 156 | | if options[:per_page] |
| 157 | | options[:page] = options[:page] ? options[:page].to_i : 1 |
| 158 | | limit = options[:per_page] |
| 159 | | offset = (options[:page] - 1) * limit |
| 160 | | if find_options[:conditions] |
| 161 | | find_options[:limit] = limit |
| 162 | | find_options[:offset] = offset |
| 163 | | options[:limit] = :all |
| 164 | | options.delete :offset |
| 165 | | else |
| 166 | | # do pagination with ferret |
| 167 | | options[:limit] = limit |
| 168 | | options[:offset] = offset |
| 169 | | end |
| 170 | | elsif find_options[:conditions] |
| 171 | | find_options[:limit] ||= options.delete(:limit) unless options[:limit] == :all |
| 172 | | find_options[:offset] ||= options.delete(:offset) |
| 173 | | options[:limit] = :all |
| 174 | | end |
| 175 | | |
| 176 | | total_hits, result = aaf_index.find_records q, options.merge(:models => [self]), find_options |
| 177 | | logger.debug "Query: #{q}\ntotal hits: #{total_hits}, results delivered: #{result.size}" |
| 178 | | SearchResults.new(result, total_hits, options[:page], options[:per_page]) |
| 155 | return ActsAsFerret::find q, self, options, find_options |
| 179 | 156 | end |
| 180 | 157 | |
| 181 | 158 | |
| ... | ...@@ -4,12 +4,19 @@ |
| 4 | 4 | module FerretFindMethods |
| 5 | 5 | |
| 6 | 6 | def find_records(q, options = {}, ar_options = {}) |
| 7 | | if options[:lazy] |
| 7 | late_pagination = options.delete :late_pagination |
| 8 | total_hits, result = if options[:lazy] |
| 8 | 9 | logger.warn "find_options #{ar_options} are ignored because :lazy => true" unless ar_options.empty? |
| 9 | 10 | lazy_find q, options |
| 10 | 11 | else |
| 11 | 12 | ar_find q, options, ar_options |
| 12 | 13 | end |
| 14 | if late_pagination |
| 15 | limit = late_pagination[:limit] |
| 16 | offset = late_pagination[:offset] |
| 17 | result = result[offset..limit+offset-1] |
| 18 | end |
| 19 | return [total_hits, result] |
| 13 | 20 | end |
| 14 | 21 | |
| 15 | 22 | def lazy_find(q, options = {}) |
| ... | ...@@ -24,8 +31,15 @@ |
| 24 | 31 | end |
| 25 | 32 | |
| 26 | 33 | def ar_find(q, options = {}, ar_options = {}) |
| 27 | | total_hits, id_arrays = find_id_model_arrays q, options |
| 34 | ferret_options = options.dup |
| 35 | if ar_options[:conditions] or ar_options[:order] |
| 36 | ferret_options[:limit] = :all |
| 37 | ferret_options.delete :offset |
| 38 | end |
| 39 | total_hits, id_arrays = find_id_model_arrays q, ferret_options |
| 40 | logger.debug "now retrieving records from AR with options: #{ar_options.inspect}" |
| 28 | 41 | result = ActsAsFerret::retrieve_records(id_arrays, ar_options) |
| 42 | logger.debug "#{result.size} results from AR: #{result.inspect}" |
| 29 | 43 | |
| 30 | 44 | # count total_hits via sql when using conditions, multiple models, or when we're called |
| 31 | 45 | # from an ActiveRecord association. |
| ... | ...@@ -158,7 +158,8 @@ |
| 158 | 158 | end |
| 159 | 159 | |
| 160 | 160 | |
| 161 | | |
| 161 | # retrieves stored fields from index definition in case the fields to retrieve |
| 162 | # haven't been specified with the :lazy option |
| 162 | 163 | def determine_stored_fields(options = {}) |
| 163 | 164 | stored_fields = options[:lazy] |
| 164 | 165 | if stored_fields && !(Array === stored_fields) |
| ... | ...@@ -170,15 +171,17 @@ |
| 170 | 171 | |
| 171 | 172 | # loads data for fields declared as :lazy from the Ferret document |
| 172 | 173 | def extract_stored_fields(doc, stored_fields) |
| 173 | | fields = index_definition[:ferret_fields] |
| 174 | 174 | data = {} |
| 175 | | logger.debug "extracting stored fields #{stored_fields.inspect} from document #{doc[:class_name]} / #{doc[:id]}" |
| 176 | | stored_fields.each do |field| |
| 177 | | if field_cfg = fields[field] |
| 178 | | data[field_cfg[:via]] = doc[field] |
| 175 | unless stored_fields.nil? |
| 176 | logger.debug "extracting stored fields #{stored_fields.inspect} from document #{doc[:class_name]} / #{doc[:id]}" |
| 177 | fields = index_definition[:ferret_fields] |
| 178 | stored_fields.each do |field| |
| 179 | if field_cfg = fields[field] |
| 180 | data[field_cfg[:via]] = doc[field] |
| 181 | end |
| 179 | 182 | end |
| 180 | | end if stored_fields |
| 181 | | logger.debug "done: #{data.inspect}" |
| 183 | logger.debug "done: #{data.inspect}" |
| 184 | end |
| 182 | 185 | return data |
| 183 | 186 | end |
| 184 | 187 | |
To list