With the app able to sort couchdb-lucene results in ascending order, it is time to get descending order working. Descending order is only available after the user has previously sorted in ascending order—if the results are currently sorted by title in ascending order, then clicking the title column header again should sort in the opposite direction.
This means that the
sort_link
helper needs access to the current state of the search results. This gives sort_link
an arity of four, requiring: the text of the link, the field on which we are sorting, the query, and, now, the current couchdb-lucene results. My preference would be to cut down on the arity—either deriving the sort field based on the link text or pulling the query from the current results. The former is probably not a good idea—too much coupling. The latter is not an option because the query represented in the results set has stemming applied. If I search on "berries", the results set will represent the search as "berri" (so that recipes containing either "berry" or "berries" can be matched).So I will stick with an arity of 4. After updating my existing
sort_link
specs to supply a fourth argument, it is time to get sort_link
reversing the order.As discovered the other day, applying sort to couchdb-lucene adds a sort attribute to the search result set. For ascending order, the results set will include something like:
"sort_order":[{"field":"sort_date","reverse":false,"type":"string"},For descending order, the results set will look like:
{"reverse":false,"type":"doc"}]
"sort_order":[{"field":"sort_date","reverse":true,"type":"string"},The examples that use results sets with these attributes are as follows:
{"reverse":false,"type":"doc"}]
it "should link in descending order if already sorted on the sort field in ascending order" doThe only differences between the two examples are the value of "reverse" (in the first, it is false/ascending, in the second, it it true/descending) and the expectation that the second will have the back-slash pre-pended on the sort field (which is how one tells couchdb-lucene to reverse sort order).
results = {
"sort_order" => [{ "field" => "sort_foo",
"reverse" => false }]
}
sort_link("Foo", "sort_foo", "query", results).
should have_selector("a",
:href => "/recipes/search?q=query&sort=\\sort_foo")
end
it "should link in ascending order if already sorted on the sort field in descending order" do
results = {
"sort_order" => [{ "field" => "sort_foo",
"reverse" => true }]
}
sort_link("Foo", "sort_foo", "query", results).
should have_selector("a",
:href => "/recipes/search?q=query&sort=sort_foo")
end
With all of the inner specs passing, it is time to move back out to the Cucumber scenario:
cstrom@jaynestown:~/repos/eee-code$ rakeUnfortunately, when I re-run the Cucumber scenario, I find this:
(in /home/cstrom/repos/eee-code)
..........
Finished in 0.098244 seconds
10 examples, 0 failures
.....................
Finished in 0.017578 seconds
21 examples, 0 failures
................................
Finished in 0.179981 seconds
32 examples, 0 failures
cstrom@jaynestown:~/repos/eee-code$ cucumber -n features -s "Sorting (name, date, preparation time, number of ingredients)"It turns out that Webrat really dislikes back-slashes—even when URI-encoded.
Feature: Search for recipes
So that I can find one recipe among many
As a web user
I want to be able search recipes
Scenario: Sorting (name, date, preparation time, number of ingredients)
Given 50 "delicious" recipes with ascending names, dates, preparation times, and number of ingredients
And a 0.5 second wait to allow the search index to be updated
When I search for "delicious"
Then I should see 20 results
When I click the "Name" column header
Then the results should be ordered by name in ascending order
When I click the "Name" column header
bad URI(is not URI?): http://localhost:5984/eee-test/_fti?limit=20&q=delicious&skip=0&sort=\sort_title (URI::InvalidURIError)
/usr/lib/ruby/1.8/uri/common.rb:436:in `split'
/usr/lib/ruby/1.8/uri/common.rb:485:in `parse'
./features/support/../../eee.rb:33:in `GET /recipes/search'
(eval):7:in `get'
features/recipe_search.feature:83:in `When I click the "Name" column header'
I am left with a choice here: change the application to suite the testing framework or not test this particular feature. I think Cucumber / Webrat are valuable enough to warrant changing the application, so back in I go. Instead of passing the back-slash from Sinatra to couchdb-lucene, I will add an
order
query parameter that will cue Sinatra to supply the back-slash to couchdb-lucene.The example for the Sinatra app is:
it "should reverse sort when order=desc is supplied" doTo get this passing, I add the bold text to the
RestClient.stub!(:get).
and_return('{"total_rows":30,"skip":0,"limit":20,"rows":[]}')
RestClient.should_receive(:get).with(/sort=\\/)
get "/recipes/search?q=title:egg&sort=sort_foo&order=desc"
end
/recipe/search
action:get '/recipes/search' doThen I need to teach the helper to produce the
@query = params[:q]
page = params[:page].to_i
skip = (page < 2) ? 0 : ((page - 1) * 20) + 1
couchdb_url = "#{@@db}/_fti?limit=20" +
"&q=#{@query}" +
"&skip=#{skip}"
if params[:sort] =~ /\w/
order = params[:order] =~ /desc/ ? "\\" : ""
couchdb_url += "&sort=#{order}#{params[:sort]}"
end
data = RestClient.get couchdb_url
@results = JSON.parse(data)
if @results['rows'].size == 0 && page > 1
redirect("/recipes/search?q=#{@query}")
return
end
haml :search
end
order
parameter, which is a simple matter of replacing the double back-slashes with "order=desc".Now, it is back out to the feature. To implement the descending sort step, I use:
Then /^the results should be ordered by name in descending order$/ doAnd now I have all of the steps passing up through pagination with sorting:
response.should have_selector("tr:nth-child(2) a",
:content => "delicious recipe 9")
response.should have_selector("tr:nth-child(3) a",
:content => "delicious recipe 8")
end
(commit)
Something to start on tomorrow.
No comments:
Post a Comment