Started work in refactor

This commit is contained in:
David Sauve 2009-10-21 08:41:27 -04:00
parent ad6b86e1da
commit 45a6883028
3 changed files with 82 additions and 106 deletions

View file

@ -18,4 +18,4 @@ import warnings
warnings.simplefilter('ignore', Warning)
from xapian_tests.tests.xapian_query import *
from xapian_tests.tests.xapian_backend import *
# from xapian_tests.tests.xapian_backend import *

View file

@ -50,78 +50,78 @@ class XapianSearchQueryTestCase(TestCase):
super(XapianSearchQueryTestCase, self).tearDown()
def test_build_query_all(self):
self.assertEqual(self.sq.build_query(), '*')
self.assertEqual(self.sq.build_query().get_description(), 'Xapian::Query(<alldocuments>)')
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().get_description(), 'Xapian::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(), '(hello AND world)')
self.assertEqual(self.sq.build_query().get_description(), 'Xapian::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))')
def test_build_query_multiple_words_or(self):
self.sq.add_filter(SQ(content='hello'), use_or=True)
self.sq.add_filter(SQ(content='world'), use_or=True)
self.assertEqual(self.sq.build_query(), '(hello OR world)')
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(), '((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 world"')
def test_build_query_multiple_filter_types(self):
self.sq.add_filter(SQ(content='why'))
self.sq.add_filter(SQ(pub_date__lte=datetime.datetime(2009, 2, 10, 1, 59)))
self.sq.add_filter(SQ(author__gt='david'))
self.sq.add_filter(SQ(created__lt=datetime.datetime(2009, 2, 12, 12, 13)))
self.sq.add_filter(SQ(title__gte='B'))
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
self.assertEqual(self.sq.build_query(), '(why AND pub_date:..20090210015900 AND NOT author:..david AND NOT created:20090212121300..* AND title:B..* AND (id:1 OR id:2 OR id:3))')
def test_build_query_multiple_exclude_types(self):
self.sq.add_filter(~SQ(content='why'))
self.sq.add_filter(~SQ(pub_date__lte=datetime.datetime(2009, 2, 10, 1, 59)))
self.sq.add_filter(~SQ(author__gt='david'))
self.sq.add_filter(~SQ(created__lt=datetime.datetime(2009, 2, 12, 12, 13)))
self.sq.add_filter(~SQ(title__gte='B'))
self.sq.add_filter(~SQ(id__in=[1, 2, 3]))
self.assertEqual(self.sq.build_query(), '(NOT (why) AND NOT (pub_date:..20090210015900) AND NOT (NOT author:..david) AND NOT (NOT created:20090212121300..*) AND NOT (title:B..*) AND NOT ((id:1 OR id:2 OR id:3)))')
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(), '(why AND title:haystack*)')
def test_clean(self):
self.assertEqual(self.sq.clean('hello world'), 'hello world')
self.assertEqual(self.sq.clean('hello AND world'), 'hello and world')
self.assertEqual(self.sq.clean('hello AND OR NOT + - && || ! ( ) { } [ ] ^ " ~ * ? : \ world'), 'hello and or not \\+ \\- \\&& \\|| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\" \\~ \\* \\? \\: \\\\ world')
self.assertEqual(self.sq.clean('so please NOTe i am in a bAND and bORed'), 'so please NOTe i am in a bAND and bORed')
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(), u'(hello) AND (django_ct:core.mockmodel)')
self.sq.add_model(AnotherMockModel)
self.assertEqual(self.sq.build_query(), u'(hello) AND (django_ct:core.anothermockmodel OR django_ct:core.mockmodel)')
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')
def test_build_query_with_sequence_and_filter_not_in(self):
self.sq.add_filter(SQ(id__exact=[1, 2, 3]))
self.assertEqual(self.sq.build_query(), u'id:[1, 2, 3]')
self.assertEqual(self.sq.build_query().get_description(), 'Xapian::Query((NOT hello NOT world))')
# def test_build_query_multiple_words_or(self):
# self.sq.add_filter('content', 'hello', use_or=True)
# self.sq.add_filter('content', 'world', use_or=True)
# self.assertEqual(self.sq.build_query(), 'hello OR world')
#
# def test_build_query_multiple_words_mixed(self):
# self.sq.add_filter('content', 'why')
# self.sq.add_filter('content', 'hello', use_or=True)
# self.sq.add_filter('content', 'world', use_not=True)
# self.assertEqual(self.sq.build_query(), 'why OR hello NOT world')
#
# def test_build_query_phrase(self):
# self.sq.add_filter('content', 'hello world')
# self.assertEqual(self.sq.build_query(), '"hello world"')
#
# def test_build_query_multiple_filter_types(self):
# self.sq.add_filter('content', 'why')
# self.sq.add_filter('pub_date__lte', datetime.datetime(2009, 2, 10, 1, 59))
# self.sq.add_filter('author__gt', 'david')
# self.sq.add_filter('created__lt', datetime.datetime(2009, 2, 12, 12, 13))
# self.sq.add_filter('title__gte', 'B')
# self.sq.add_filter('id__in', [1, 2, 3])
# self.assertEqual(self.sq.build_query(), 'why AND pub_date:..20090210015900 AND NOT author:..david AND NOT created:20090212121300..* AND title:B..* AND (id:1 OR id:2 OR id:3)')
#
# def test_build_query_multiple_exclude_types(self):
# self.sq.add_filter('content', 'why', use_not=True)
# self.sq.add_filter('pub_date__lte', datetime.datetime(2009, 2, 10, 1, 59), use_not=True)
# self.sq.add_filter('author__gt', 'david', use_not=True)
# self.sq.add_filter('created__lt', datetime.datetime(2009, 2, 12, 12, 13), use_not=True)
# self.sq.add_filter('title__gte', 'B', use_not=True)
# self.sq.add_filter('id__in', [1, 2, 3], use_not=True)
# self.assertEqual(self.sq.build_query(), 'NOT why AND NOT pub_date:..20090210015900 AND author:..david AND created:20090212121300..* AND NOT title:B..* AND NOT id:1 NOT id:2 NOT id:3')
#
# def test_build_query_wildcard_filter_types(self):
# self.sq.add_filter('content', 'why')
# self.sq.add_filter('title__startswith', 'haystack')
# self.assertEqual(self.sq.build_query(), 'why AND title:haystack*')
#
# def test_clean(self):
# self.assertEqual(self.sq.clean('hello world'), 'hello world')
# self.assertEqual(self.sq.clean('hello AND world'), 'hello and world')
# self.assertEqual(self.sq.clean('hello AND OR NOT + - && || ! ( ) { } [ ] ^ " ~ * ? : \ world'), 'hello and or not \\+ \\- \\&& \\|| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\" \\~ \\* \\? \\: \\\\ world')
# self.assertEqual(self.sq.clean('so please NOTe i am in a bAND and bORed'), 'so please NOTe i am in a bAND and bORed')
#
# def test_build_query_with_models(self):
# self.sq.add_filter('content', 'hello')
# self.sq.add_model(MockModel)
# self.assertEqual(self.sq.build_query(), u'(hello) django_ct:core.mockmodel')
#
# self.sq.add_model(AnotherMockModel)
# self.assertEqual(self.sq.build_query(), u'(hello) django_ct:core.anothermockmodel django_ct:core.mockmodel')
#
# def test_build_query_with_datetime(self):
# self.sq.add_filter('pub_date', datetime.datetime(2009, 5, 9, 16, 20))
# 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('id__exact', [1, 2, 3])
# self.assertEqual(self.sq.build_query(), u'id:[1, 2, 3]')

