Skip to content

Commit bb04d0c

Browse files
committed
BACKWARD-INCOMPATIBLE: auto_query has changed so that only double quotes cause exact match searches. Thanks to craigds for the report!
1 parent 180e36a commit bb04d0c

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

haystack/query.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -346,21 +346,24 @@ def auto_query(self, query_string):
346346
clone = self._clone()
347347

348348
# Pull out anything wrapped in quotes and do an exact match on it.
349-
quote_regex = re.compile(r'([\'"])(.*?)\1')
350-
result = quote_regex.search(query_string)
351-
352-
while result is not None:
353-
full_match = result.group()
354-
query_string = query_string.replace(full_match, '', 1)
355-
356-
exact_match = result.groups()[1]
357-
clone = clone.filter(content=clone.query.clean(exact_match))
358-
359-
# Re-search the string for other exact matches.
360-
result = quote_regex.search(query_string)
349+
open_quote_position = None
350+
non_exact_query = query_string
351+
352+
for offset, char in enumerate(query_string):
353+
if char == '"':
354+
if open_quote_position != None:
355+
current_match = non_exact_query[open_quote_position + 1:offset]
356+
357+
if current_match:
358+
clone = clone.filter(content=clone.query.clean(current_match))
359+
360+
non_exact_query = non_exact_query.replace('"%s"' % current_match, '', 1)
361+
open_quote_position = None
362+
else:
363+
open_quote_position = offset
361364

362365
# Pseudo-tokenize the rest of the query.
363-
keywords = query_string.split()
366+
keywords = non_exact_query.split()
364367

365368
# Loop through keywords and add filters to the query.
366369
for keyword in keywords:

tests/core/tests/query.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,11 +507,11 @@ def test_auto_query(self):
507507

508508
sqs = self.bsqs.auto_query('test "my thing" search \'moar quotes\' -stuff')
509509
self.assert_(isinstance(sqs, SearchQuerySet))
510-
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND (content__exact=my thing AND content__exact=moar quotes AND content__exact=test AND content__exact=search AND NOT (content__exact=stuff))>')
510+
self.assertEqual(repr(sqs.query.query_filter), "<SQ: AND (content__exact=my thing AND content__exact=test AND content__exact=search AND content__exact='moar AND content__exact=quotes' AND NOT (content__exact=stuff))>")
511511

512512
sqs = self.bsqs.auto_query('test "my thing" search \'moar quotes\' "foo -stuff')
513513
self.assert_(isinstance(sqs, SearchQuerySet))
514-
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND (content__exact=my thing AND content__exact=moar quotes AND content__exact=test AND content__exact=search AND content__exact="foo AND NOT (content__exact=stuff))>')
514+
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND (content__exact=my thing AND content__exact=test AND content__exact=search AND content__exact=\'moar AND content__exact=quotes\' AND content__exact="foo AND NOT (content__exact=stuff))>')
515515

516516
sqs = self.bsqs.auto_query('test - stuff')
517517
self.assert_(isinstance(sqs, SearchQuerySet))

tests/solr_tests/tests/solr_backend.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
import datetime
23
import logging
34
import pysolr
@@ -829,6 +830,53 @@ def test_related_cache_is_full(self):
829830
fire_the_iterator_and_fill_cache = [result for result in results]
830831
self.assertEqual(results._cache_is_full(), True)
831832
self.assertEqual(len(backends.queries), 5)
833+
834+
def test_quotes_regression(self):
835+
sqs = self.sqs.auto_query("44°48'40''N 20°28'32''E")
836+
# Should not have empty terms.
837+
self.assertEqual(sqs.query.build_query(), u"(44\ufffd\ufffd48'40''N AND 20\ufffd\ufffd28'32''E)")
838+
# Should not cause Solr to 500.
839+
self.assertEqual(sqs.count(), 0)
840+
841+
sqs = self.sqs.auto_query('blazing')
842+
self.assertEqual(sqs.query.build_query(), u'blazing')
843+
self.assertEqual(sqs.count(), 0)
844+
sqs = self.sqs.auto_query('blazing saddles')
845+
self.assertEqual(sqs.query.build_query(), u'(blazing AND saddles)')
846+
self.assertEqual(sqs.count(), 0)
847+
sqs = self.sqs.auto_query('"blazing saddles')
848+
self.assertEqual(sqs.query.build_query(), u'(\\"blazing AND saddles)')
849+
self.assertEqual(sqs.count(), 0)
850+
sqs = self.sqs.auto_query('"blazing saddles"')
851+
self.assertEqual(sqs.query.build_query(), u'"blazing saddles"')
852+
self.assertEqual(sqs.count(), 0)
853+
sqs = self.sqs.auto_query('mel "blazing saddles"')
854+
self.assertEqual(sqs.query.build_query(), u'("blazing saddles" AND mel)')
855+
self.assertEqual(sqs.count(), 0)
856+
sqs = self.sqs.auto_query('mel "blazing \'saddles"')
857+
self.assertEqual(sqs.query.build_query(), u'("blazing \'saddles" AND mel)')
858+
self.assertEqual(sqs.count(), 0)
859+
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"')
860+
self.assertEqual(sqs.query.build_query(), u'("blazing \'\'saddles" AND mel)')
861+
self.assertEqual(sqs.count(), 0)
862+
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'')
863+
self.assertEqual(sqs.query.build_query(), u'("blazing \'\'saddles" AND mel AND \')')
864+
self.assertEqual(sqs.count(), 0)
865+
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'"')
866+
self.assertEqual(sqs.query.build_query(), u'("blazing \'\'saddles" AND mel AND \'\\")')
867+
self.assertEqual(sqs.count(), 0)
868+
sqs = self.sqs.auto_query('"blazing saddles" mel')
869+
self.assertEqual(sqs.query.build_query(), u'("blazing saddles" AND mel)')
870+
self.assertEqual(sqs.count(), 0)
871+
sqs = self.sqs.auto_query('"blazing saddles" mel brooks')
872+
self.assertEqual(sqs.query.build_query(), u'("blazing saddles" AND mel AND brooks)')
873+
self.assertEqual(sqs.count(), 0)
874+
sqs = self.sqs.auto_query('mel "blazing saddles" brooks')
875+
self.assertEqual(sqs.query.build_query(), u'("blazing saddles" AND mel AND brooks)')
876+
self.assertEqual(sqs.count(), 0)
877+
sqs = self.sqs.auto_query('mel "blazing saddles" "brooks')
878+
self.assertEqual(sqs.query.build_query(), u'("blazing saddles" AND mel AND \\"brooks)')
879+
self.assertEqual(sqs.count(), 0)
832880

833881

834882
class LiveSolrMoreLikeThisTestCase(TestCase):

tests/whoosh_tests/tests/whoosh_backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ def test_various_searchquerysets(self):
488488
self.assertEqual(len(sqs), 0)
489489

490490
sqs = self.sqs.auto_query("daler-rowney pearlescent 'bell bronze'")
491-
self.assertEqual(sqs.query.build_query(), u"(\"bell bronze\" AND 'daler-rowney' AND pearlescent)")
491+
self.assertEqual(sqs.query.build_query(), u"('daler-rowney' AND pearlescent AND 'bell AND bronze')")
492492
self.assertEqual(len(sqs), 0)
493493

494494
sqs = self.sqs.models(MockModel)

0 commit comments

Comments
 (0)