diff --git a/api/search.rb b/api/search.rb index 0ab1e68..c751895 100644 --- a/api/search.rb +++ b/api/search.rb @@ -37,29 +37,17 @@ get "#{APIPREFIX}/search/threads" do results = CommentThread.perform_search(params, options.merge(page: results.total_pages)) end - threads = CommentThread.where(id: {"$in" => results.map {|r| r.id} }).to_a - if threads.length == 0 + if results.length == 0 collection = [] else - pres_threads = ThreadPresenter.new( - threads, + pres_threads = ThreadSearchResultPresenter.new( + results, params[:user_id] ? user : nil, - params[:course_id] || threads.first.course_id + params[:course_id] || results.first.course_id ) collection = pres_threads.to_hash_array(bool_recursive) end - # merge highlighted text / highlighted body. not sure if this is used by the client, - # but doing it to preserve the legacy behavior - # TODO: move this logic into a presenter object for search results - result_map = Hash[results.map { |t| [t.id, t] }] - collection.each do |thread_hash| - thread_key = thread_hash["id"].to_s - highlight = result_map[thread_key].highlight || {} - thread_hash["highlighted_body"] = (highlight[:body] || []).first || thread_hash["body"] - thread_hash["highlighted_title"] = (highlight[:title] || []).first || thread_hash["title"] - end - num_pages = results.total_pages page = [num_pages, [1, page].max].min { diff --git a/presenters/thread_search_result.rb b/presenters/thread_search_result.rb new file mode 100644 index 0000000..f8b2f66 --- /dev/null +++ b/presenters/thread_search_result.rb @@ -0,0 +1,23 @@ +require_relative 'thread' + +class ThreadSearchResultPresenter < ThreadPresenter + + alias :super_to_hash :to_hash + + def initialize(search_results, user, course_id) + @search_result_map = Hash[search_results.map { |t| [t.id, t] }] + threads = CommentThread.where(id: {"$in" => @search_result_map.keys}).to_a + # reorder fetched threads to match the original result order + threads = Hash[threads.map { |t| [t._id.to_s, t] }].values_at *search_results.map { |t| t.id } + super(threads, user, course_id) + end + + def to_hash(thread, with_comments=false) + thread_hash = super_to_hash(thread, with_comments) + highlight = @search_result_map[thread.id.to_s].highlight || {} + thread_hash["highlighted_body"] = (highlight[:body] || []).first || thread_hash["body"] + thread_hash["highlighted_title"] = (highlight[:title] || []).first || thread_hash["title"] + thread_hash + end + +end diff --git a/spec/presenters/thread_search_result_spec.rb b/spec/presenters/thread_search_result_spec.rb new file mode 100644 index 0000000..f7da86d --- /dev/null +++ b/spec/presenters/thread_search_result_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe ThreadSearchResultPresenter do + context "#to_hash" do + + before(:each) { setup_10_threads } + + # NOTE: throrough coverage of search result hash structure is presently provided in spec/api/search_spec + def check_search_result_hash(search_result, hash) + hash["highlighted_body"].should == ((search_result.highlight[:body] || []).first || hash["body"]) + hash["highlighted_title"].should == ((search_result.highlight[:title] || []).first || hash["title"]) + end + + def check_search_results_hash_array(search_results, hashes) + expected_order = search_results.map {|t| t.id} + actual_order = hashes.map {|h| h["id"].to_s} + actual_order.should == expected_order + hashes.each_with_index { |hash, i| check_search_result_hash(search_results[i], hash) } + end + + it "presents search results in correct order" do + threads_random_order = @threads.values.shuffle + mock_results = threads_random_order.map do |t| + double(Tire::Results::Item, :id => t._id.to_s, :highlight => {:body => ["foo"], :title => ["bar"]}) + end + pres = ThreadSearchResultPresenter.new(mock_results, nil, DFLT_COURSE_ID) + check_search_results_hash_array(mock_results, pres.to_hash_array) + end + + it "presents search results with correct default highlights" do + threads_random_order = @threads.values.shuffle + mock_results = threads_random_order.map do |t| + double(Tire::Results::Item, :id => t._id.to_s, :highlight => {}) + end + pres = ThreadSearchResultPresenter.new(mock_results, nil, DFLT_COURSE_ID) + check_search_results_hash_array(mock_results, pres.to_hash_array) + end + + end +end