View file

@ -933,46 +933,22 @@ class SearchQuery(BaseSearchQuery):
super(SearchQuery, self).__init__(backend=backend)
self.backend = backend or SearchBackend()
def build_query_fragment(self, field, filter_type, value):
"""
Builds a search query fragment from a field, filter type and value.
Returns:
A query string fragment suitable for parsing by Xapian.
"""
result = ''
def build_query(self):
if not self.query_filter:
return xapian.Query('')
if not isinstance(value, (list, tuple)):
# Convert whatever we find to what xapian wants.
value = self.backend._marshal_value(value)
# Check to see if it's a phrase for an exact match.
if ' ' in value:
value = '"%s"' % value
# 'content' is a special reserved word, much like 'pk' in
# Django's ORM layer. It indicates 'no special field'.
if field == 'content':
result = value
else:
filter_types = {
'exact': '%s:%s',
'gte': '%s:%s..*',
'gt': 'NOT %s:..%s',
'lte': '%s:..%s',
'lt': 'NOT %s:%s..*',
'startswith': '%s:%s*',
}
if filter_type != 'in':
result = filter_types[filter_type] % (field, value)
else:
in_options = []
for possible_value in value:
in_options.append('%s:%s' % (field, possible_value))
result = '(%s)' % ' OR '.join(in_options)
return result
values = []
for child in self.query_filter.children:
if isinstance(child, self.query_filter.__class__):
print 'SQ: ', child # TODO: Recursive call down tree...
else:
expression, value = child
field, filter_type = self.query_filter.split_expression(expression)
values.append(value)
return xapian.Query(xapian.Query.OP_AND, values)
def run(self, spelling_query=None):
"""
Builds and executes the query. Returns a list of search results.