Permalink
Browse files

Fixed a bug with query construction. Thanks to dstufft for the report!

This goes back to erroring on the side of too many parens, where there weren't enough before. The engines will no-op them when they're not important.
  • Loading branch information...
1 parent ea5dbd5 commit 50eb733f885f482b5fa584fbe99824293f183369 @toastdriven toastdriven committed Mar 1, 2012
View
3 haystack/backends/elasticsearch_backend.py
@@ -726,6 +726,9 @@ def build_query_fragment(self, field, filter_type, value):
query_frag = filter_types[filter_type] % prepared_value
+ if len(query_frag) and not query_frag.startswith('(') and not query_frag.endswith(')'):
+ query_frag = "(%s)" % query_frag
+
return u"%s%s" % (index_fieldname, query_frag)
def build_alt_parser_query(self, parser_name, query_string='', **kwargs):
View
3 haystack/backends/solr_backend.py
@@ -580,6 +580,9 @@ def build_query_fragment(self, field, filter_type, value):
query_frag = filter_types[filter_type] % prepared_value
+ if len(query_frag) and not query_frag.startswith('(') and not query_frag.endswith(')'):
+ query_frag = "(%s)" % query_frag
+
return u"%s%s" % (index_fieldname, query_frag)
def build_alt_parser_query(self, parser_name, query_string='', **kwargs):
View
3 haystack/backends/whoosh_backend.py
@@ -848,6 +848,9 @@ def build_query_fragment(self, field, filter_type, value):
query_frag = filter_types[filter_type] % prepared_value
+ if len(query_frag) and not query_frag.startswith('(') and not query_frag.endswith(')'):
+ query_frag = "(%s)" % query_frag
+
return u"%s%s" % (index_fieldname, query_frag)
View
49 tests/elasticsearch_tests/tests/elasticsearch_backend.py
@@ -8,6 +8,7 @@
from django.test import TestCase
from haystack import connections, connection_router, reset_search_queries
from haystack import indexes
+from haystack.inputs import AutoQuery
from haystack.models import SearchResult
from haystack.query import SearchQuerySet, RelatedSearchQuerySet, SQ
from haystack.utils.loading import UnifiedIndex
@@ -536,16 +537,16 @@ def test_log_query(self):
self.sq.add_filter(SQ(name='bar'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 1)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
# And again, for good measure.
self.sq = connections['default'].query()
self.sq.add_filter(SQ(name='bar'))
self.sq.add_filter(SQ(text='moof'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 2)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
- self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:bar AND text:moof)')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
+ self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:(bar) AND text:(moof))')
# Restore.
settings.DEBUG = old_debug
@@ -668,7 +669,7 @@ def test___and__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'(foo AND bar)')
+ self.assertEqual(sqs.query.build_query(), u'((foo) AND (bar))')
# Now for something more complex...
sqs3 = self.sqs.exclude(title='moof').filter(SQ(content='foo') | SQ(content='baz'))
@@ -677,7 +678,7 @@ def test___and__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 3)
- self.assertEqual(sqs.query.build_query(), u'(NOT (title:moof) AND (foo OR baz) AND bar)')
+ self.assertEqual(sqs.query.build_query(), u'(NOT (title:(moof)) AND ((foo) OR (baz)) AND (bar))')
def test___or__(self):
sqs1 = self.sqs.filter(content='foo')
@@ -686,7 +687,7 @@ def test___or__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'(foo OR bar)')
+ self.assertEqual(sqs.query.build_query(), u'((foo) OR (bar))')
# Now for something more complex...
sqs3 = self.sqs.exclude(title='moof').filter(SQ(content='foo') | SQ(content='baz'))
@@ -695,15 +696,15 @@ def test___or__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'((NOT (title:moof) AND (foo OR baz)) OR bar)')
+ self.assertEqual(sqs.query.build_query(), u'((NOT (title:(moof)) AND ((foo) OR (baz))) OR (bar))')
def test_auto_query(self):
# Ensure bits in exact matches get escaped properly as well.
# This will break horrifically if escaping isn't working.
sqs = self.sqs.auto_query('"pants:rule"')
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND content__contains="pants:rule">')
- self.assertEqual(sqs.query.build_query(), u'"pants\\:rule"')
+ self.assertEqual(sqs.query.build_query(), u'("pants\\:rule")')
self.assertEqual(len(sqs), 0)
# Regressions
@@ -817,50 +818,54 @@ def test_related_cache_is_full(self):
def test_quotes_regression(self):
sqs = self.sqs.auto_query(u"44°48'40''N 20°28'32''E")
# Should not have empty terms.
- self.assertEqual(sqs.query.build_query(), u"44\xb048'40''N 20\xb028'32''E")
+ self.assertEqual(sqs.query.build_query(), u"(44\xb048'40''N 20\xb028'32''E)")
# Should not cause Elasticsearch to 500.
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('blazing')
- self.assertEqual(sqs.query.build_query(), u'blazing')
+ self.assertEqual(sqs.query.build_query(), u'(blazing)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('blazing saddles')
- self.assertEqual(sqs.query.build_query(), u'blazing saddles')
+ self.assertEqual(sqs.query.build_query(), u'(blazing saddles)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles')
- self.assertEqual(sqs.query.build_query(), u'\\"blazing saddles')
+ self.assertEqual(sqs.query.build_query(), u'(\\"blazing saddles)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles"')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles"')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles" \'')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles" \')')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles" \'\\"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles" \'\\")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles" mel')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles" mel')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles" mel)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles" mel brooks')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles" mel brooks')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles" mel brooks)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles" brooks')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles" brooks')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles" brooks)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles" "brooks')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles" \\"brooks')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles" \\"brooks)')
self.assertEqual(sqs.count(), 0)
+ def test_query_generation(self):
+ sqs = self.sqs.filter(SQ(content=AutoQuery("hello world")) | SQ(title=AutoQuery("hello world")))
+ self.assertEqual(sqs.query.build_query(), u"((hello world) OR title:(hello world))")
+
def test_result_class(self):
# Assert that we're defaulting to ``SearchResult``.
sqs = self.sqs.all()
View
36 tests/elasticsearch_tests/tests/elasticsearch_query.py
@@ -17,48 +17,48 @@ def test_build_query_all(self):
def test_build_query_single_word(self):
self.sq.add_filter(SQ(content='hello'))
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
def test_build_query_boolean(self):
self.sq.add_filter(SQ(content=True))
- self.assertEqual(self.sq.build_query(), 'True')
+ self.assertEqual(self.sq.build_query(), '(True)')
def test_build_query_datetime(self):
self.sq.add_filter(SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
- self.assertEqual(self.sq.build_query(), '2009-05-08T11:28:00')
+ self.assertEqual(self.sq.build_query(), '(2009-05-08T11:28:00)')
def test_build_query_multiple_words_and(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_filter(SQ(content='world'))
- self.assertEqual(self.sq.build_query(), '(hello AND world)')
+ self.assertEqual(self.sq.build_query(), '((hello) AND (world))')
def test_build_query_multiple_words_not(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), '(NOT (hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), '(NOT ((hello)) AND NOT ((world)))')
def test_build_query_multiple_words_or(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(SQ(content='hello'), use_or=True)
- self.assertEqual(self.sq.build_query(), '(NOT (hello) OR hello)')
+ self.assertEqual(self.sq.build_query(), '(NOT ((hello)) OR (hello))')
def test_build_query_multiple_words_mixed(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(content='hello'), use_or=True)
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'((why OR hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), u'(((why) OR (hello)) AND NOT ((world)))')
def test_build_query_phrase(self):
self.sq.add_filter(SQ(content='hello world'))
self.assertEqual(self.sq.build_query(), '(hello AND world)')
self.sq.add_filter(SQ(content__exact='hello world'))
- self.assertEqual(self.sq.build_query(), u'((hello AND world) AND "hello world")')
+ self.assertEqual(self.sq.build_query(), u'((hello AND world) AND ("hello world"))')
def test_build_query_boost(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_boost('world', 5)
- self.assertEqual(self.sq.build_query(), "hello world^5")
+ self.assertEqual(self.sq.build_query(), "(hello) world^5")
def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
@@ -68,7 +68,7 @@ def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.sq.add_filter(SQ(rating__range=[3, 5]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:[* TO "2009-02-10 01:59:00"] AND author:{"daniel" TO *} AND created:{* TO "2009-02-12 12:13:00"} AND title:["B" TO *] AND id:("1" OR "2" OR "3") AND rating:["3" TO "5"])')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:([* TO "2009-02-10 01:59:00"]) AND author:({"daniel" TO *}) AND created:({* TO "2009-02-12 12:13:00"}) AND title:(["B" TO *]) AND id:("1" OR "2" OR "3") AND rating:(["3" TO "5"]))')
def test_build_query_multiple_filter_types_with_datetimes(self):
self.sq.add_filter(SQ(content='why'))
@@ -78,27 +78,27 @@ def test_build_query_multiple_filter_types_with_datetimes(self):
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.sq.add_filter(SQ(rating__range=[3, 5]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:[* TO "2009-02-10T01:59:00"] AND author:{"daniel" TO *} AND created:{* TO "2009-02-12T12:13:00"} AND title:["B" TO *] AND id:("1" OR "2" OR "3") AND rating:["3" TO "5"])')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:([* TO "2009-02-10T01:59:00"]) AND author:({"daniel" TO *}) AND created:({* TO "2009-02-12T12:13:00"}) AND title:(["B" TO *]) AND id:("1" OR "2" OR "3") AND rating:(["3" TO "5"]))')
def test_build_query_in_filter_multiple_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article"]))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_in_filter_datetime(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__in=[datetime.datetime(2009, 7, 6, 1, 56, 21)]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:("2009-07-06T01:56:21"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:("2009-07-06T01:56:21"))')
def test_build_query_in_with_set(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=set(["A Famous Paper", "An Infamous Article"])))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_wildcard_filter_types(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__startswith='haystack'))
- self.assertEqual(self.sq.build_query(), u'(why AND title:haystack*)')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:(haystack*))')
def test_clean(self):
self.assertEqual(self.sq.clean('hello world'), 'hello world')
@@ -109,10 +109,10 @@ def test_clean(self):
def test_build_query_with_models(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_model(MockModel)
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
self.sq.add_model(AnotherMockModel)
- self.assertEqual(self.sq.build_query(), u'hello')
+ self.assertEqual(self.sq.build_query(), u'(hello)')
def test_set_result_class(self):
# Assert that we're defaulting to ``SearchResult``.
@@ -132,4 +132,4 @@ class IttyBittyResult(object):
def test_in_filter_values_list(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=MockModel.objects.values_list('id', flat=True)))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("1" OR "2" OR "3"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("1" OR "2" OR "3"))')
View
4 tests/overrides/tests/altered_internal_names.py
@@ -36,10 +36,10 @@ def test_altered_names(self):
sq.add_filter(SQ(content='hello'))
sq.add_model(MockModel)
- self.assertEqual(sq.build_query(), u'hello')
+ self.assertEqual(sq.build_query(), u'(hello)')
sq.add_model(AnotherMockModel)
- self.assertEqual(sq.build_query(), u'hello')
+ self.assertEqual(sq.build_query(), u'(hello)')
def test_solr_schema(self):
command = Command()
View
53 tests/solr_tests/tests/solr_backend.py
@@ -9,6 +9,7 @@
from django.test import TestCase
from haystack import connections, connection_router, reset_search_queries
from haystack import indexes
+from haystack.inputs import AutoQuery
from haystack.models import SearchResult
from haystack.query import SearchQuerySet, RelatedSearchQuerySet, SQ
from haystack.utils.loading import UnifiedIndex
@@ -613,8 +614,8 @@ def tearDown(self):
def test_get_spelling(self):
self.sq.add_filter(SQ(content='Indexy'))
- self.assertEqual(self.sq.get_spelling_suggestion(), u'index')
- self.assertEqual(self.sq.get_spelling_suggestion('indexy'), u'index')
+ self.assertEqual(self.sq.get_spelling_suggestion(), u'(index)')
+ self.assertEqual(self.sq.get_spelling_suggestion('indexy'), u'(index)')
def test_log_query(self):
from django.conf import settings
@@ -634,16 +635,16 @@ def test_log_query(self):
self.sq.add_filter(SQ(name='bar'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 1)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
# And again, for good measure.
self.sq = connections['default'].query()
self.sq.add_filter(SQ(name='bar'))
self.sq.add_filter(SQ(text='moof'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 2)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
- self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:bar AND text:moof)')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
+ self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:(bar) AND text:(moof))')
# Restore.
settings.DEBUG = old_debug
@@ -766,7 +767,7 @@ def test___and__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'(foo AND bar)')
+ self.assertEqual(sqs.query.build_query(), u'((foo) AND (bar))')
# Now for something more complex...
sqs3 = self.sqs.exclude(title='moof').filter(SQ(content='foo') | SQ(content='baz'))
@@ -775,7 +776,7 @@ def test___and__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 3)
- self.assertEqual(sqs.query.build_query(), u'(NOT (title:moof) AND (foo OR baz) AND bar)')
+ self.assertEqual(sqs.query.build_query(), u'(NOT (title:(moof)) AND ((foo) OR (baz)) AND (bar))')
def test___or__(self):
sqs1 = self.sqs.filter(content='foo')
@@ -784,7 +785,7 @@ def test___or__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'(foo OR bar)')
+ self.assertEqual(sqs.query.build_query(), u'((foo) OR (bar))')
# Now for something more complex...
sqs3 = self.sqs.exclude(title='moof').filter(SQ(content='foo') | SQ(content='baz'))
@@ -793,15 +794,15 @@ def test___or__(self):
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(len(sqs.query.query_filter), 2)
- self.assertEqual(sqs.query.build_query(), u'((NOT (title:moof) AND (foo OR baz)) OR bar)')
+ self.assertEqual(sqs.query.build_query(), u'((NOT (title:(moof)) AND ((foo) OR (baz))) OR (bar))')
def test_auto_query(self):
# Ensure bits in exact matches get escaped properly as well.
# This will break horrifically if escaping isn't working.
sqs = self.sqs.auto_query('"pants:rule"')
self.assertTrue(isinstance(sqs, SearchQuerySet))
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND content__contains="pants:rule">')
- self.assertEqual(sqs.query.build_query(), u'"pants\\:rule"')
+ self.assertEqual(sqs.query.build_query(), u'("pants\\:rule")')
self.assertEqual(len(sqs), 0)
# Regressions
@@ -915,50 +916,54 @@ def test_related_cache_is_full(self):
def test_quotes_regression(self):
sqs = self.sqs.auto_query(u"44°48'40''N 20°28'32''E")
# Should not have empty terms.
- self.assertEqual(sqs.query.build_query(), u"44\xb048'40''N 20\xb028'32''E")
+ self.assertEqual(sqs.query.build_query(), u"(44\xb048'40''N 20\xb028'32''E)")
# Should not cause Solr to 500.
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('blazing')
- self.assertEqual(sqs.query.build_query(), u'blazing')
+ self.assertEqual(sqs.query.build_query(), u'(blazing)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('blazing saddles')
- self.assertEqual(sqs.query.build_query(), u'blazing saddles')
+ self.assertEqual(sqs.query.build_query(), u'(blazing saddles)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles')
- self.assertEqual(sqs.query.build_query(), u'\\"blazing saddles')
+ self.assertEqual(sqs.query.build_query(), u'(\\"blazing saddles)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles"')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles"')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles" \'')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles" \')')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing \'\'saddles"\'"')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing \'\'saddles" \'\\"')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing \'\'saddles" \'\\")')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles" mel')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles" mel')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles" mel)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('"blazing saddles" mel brooks')
- self.assertEqual(sqs.query.build_query(), u'"blazing saddles" mel brooks')
+ self.assertEqual(sqs.query.build_query(), u'("blazing saddles" mel brooks)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles" brooks')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles" brooks')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles" brooks)')
self.assertEqual(sqs.count(), 0)
sqs = self.sqs.auto_query('mel "blazing saddles" "brooks')
- self.assertEqual(sqs.query.build_query(), u'mel "blazing saddles" \\"brooks')
+ self.assertEqual(sqs.query.build_query(), u'(mel "blazing saddles" \\"brooks)')
self.assertEqual(sqs.count(), 0)
+ def test_query_generation(self):
+ sqs = self.sqs.filter(SQ(content=AutoQuery("hello world")) | SQ(title=AutoQuery("hello world")))
+ self.assertEqual(sqs.query.build_query(), u"((hello world) OR title:(hello world))")
+
def test_result_class(self):
# Assert that we're defaulting to ``SearchResult``.
sqs = self.sqs.all()
View
38 tests/solr_tests/tests/solr_query.py
@@ -17,52 +17,52 @@ def test_build_query_all(self):
def test_build_query_single_word(self):
self.sq.add_filter(SQ(content='hello'))
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
def test_build_query_boolean(self):
self.sq.add_filter(SQ(content=True))
- self.assertEqual(self.sq.build_query(), 'true')
+ self.assertEqual(self.sq.build_query(), '(true)')
def test_build_query_datetime(self):
self.sq.add_filter(SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
- self.assertEqual(self.sq.build_query(), '2009-05-08T11:28:00Z')
+ self.assertEqual(self.sq.build_query(), '(2009-05-08T11:28:00Z)')
def test_build_query_multiple_words_and(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_filter(SQ(content='world'))
- self.assertEqual(self.sq.build_query(), '(hello AND world)')
+ self.assertEqual(self.sq.build_query(), '((hello) AND (world))')
def test_build_query_multiple_words_not(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), '(NOT (hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), '(NOT ((hello)) AND NOT ((world)))')
def test_build_query_multiple_words_or(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(SQ(content='hello'), use_or=True)
- self.assertEqual(self.sq.build_query(), '(NOT (hello) OR hello)')
+ self.assertEqual(self.sq.build_query(), '(NOT ((hello)) OR (hello))')
def test_build_query_multiple_words_mixed(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(content='hello'), use_or=True)
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'((why OR hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), u'(((why) OR (hello)) AND NOT ((world)))')
def test_build_query_phrase(self):
self.sq.add_filter(SQ(content='hello world'))
self.assertEqual(self.sq.build_query(), '(hello AND world)')
self.sq.add_filter(SQ(content__exact='hello world'))
- self.assertEqual(self.sq.build_query(), u'((hello AND world) AND "hello world")')
+ self.assertEqual(self.sq.build_query(), u'((hello AND world) AND ("hello world"))')
def test_build_query_boost(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_boost('world', 5)
- self.assertEqual(self.sq.build_query(), "hello world^5")
+ self.assertEqual(self.sq.build_query(), "(hello) world^5")
def test_correct_exact(self):
self.sq.add_filter(SQ(content=Exact('hello world')))
- self.assertEqual(self.sq.build_query(), '"hello world"')
+ self.assertEqual(self.sq.build_query(), '("hello world")')
def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
@@ -72,7 +72,7 @@ def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.sq.add_filter(SQ(rating__range=[3, 5]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:[* TO "2009-02-10 01:59:00"] AND author:{"daniel" TO *} AND created:{* TO "2009-02-12 12:13:00"} AND title:["B" TO *] AND id:("1" OR "2" OR "3") AND rating:["3" TO "5"])')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:([* TO "2009-02-10 01:59:00"]) AND author:({"daniel" TO *}) AND created:({* TO "2009-02-12 12:13:00"}) AND title:(["B" TO *]) AND id:("1" OR "2" OR "3") AND rating:(["3" TO "5"]))')
def test_build_query_multiple_filter_types_with_datetimes(self):
self.sq.add_filter(SQ(content='why'))
@@ -82,27 +82,27 @@ def test_build_query_multiple_filter_types_with_datetimes(self):
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.sq.add_filter(SQ(rating__range=[3, 5]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:[* TO "2009-02-10T01:59:00Z"] AND author:{"daniel" TO *} AND created:{* TO "2009-02-12T12:13:00Z"} AND title:["B" TO *] AND id:("1" OR "2" OR "3") AND rating:["3" TO "5"])')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:([* TO "2009-02-10T01:59:00Z"]) AND author:({"daniel" TO *}) AND created:({* TO "2009-02-12T12:13:00Z"}) AND title:(["B" TO *]) AND id:("1" OR "2" OR "3") AND rating:(["3" TO "5"]))')
def test_build_query_in_filter_multiple_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article"]))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_in_filter_datetime(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__in=[datetime.datetime(2009, 7, 6, 1, 56, 21)]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:("2009-07-06T01:56:21Z"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:("2009-07-06T01:56:21Z"))')
def test_build_query_in_with_set(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=set(["A Famous Paper", "An Infamous Article"])))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_wildcard_filter_types(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__startswith='haystack'))
- self.assertEqual(self.sq.build_query(), u'(why AND title:haystack*)')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:(haystack*))')
def test_clean(self):
self.assertEqual(self.sq.clean('hello world'), 'hello world')
@@ -113,10 +113,10 @@ def test_clean(self):
def test_build_query_with_models(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_model(MockModel)
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
self.sq.add_model(AnotherMockModel)
- self.assertEqual(self.sq.build_query(), u'hello')
+ self.assertEqual(self.sq.build_query(), u'(hello)')
def test_set_result_class(self):
# Assert that we're defaulting to ``SearchResult``.
@@ -136,4 +136,4 @@ class IttyBittyResult(object):
def test_in_filter_values_list(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=MockModel.objects.values_list('id', flat=True)))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("1" OR "2" OR "3"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("1" OR "2" OR "3"))')
View
27 tests/whoosh_tests/tests/whoosh_backend.py
@@ -9,6 +9,7 @@
from django.test import TestCase
from haystack import connections, connection_router, reset_search_queries
from haystack import indexes
+from haystack.inputs import AutoQuery
from haystack.models import SearchResult
from haystack.query import SearchQuerySet, SQ
from haystack.utils.loading import UnifiedIndex
@@ -550,16 +551,16 @@ def test_log_query(self):
self.sq.add_filter(SQ(name='bar'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 1)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
# And again, for good measure.
self.sq = connections['default'].get_query()
self.sq.add_filter(SQ(name='baz'))
self.sq.add_filter(SQ(text='foo'))
len(self.sq.get_results())
self.assertEqual(len(connections['default'].queries), 2)
- self.assertEqual(connections['default'].queries[0]['query_string'], 'name:bar')
- self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:baz AND text:foo)')
+ self.assertEqual(connections['default'].queries[0]['query_string'], 'name:(bar)')
+ self.assertEqual(connections['default'].queries[1]['query_string'], u'(name:(baz) AND text:(foo))')
# Restore.
settings.DEBUG = old_debug
@@ -614,35 +615,35 @@ def test_various_searchquerysets(self):
self.sb.update(self.wmmi, self.sample_objs)
sqs = self.sqs.filter(content='Index')
- self.assertEqual(sqs.query.build_query(), u'Index')
+ self.assertEqual(sqs.query.build_query(), u'(Index)')
self.assertEqual(len(sqs), 3)
sqs = self.sqs.auto_query('Indexed!')
- self.assertEqual(sqs.query.build_query(), u"'Indexed!'")
+ self.assertEqual(sqs.query.build_query(), u"('Indexed!')")
self.assertEqual(len(sqs), 3)
sqs = self.sqs.auto_query('Indexed!').filter(pub_date__lte=date(2009, 8, 31))
- self.assertEqual(sqs.query.build_query(), u"('Indexed!' AND pub_date:[to 20090831000000])")
+ self.assertEqual(sqs.query.build_query(), u"(('Indexed!') AND pub_date:([to 20090831000000]))")
self.assertEqual(len(sqs), 3)
sqs = self.sqs.auto_query('Indexed!').filter(pub_date__lte=date(2009, 2, 23))
- self.assertEqual(sqs.query.build_query(), u"('Indexed!' AND pub_date:[to 20090223000000])")
+ self.assertEqual(sqs.query.build_query(), u"(('Indexed!') AND pub_date:([to 20090223000000]))")
self.assertEqual(len(sqs), 2)
sqs = self.sqs.auto_query('Indexed!').filter(pub_date__lte=date(2009, 2, 25)).filter(django_id__in=[1, 2]).exclude(name='daniel1')
- self.assertEqual(sqs.query.build_query(), u"('Indexed!' AND pub_date:[to 20090225000000] AND django_id:(\"1\" OR \"2\") AND NOT (name:daniel1))")
+ self.assertEqual(sqs.query.build_query(), u'((\'Indexed!\') AND pub_date:([to 20090225000000]) AND django_id:("1" OR "2") AND NOT (name:(daniel1)))')
self.assertEqual(len(sqs), 1)
sqs = self.sqs.auto_query('re-inker')
- self.assertEqual(sqs.query.build_query(), u"'re-inker'")
+ self.assertEqual(sqs.query.build_query(), u"('re-inker')")
self.assertEqual(len(sqs), 0)
sqs = self.sqs.auto_query('0.7 wire')
- self.assertEqual(sqs.query.build_query(), u"'0.7' wire")
+ self.assertEqual(sqs.query.build_query(), u"('0.7' wire)")
self.assertEqual(len(sqs), 0)
sqs = self.sqs.auto_query("daler-rowney pearlescent 'bell bronze'")
- self.assertEqual(sqs.query.build_query(), u"'daler-rowney' pearlescent 'bell bronze'")
+ self.assertEqual(sqs.query.build_query(), u"('daler-rowney' pearlescent 'bell bronze')")
self.assertEqual(len(sqs), 0)
sqs = self.sqs.models(MockModel)
@@ -754,6 +755,10 @@ def test_count(self):
self.assertEqual(results._cache_is_full(), False)
self.assertEqual(len(connections['default'].queries), 1)
+ def test_query_generation(self):
+ sqs = self.sqs.filter(SQ(content=AutoQuery("hello world")) | SQ(title=AutoQuery("hello world")))
+ self.assertEqual(sqs.query.build_query(), u"((hello world) OR title:(hello world))")
+
def test_result_class(self):
self.sb.update(self.wmmi, self.sample_objs)
View
36 tests/whoosh_tests/tests/whoosh_query.py
@@ -33,42 +33,42 @@ def test_build_query_all(self):
def test_build_query_single_word(self):
self.sq.add_filter(SQ(content='hello'))
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
def test_build_query_multiple_words_and(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_filter(SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'(hello AND world)')
+ self.assertEqual(self.sq.build_query(), u'((hello) AND (world))')
def test_build_query_multiple_words_not(self):
self.sq.add_filter(~SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'(NOT (hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), u'(NOT ((hello)) AND NOT ((world)))')
def test_build_query_multiple_words_or(self):
self.sq.add_filter(SQ(content='hello') | SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'(hello OR world)')
+ self.assertEqual(self.sq.build_query(), u'((hello) OR (world))')
def test_build_query_multiple_words_mixed(self):
self.sq.add_filter(SQ(content='why') | SQ(content='hello'))
self.sq.add_filter(~SQ(content='world'))
- self.assertEqual(self.sq.build_query(), u'((why OR hello) AND NOT (world))')
+ self.assertEqual(self.sq.build_query(), u'(((why) OR (hello)) AND NOT ((world)))')
def test_build_query_phrase(self):
self.sq.add_filter(SQ(content='hello world'))
self.assertEqual(self.sq.build_query(), u'(hello AND world)')
self.sq.add_filter(SQ(content__exact='hello world'))
- self.assertEqual(self.sq.build_query(), u'((hello AND world) AND "hello world")')
+ self.assertEqual(self.sq.build_query(), u'((hello AND world) AND ("hello world"))')
def test_build_query_boost(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_boost('world', 5)
- self.assertEqual(self.sq.build_query(), "hello world^5")
+ self.assertEqual(self.sq.build_query(), "(hello) world^5")
def test_correct_exact(self):
self.sq.add_filter(SQ(content=Exact('hello world')))
- self.assertEqual(self.sq.build_query(), '"hello world"')
+ self.assertEqual(self.sq.build_query(), '("hello world")')
def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
@@ -78,27 +78,27 @@ def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.sq.add_filter(SQ(rating__range=[3, 5]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:[to 20090210015900] AND author:{daniel to} AND created:{to 20090212121300} AND title:[B to] AND id:("1" OR "2" OR "3") AND rating:[3 to 5])')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:([to 20090210015900]) AND author:({daniel to}) AND created:({to 20090212121300}) AND title:([B to]) AND id:("1" OR "2" OR "3") AND rating:([3 to 5]))')
def test_build_query_in_filter_multiple_words(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article"]))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_in_filter_datetime(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__in=[datetime.datetime(2009, 7, 6, 1, 56, 21)]))
- self.assertEqual(self.sq.build_query(), u'(why AND pub_date:("20090706015621"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND pub_date:("20090706015621"))')
def test_build_query_in_with_set(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=set(["A Famous Paper", "An Infamous Article"])))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("A Famous Paper" OR "An Infamous Article"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("A Famous Paper" OR "An Infamous Article"))')
def test_build_query_wildcard_filter_types(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__startswith='haystack'))
- self.assertEqual(self.sq.build_query(), u'(why AND title:haystack*)')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:(haystack*))')
def test_clean(self):
self.assertEqual(self.sq.clean('hello world'), 'hello world')
@@ -109,18 +109,18 @@ def test_clean(self):
def test_build_query_with_models(self):
self.sq.add_filter(SQ(content='hello'))
self.sq.add_model(MockModel)
- self.assertEqual(self.sq.build_query(), 'hello')
+ self.assertEqual(self.sq.build_query(), '(hello)')
self.sq.add_model(AnotherMockModel)
- self.assertEqual(self.sq.build_query(), u'hello')
+ self.assertEqual(self.sq.build_query(), u'(hello)')
def test_build_query_with_datetime(self):
self.sq.add_filter(SQ(pub_date=datetime.datetime(2009, 5, 9, 16, 20)))
- self.assertEqual(self.sq.build_query(), u'pub_date:20090509162000')
+ self.assertEqual(self.sq.build_query(), u'pub_date:(20090509162000)')
def test_build_query_with_sequence_and_filter_not_in(self):
self.sq.add_filter(SQ(id=[1, 2, 3]))
- self.assertEqual(self.sq.build_query(), u'id:1,2,3')
+ self.assertEqual(self.sq.build_query(), u'id:(1,2,3)')
def test_set_result_class(self):
# Assert that we're defaulting to ``SearchResult``.
@@ -140,4 +140,4 @@ class IttyBittyResult(object):
def test_in_filter_values_list(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(title__in=MockModel.objects.values_list('id', flat=True)))
- self.assertEqual(self.sq.build_query(), u'(why AND title:("1" OR "2" OR "3"))')
+ self.assertEqual(self.sq.build_query(), u'((why) AND title:("1" OR "2" OR "3"))')

0 comments on commit 50eb733

Please sign in to comment.