aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeb Bacon <seb.bacon@gmail.com>2012-01-17 12:50:30 +0000
committerSeb Bacon <seb.bacon@gmail.com>2012-01-17 12:53:52 +0000
commitc8a68219c541840b5c5f56cd75c1e84de6c15fe5 (patch)
tree9b1f062ba77a19b63c09a90710004959465c470b
parent3b0222d887e2ef1bd508e505b2327f8c2acac1d3 (diff)
Actually do a proper ORed and partial match query, rather than fix parsing errors ad hoc as I find them that result from the workaround code. Fixes #328 (for good, I hope).
-rw-r--r--app/controllers/application_controller.rb28
-rw-r--r--spec/controllers/request_controller_spec.rb14
-rw-r--r--vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb15
3 files changed, 39 insertions, 18 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f6068120d..0c8544932 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -366,23 +366,31 @@ class ApplicationController < ActionController::Base
return (params[:page] || "1").to_i
end
def perform_search_typeahead(query, model)
- # strip out unintended search operators - see
- # https://github.com/sebbacon/alaveteli/issues/328
- # XXX this is a result of the OR hack below -- should fix by
- # allowing a parameter to perform_search to control the
- # default operator!
- query = query.strip.gsub(/(\s-\s|&|\(|\))/, "")
- query = query.split(/ +(?![-+]+)/)
- if query.last.nil? || query.last.strip.length < 3
+ query_words = query.split(/ +(?![-+]+)/)
+ if query_words.last.nil? || query_words.last.strip.length < 3
xapian_requests = nil
else
- query = query.join(' OR ') # XXX: HACK for OR instead of default AND!
if model == PublicBody
collapse = nil
elsif model == InfoRequestEvent
collapse = 'request_collapse'
end
- xapian_requests = perform_search([model], query, 'relevant', collapse, 5)
+ options = {
+ :offset => 0,
+ :limit => 5,
+ :sort_by_prefix => nil,
+ :sort_by_ascending => true,
+ :collapse_by_prefix => collapse,
+ }
+ ActsAsXapian.readable_init
+ old_default_op = ActsAsXapian.query_parser.default_op
+ ActsAsXapian.query_parser.default_op = Xapian::Query::OP_OR
+ user_query = ActsAsXapian.query_parser.parse_query(
+ query,
+ Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_PARTIAL |
+ Xapian::QueryParser::FLAG_SPELLING_CORRECTION)
+ xapian_requests = ActsAsXapian::Search.new([model], query, options, user_query)
+ ActsAsXapian.query_parser.default_op = old_default_op
end
return xapian_requests
end
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 40cb168f4..dcdacc29c 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -450,7 +450,9 @@ describe RequestController, "when searching for an authority" do
"Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ",
"Bellevue Road Ryde Isle of Wight PO33 2AR - what is the",
"NHS Ayrshire & Arran",
- " cardiff"]
+ " cardiff",
+ "Foo * bax",
+ "qux ~ quux"]
lambda {
get :select_authority, :query => phrase
}.should_not raise_error(StandardError)
@@ -1518,12 +1520,20 @@ describe RequestController, "when doing type ahead searches" do
assigns[:xapian_requests].should be_nil
end
+ it "should do partial matches for longer words" do
+ get :search_typeahead, :q => "chick"
+ response.should render_template('request/_search_ahead.rhtml')
+ assigns[:xapian_requests].results.size.should ==1
+ end
+
it "should not give an error when user users unintended search operators" do
for phrase in ["Marketing/PR activities - Aldborough E-Act Free Schoo",
"Request for communications between DCMS/Ed Vaizey and ICO from Jan 1st 2011 - May ",
"Bellevue Road Ryde Isle of Wight PO33 2AR - what is the",
"NHS Ayrshire & Arran",
- "uda ( units of dent"]
+ "uda ( units of dent",
+ "frob * baz",
+ "bar ~ qux"]
lambda {
get :search_typeahead, :q => phrase
}.should_not raise_error(StandardError)
diff --git a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
index 45e412e0e..38bfb7c98 100644
--- a/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
+++ b/vendor/plugins/acts_as_xapian/lib/acts_as_xapian.rb
@@ -274,7 +274,7 @@ module ActsAsXapian
ActsAsXapian.enquire.sort_by_relevance!
else
value = ActsAsXapian.values_by_prefix[sort_by_prefix]
- raise "couldn't find prefix '" + sort_by_prefix + "'" if value.nil?
+ raise "couldn't find prefix '" + sort_by_prefix.to_s + "'" if value.nil?
ActsAsXapian.enquire.sort_by_value_then_relevance!(value, sort_by_ascending)
end
if collapse_by_prefix.nil?
@@ -420,7 +420,7 @@ module ActsAsXapian
# User]. Can take a single model class, or you can express the model
# class names in strings if you like.
# query_string - user inputed query string, with syntax much like Google Search
- def initialize(model_classes, query_string, options = {})
+ def initialize(model_classes, query_string, options = {}, user_query = nil)
# Check parameters, convert to actual array of model classes
new_model_classes = []
model_classes = [model_classes] if model_classes.class != Array
@@ -439,10 +439,13 @@ module ActsAsXapian
# Construct query which only finds things from specified models
model_query = Xapian::Query.new(Xapian::Query::OP_OR, model_classes.map{|mc| "M" + mc.to_s})
- user_query = ActsAsXapian.query_parser.parse_query(self.query_string,
- Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE |
- Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD |
- Xapian::QueryParser::FLAG_SPELLING_CORRECTION)
+ if user_query.nil?
+ user_query = ActsAsXapian.query_parser.parse_query(
+ self.query_string,
+ Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_PHRASE |
+ Xapian::QueryParser::FLAG_LOVEHATE | Xapian::QueryParser::FLAG_WILDCARD |
+ Xapian::QueryParser::FLAG_SPELLING_CORRECTION)
+ end
self.query = Xapian::Query.new(Xapian::Query::OP_AND, model_query, user_query)
# Call base class constructor