Merged 2.0.X branch
This commit is contained in:
commit
dcdc9eb319
2
AUTHORS
2
AUTHORS
|
@ -25,4 +25,4 @@ Thanks to:
|
|||
* Jacob Kaplan-Moss for pointing out that write permission shouldn't be required for searching.
|
||||
* glassresistor for assistance troubleshooting an issue with boosting a phrase query & a patch to make weighting schemes overridable.
|
||||
* James Addison for helping to debug an intermittent issue with `order_by` and `build_schema`.
|
||||
* Michael Opitz for a patch that enables support for `inmemorydb`.
|
||||
* Michael Opitz for a patch that enables support for `inmemorydb`.
|
||||
|
|
18
README.rst
18
README.rst
|
@ -13,7 +13,7 @@ Requirements
|
|||
|
||||
- Python 2.4 (May work with 2.3, but untested)
|
||||
- Django 1.0.x
|
||||
- Django-Haystack 1.1.X (If you wish to use django-haystack 1.0.X, please use xapian-haystack 1.0.X)
|
||||
- Django-Haystack 2.0.X
|
||||
- Xapian 1.0.13+ (May work with earlier versions, but untested)
|
||||
|
||||
Notes
|
||||
|
@ -33,13 +33,19 @@ Installation
|
|||
or
|
||||
|
||||
``pip install xapian-haystack``
|
||||
|
||||
|
||||
or
|
||||
|
||||
``easy_install xapian-haystack``
|
||||
|
||||
#. Add ``HAYSTACK_XAPIAN_PATH`` to ``settings.py``
|
||||
#. Set ``HAYSTACK_SEARCH_ENGINE`` to ``xapian``
|
||||
#. Set to something similar to:
|
||||
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'haystack.backends.xapian_backend.XapianEngine',
|
||||
'PATH': os.path.join(os.path.dirname(__file__), 'xapian_index')
|
||||
},
|
||||
}
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
@ -96,10 +102,10 @@ xapian-haystack is maintained by `David Sauve <mailto:david.sauve@bag-of-holding
|
|||
License
|
||||
-------
|
||||
|
||||
xapian-haystack is Copyright (c) 2009, 2010, 2011 David Sauve, 2009, 2010 Trapeze. It is free software, and may be redistributed under the terms specified in the LICENSE file.
|
||||
xapian-haystack is Copyright (c) 2009, 2010, 2011, 2012 David Sauve, 2009, 2010 Trapeze. It is free software, and may be redistributed under the terms specified in the LICENSE file.
|
||||
|
||||
Questions, Comments, Concerns:
|
||||
------------------------------
|
||||
|
||||
Feel free to open an issue here: `github.com/notanumber/xapian-haystack/issues <http://github.com/notanumber/xapian-haystack/issues>`_
|
||||
Alternatively, ask questions on the django-haystack `mailing list <http://groups.google.com/group/django-haystack/>`_ or `irc channel <irc://irc.freenode.net/haystack>`_.
|
||||
Alternatively, ask questions on the django-haystack `mailing list <http://groups.google.com/group/django-haystack/>`_ or `irc channel <irc://irc.freenode.net/haystack>`_.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
||||
import os
|
||||
|
@ -8,6 +8,10 @@ INSTALLED_APPS += [
|
|||
'xapian_tests',
|
||||
]
|
||||
|
||||
HAYSTACK_SEARCH_ENGINE = 'xapian'
|
||||
HAYSTACK_XAPIAN_PATH = os.path.join('tmp', 'test_xapian_query')
|
||||
HAYSTACK_INCLUDE_SPELLING = True
|
||||
HAYSTACK_CONNECTIONS = {
|
||||
'default': {
|
||||
'ENGINE': 'haystack.backends.xapian_backend.XapianEngine',
|
||||
'PATH': os.path.join('tmp', 'test_xapian_query'),
|
||||
'INCLUDE_SPELLING': True,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
||||
import warnings
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
||||
# Based on original code by Daniel Lindsley as part of the Haystack test suite.
|
||||
|
||||
import cPickle as pickle
|
||||
import datetime
|
||||
import os
|
||||
import shutil
|
||||
|
@ -14,12 +13,12 @@ from django.conf import settings
|
|||
from django.db import models
|
||||
from django.test import TestCase
|
||||
|
||||
from haystack import indexes, sites, backends
|
||||
from haystack.backends.xapian_backend import SearchBackend, SearchQuery, _marshal_value
|
||||
from haystack.exceptions import HaystackError
|
||||
from haystack import connections, reset_search_queries
|
||||
from haystack import indexes
|
||||
from haystack.backends.xapian_backend import _marshal_value
|
||||
from haystack.models import SearchResult
|
||||
from haystack.query import SearchQuerySet, SQ
|
||||
from haystack.sites import SearchSite
|
||||
from haystack.utils.loading import UnifiedIndex
|
||||
|
||||
from core.models import MockTag, MockModel, AnotherMockModel, AFourthMockModel
|
||||
from core.tests.mocks import MockSearchResult
|
||||
|
@ -35,16 +34,16 @@ class XapianMockModel(models.Model):
|
|||
pub_date = models.DateTimeField(default=datetime.datetime.now)
|
||||
exp_date = models.DateTimeField(default=datetime.datetime.now)
|
||||
tag = models.ForeignKey(MockTag)
|
||||
|
||||
|
||||
value = models.IntegerField(default=0)
|
||||
flag = models.BooleanField(default=True)
|
||||
slug = models.SlugField()
|
||||
popularity = models.FloatField(default=0.0)
|
||||
url = models.URLField()
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return self.author
|
||||
|
||||
|
||||
def hello(self):
|
||||
return 'World!'
|
||||
|
||||
|
@ -64,13 +63,16 @@ class XapianMockSearchIndex(indexes.SearchIndex):
|
|||
month = indexes.CharField(indexed=False)
|
||||
url = indexes.CharField(model_attr='url')
|
||||
empty = indexes.CharField()
|
||||
|
||||
|
||||
# Various MultiValueFields
|
||||
sites = indexes.MultiValueField()
|
||||
tags = indexes.MultiValueField()
|
||||
keys = indexes.MultiValueField()
|
||||
titles = indexes.MultiValueField()
|
||||
|
||||
|
||||
def get_model(self):
|
||||
return XapianMockModel
|
||||
|
||||
def prepare_sites(self, obj):
|
||||
return ['%d' % (i * obj.id) for i in xrange(1, 4)]
|
||||
|
||||
|
@ -92,7 +94,6 @@ class XapianMockSearchIndex(indexes.SearchIndex):
|
|||
return ['object two title one', 'object two title two']
|
||||
else:
|
||||
return ['object three title one', 'object three title two']
|
||||
pub_date = indexes.DateField(model_attr='pub_date')
|
||||
|
||||
def prepare_month(self, obj):
|
||||
return '%02d' % obj.pub_date.month
|
||||
|
@ -110,18 +111,23 @@ class XapianBoostMockSearchIndex(indexes.SearchIndex):
|
|||
editor = indexes.CharField(model_attr='editor')
|
||||
pub_date = indexes.DateField(model_attr='pub_date')
|
||||
|
||||
def get_model(self):
|
||||
return AFourthMockModel
|
||||
|
||||
|
||||
class XapianSearchBackendTestCase(TestCase):
|
||||
def setUp(self):
|
||||
super(XapianSearchBackendTestCase, self).setUp()
|
||||
|
||||
self.site = SearchSite()
|
||||
self.backend = SearchBackend(site=self.site)
|
||||
self.index = XapianMockSearchIndex(XapianMockModel, backend=self.backend)
|
||||
self.site.register(XapianMockModel, XapianMockSearchIndex)
|
||||
|
||||
|
||||
self.old_ui = connections['default'].get_unified_index()
|
||||
self.ui = UnifiedIndex()
|
||||
self.index = XapianMockSearchIndex()
|
||||
self.ui.build(indexes=[self.index])
|
||||
self.backend = connections['default'].get_backend()
|
||||
connections['default']._index = self.ui
|
||||
|
||||
self.sample_objs = []
|
||||
|
||||
|
||||
for i in xrange(1, 4):
|
||||
mock = XapianMockModel()
|
||||
mock.id = i
|
||||
|
@ -133,69 +139,70 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
mock.slug = 'http://example.com/%d/' % i
|
||||
mock.url = 'http://example.com/%d/' % i
|
||||
self.sample_objs.append(mock)
|
||||
|
||||
|
||||
self.sample_objs[0].popularity = 834.0
|
||||
self.sample_objs[1].popularity = 35.5
|
||||
self.sample_objs[2].popularity = 972.0
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(settings.HAYSTACK_XAPIAN_PATH):
|
||||
shutil.rmtree(settings.HAYSTACK_XAPIAN_PATH)
|
||||
|
||||
if os.path.exists(settings.HAYSTACK_CONNECTIONS['default']['PATH']):
|
||||
shutil.rmtree(settings.HAYSTACK_CONNECTIONS['default']['PATH'])
|
||||
|
||||
connections['default']._index = self.old_ui
|
||||
super(XapianSearchBackendTestCase, self).tearDown()
|
||||
|
||||
|
||||
def test_update(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query(''))['results']], [1, 2, 3])
|
||||
|
||||
|
||||
def test_duplicate_update(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.backend.update(self.index, self.sample_objs) # Duplicates should be updated, not appended -- http://github.com/notanumber/xapian-haystack/issues/#issue/6
|
||||
|
||||
self.backend.update(self.index, self.sample_objs) # Duplicates should be updated, not appended -- http://github.com/notanumber/xapian-haystack/issues/#issue/6
|
||||
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
def test_remove(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.backend.remove(self.sample_objs[0])
|
||||
self.assertEqual(self.backend.document_count(), 2)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query(''))['results']], [2, 3])
|
||||
|
||||
|
||||
def test_clear(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.backend.clear()
|
||||
self.assertEqual(self.backend.document_count(), 0)
|
||||
|
||||
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.backend.clear([AnotherMockModel])
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.backend.clear([XapianMockModel])
|
||||
self.assertEqual(self.backend.document_count(), 0)
|
||||
|
||||
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.backend.clear([AnotherMockModel, XapianMockModel])
|
||||
self.assertEqual(self.backend.document_count(), 0)
|
||||
|
||||
|
||||
def test_search(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query()), {'hits': 0, 'results': []})
|
||||
self.assertEqual(self.backend.search(xapian.Query(''))['hits'], 3)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query(''))['results']], [1, 2, 3])
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 3)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query(''))['results']], [1, 2, 3])
|
||||
|
||||
|
||||
# Ensure that swapping the ``result_class`` works.
|
||||
self.assertTrue(isinstance(self.backend.search(xapian.Query('indexed'), result_class=MockSearchResult)['results'][0], MockSearchResult))
|
||||
|
||||
|
@ -209,33 +216,33 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
def test_search_by_mvf(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query('ab'))['hits'], 1)
|
||||
self.assertEqual(self.backend.search(xapian.Query('b'))['hits'], 1)
|
||||
self.assertEqual(self.backend.search(xapian.Query('to'))['hits'], 1)
|
||||
self.assertEqual(self.backend.search(xapian.Query('one'))['hits'], 3)
|
||||
|
||||
|
||||
def test_field_facets(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query(), facets=['name']), {'hits': 0, 'results': []})
|
||||
results = self.backend.search(xapian.Query('indexed'), facets=['name'])
|
||||
self.assertEqual(results['hits'], 3)
|
||||
self.assertEqual(results['facets']['fields']['name'], [('david1', 1), ('david2', 1), ('david3', 1)])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query('indexed'), facets=['flag'])
|
||||
self.assertEqual(results['hits'], 3)
|
||||
self.assertEqual(results['facets']['fields']['flag'], [(False, 1), (True, 2)])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query('indexed'), facets=['sites'])
|
||||
self.assertEqual(results['hits'], 3)
|
||||
self.assertEqual(results['facets']['fields']['sites'], [('1', 1), ('3', 2), ('2', 2), ('4', 1), ('6', 2), ('9', 1)])
|
||||
|
||||
|
||||
def test_date_facets(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query(), date_facets={'pub_date': {'start_date': datetime.datetime(2008, 10, 26), 'end_date': datetime.datetime(2009, 3, 26), 'gap_by': 'month'}}), {'hits': 0, 'results': []})
|
||||
results = self.backend.search(xapian.Query('indexed'), date_facets={'pub_date': {'start_date': datetime.datetime(2008, 10, 26), 'end_date': datetime.datetime(2009, 3, 26), 'gap_by': 'month'}})
|
||||
self.assertEqual(results['hits'], 3)
|
||||
|
@ -246,7 +253,7 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
('2008-11-26T00:00:00', 0),
|
||||
('2008-10-26T00:00:00', 0),
|
||||
])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query('indexed'), date_facets={'pub_date': {'start_date': datetime.datetime(2009, 02, 01), 'end_date': datetime.datetime(2009, 3, 15), 'gap_by': 'day', 'gap_amount': 15}})
|
||||
self.assertEqual(results['hits'], 3)
|
||||
self.assertEqual(results['facets']['dates']['pub_date'], [
|
||||
|
@ -254,137 +261,107 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
('2009-02-16T00:00:00', 3),
|
||||
('2009-02-01T00:00:00', 0)
|
||||
])
|
||||
|
||||
|
||||
def test_query_facets(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query(), query_facets={'name': 'da*'}), {'hits': 0, 'results': []})
|
||||
results = self.backend.search(xapian.Query('indexed'), query_facets={'name': 'da*'})
|
||||
self.assertEqual(results['hits'], 3)
|
||||
self.assertEqual(results['facets']['queries']['name'], ('da*', 3))
|
||||
|
||||
|
||||
def test_narrow_queries(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query(), narrow_queries=set(['name:david1'])), {'hits': 0, 'results': []})
|
||||
results = self.backend.search(xapian.Query('indexed'), narrow_queries=set(['name:david1']))
|
||||
self.assertEqual(results['hits'], 1)
|
||||
|
||||
|
||||
def test_highlight(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query(), highlight=True), {'hits': 0, 'results': []})
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'), highlight=True)['hits'], 3)
|
||||
self.assertEqual([result.highlighted['text'] for result in self.backend.search(xapian.Query('indexed'), highlight=True)['results']], ['<em>indexed</em>!\n1', '<em>indexed</em>!\n2', '<em>indexed</em>!\n3'])
|
||||
|
||||
|
||||
def test_spelling_suggestion(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query('indxe'))['hits'], 0)
|
||||
self.assertEqual(self.backend.search(xapian.Query('indxe'))['spelling_suggestion'], 'indexed')
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query('indxed'))['hits'], 0)
|
||||
self.assertEqual(self.backend.search(xapian.Query('indxed'))['spelling_suggestion'], 'indexed')
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query('foo'))['hits'], 0)
|
||||
self.assertEqual(self.backend.search(xapian.Query('foo'), spelling_query='indexy')['spelling_suggestion'], 'indexed')
|
||||
|
||||
|
||||
self.assertEqual(self.backend.search(xapian.Query('XNAMEdavid'))['hits'], 0)
|
||||
self.assertEqual(self.backend.search(xapian.Query('XNAMEdavid'))['spelling_suggestion'], 'david1')
|
||||
|
||||
|
||||
def test_more_like_this(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
results = self.backend.more_like_this(self.sample_objs[0])
|
||||
self.assertEqual(results['hits'], 2)
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2])
|
||||
|
||||
|
||||
results = self.backend.more_like_this(self.sample_objs[0], additional_query=xapian.Query('david3'))
|
||||
self.assertEqual(results['hits'], 1)
|
||||
self.assertEqual([result.pk for result in results['results']], [3])
|
||||
|
||||
|
||||
results = self.backend.more_like_this(self.sample_objs[0], limit_to_registered_models=True)
|
||||
self.assertEqual(results['hits'], 2)
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2])
|
||||
|
||||
|
||||
# Ensure that swapping the ``result_class`` works.
|
||||
self.assertTrue(isinstance(self.backend.more_like_this(self.sample_objs[0], result_class=MockSearchResult)['results'][0], MockSearchResult))
|
||||
|
||||
def test_use_correct_site(self):
|
||||
test_site = SearchSite()
|
||||
test_site.register(XapianMockModel, XapianMockSearchIndex)
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
|
||||
# Make sure that ``_process_results`` uses the right ``site``.
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 3)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query('indexed'))['results']], [1, 2, 3])
|
||||
|
||||
self.site.unregister(XapianMockModel)
|
||||
self.assertEqual(len(self.site.get_indexed_models()), 0)
|
||||
self.backend.site = test_site
|
||||
self.assertTrue(len(self.backend.site.get_indexed_models()) > 0)
|
||||
|
||||
# Should still be there, despite the main ``site`` not having that model
|
||||
# registered any longer.
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 3)
|
||||
self.assertEqual([result.pk for result in self.backend.search(xapian.Query('indexed'))['results']], [1, 2, 3])
|
||||
|
||||
# Unregister it on the backend & make sure it takes effect.
|
||||
self.backend.site.unregister(XapianMockModel)
|
||||
self.assertEqual(len(self.backend.site.get_indexed_models()), 0)
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 0)
|
||||
|
||||
# Nuke it & fallback on the main ``site``.
|
||||
self.backend.site = haystack.site
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 0)
|
||||
self.site.register(XapianMockModel, XapianMockSearchIndex)
|
||||
self.assertEqual(self.backend.search(xapian.Query('indexed'))['hits'], 3)
|
||||
|
||||
|
||||
def test_order_by(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['pub_date'])
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2, 1])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['-pub_date'])
|
||||
self.assertEqual([result.pk for result in results['results']], [1, 2, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['exp_date'])
|
||||
self.assertEqual([result.pk for result in results['results']], [1, 2, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['-exp_date'])
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2, 1])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['id'])
|
||||
self.assertEqual([result.pk for result in results['results']], [1, 2, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['-id'])
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2, 1])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['value'])
|
||||
self.assertEqual([result.pk for result in results['results']], [1, 2, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['-value'])
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 2, 1])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['popularity'])
|
||||
self.assertEqual([result.pk for result in results['results']], [2, 1, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['-popularity'])
|
||||
self.assertEqual([result.pk for result in results['results']], [3, 1, 2])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['flag', 'id'])
|
||||
self.assertEqual([result.pk for result in results['results']], [2, 1, 3])
|
||||
|
||||
|
||||
results = self.backend.search(xapian.Query(''), sort_by=['flag', '-id'])
|
||||
self.assertEqual([result.pk for result in results['results']], [2, 3, 1])
|
||||
|
||||
|
||||
def test_verify_type(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(self.backend.document_count(), 3)
|
||||
|
@ -404,9 +381,9 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
self.assertEqual(_marshal_value(datetime.datetime(2009, 5, 9, 0, 0)), u'20090509000000')
|
||||
self.assertEqual(_marshal_value(datetime.datetime(1899, 5, 18, 0, 0)), u'18990518000000')
|
||||
self.assertEqual(_marshal_value(datetime.datetime(2009, 5, 18, 1, 16, 30, 250)), u'20090518011630000250')
|
||||
|
||||
|
||||
def test_build_schema(self):
|
||||
(content_field_name, fields) = self.backend.build_schema(self.site.all_searchfields())
|
||||
(content_field_name, fields) = self.backend.build_schema(connections['default'].get_unified_index().all_searchfields())
|
||||
self.assertEqual(content_field_name, 'text')
|
||||
self.assertEqual(len(fields), 15)
|
||||
self.assertEqual(fields, [
|
||||
|
@ -426,7 +403,7 @@ class XapianSearchBackendTestCase(TestCase):
|
|||
{'column': 13, 'type': 'text', 'field_name': 'url', 'multi_valued': 'false'},
|
||||
{'column': 14, 'type': 'long', 'field_name': 'value', 'multi_valued': 'false'}
|
||||
])
|
||||
|
||||
|
||||
def test_parse_query(self):
|
||||
self.backend.update(self.index, self.sample_objs)
|
||||
self.assertEqual(str(self.backend.parse_query('indexed')), 'Xapian::Query(Zindex:(pos=1))')
|
||||
|
@ -451,49 +428,58 @@ class LiveXapianMockSearchIndex(indexes.SearchIndex):
|
|||
created = indexes.DateField()
|
||||
title = indexes.CharField()
|
||||
|
||||
def get_model(self):
|
||||
return MockModel
|
||||
|
||||
|
||||
class LiveXapianSearchQueryTestCase(TestCase):
|
||||
"""
|
||||
SearchQuery specific tests
|
||||
"""
|
||||
fixtures = ['initial_data.json']
|
||||
|
||||
|
||||
def setUp(self):
|
||||
super(LiveXapianSearchQueryTestCase, self).setUp()
|
||||
|
||||
site = SearchSite()
|
||||
backend = SearchBackend(site=site)
|
||||
index = LiveXapianMockSearchIndex(MockModel, backend=backend)
|
||||
site.register(MockModel, LiveXapianMockSearchIndex)
|
||||
|
||||
self.old_ui = connections['default'].get_unified_index()
|
||||
ui = UnifiedIndex()
|
||||
index = LiveXapianMockSearchIndex()
|
||||
ui.build(indexes=[index])
|
||||
backend = connections['default'].get_backend()
|
||||
connections['default']._index = ui
|
||||
backend.update(index, MockModel.objects.all())
|
||||
|
||||
self.sq = SearchQuery(backend=backend)
|
||||
|
||||
|
||||
self.sq = connections['default'].get_query()
|
||||
|
||||
def tearDown(self):
|
||||
connections['default']._index = self.old_ui
|
||||
super(LiveXapianSearchQueryTestCase, self).tearDown()
|
||||
|
||||
def test_get_spelling(self):
|
||||
self.sq.add_filter(SQ(content='indxd'))
|
||||
self.assertEqual(self.sq.get_spelling_suggestion(), u'indexed')
|
||||
self.assertEqual(self.sq.get_spelling_suggestion('indxd'), u'indexed')
|
||||
|
||||
|
||||
def test_startswith(self):
|
||||
self.sq.add_filter(SQ(name__startswith='da'))
|
||||
self.assertEqual([result.pk for result in self.sq.get_results()], [1, 2, 3])
|
||||
|
||||
|
||||
def test_build_query_gt(self):
|
||||
self.sq.add_filter(SQ(name__gt='m'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT VALUE_RANGE 2 a m))')
|
||||
|
||||
|
||||
def test_build_query_gte(self):
|
||||
self.sq.add_filter(SQ(name__gte='m'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(VALUE_RANGE 2 m zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz)')
|
||||
|
||||
|
||||
def test_build_query_lt(self):
|
||||
self.sq.add_filter(SQ(name__lt='m'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT VALUE_RANGE 2 m zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz))')
|
||||
|
||||
|
||||
def test_build_query_lte(self):
|
||||
self.sq.add_filter(SQ(name__lte='m'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(VALUE_RANGE 2 a m)')
|
||||
|
||||
|
||||
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, 0)))
|
||||
|
@ -502,35 +488,35 @@ class LiveXapianSearchQueryTestCase(TestCase):
|
|||
self.sq.add_filter(SQ(title__gte='B'))
|
||||
self.sq.add_filter(SQ(id__in=[1, 2, 3]))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND VALUE_RANGE 3 00010101000000 20090210015900 AND (<alldocuments> AND_NOT VALUE_RANGE 2 a david) AND (<alldocuments> AND_NOT VALUE_RANGE 1 20090212121300 99990101000000) AND VALUE_RANGE 5 b zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz AND (Q1 OR Q2 OR Q3)))')
|
||||
|
||||
|
||||
def test_log_query(self):
|
||||
backends.reset_search_queries()
|
||||
self.assertEqual(len(backends.queries), 0)
|
||||
|
||||
reset_search_queries()
|
||||
self.assertEqual(len(connections['default'].queries), 0)
|
||||
|
||||
# Stow.
|
||||
old_debug = settings.DEBUG
|
||||
settings.DEBUG = False
|
||||
|
||||
|
||||
len(self.sq.get_results())
|
||||
self.assertEqual(len(backends.queries), 0)
|
||||
|
||||
self.assertEqual(len(connections['default'].queries), 0)
|
||||
|
||||
settings.DEBUG = True
|
||||
# Redefine it to clear out the cached results.
|
||||
self.sq = SearchQuery(backend=SearchBackend())
|
||||
self.sq = connections['default'].get_query()
|
||||
self.sq.add_filter(SQ(name='bar'))
|
||||
len(self.sq.get_results())
|
||||
self.assertEqual(len(backends.queries), 1)
|
||||
self.assertEqual(str(backends.queries[0]['query_string']), u'Xapian::Query((ZXNAMEbar OR XNAMEbar))')
|
||||
|
||||
self.assertEqual(len(connections['default'].queries), 1)
|
||||
self.assertEqual(str(connections['default'].queries[0]['query_string']), u'Xapian::Query((ZXNAMEbar OR XNAMEbar))')
|
||||
|
||||
# And again, for good measure.
|
||||
self.sq = SearchQuery(backend=SearchBackend())
|
||||
self.sq = connections['default'].get_query()
|
||||
self.sq.add_filter(SQ(name='bar'))
|
||||
self.sq.add_filter(SQ(text='moof'))
|
||||
len(self.sq.get_results())
|
||||
self.assertEqual(len(backends.queries), 2)
|
||||
self.assertEqual(str(backends.queries[0]['query_string']), u'Xapian::Query((ZXNAMEbar OR XNAMEbar))')
|
||||
self.assertEqual(str(backends.queries[1]['query_string']), u'Xapian::Query(((ZXNAMEbar OR XNAMEbar) AND (ZXTEXTmoof OR XTEXTmoof)))')
|
||||
|
||||
self.assertEqual(len(connections['default'].queries), 2)
|
||||
self.assertEqual(str(connections['default'].queries[0]['query_string']), u'Xapian::Query((ZXNAMEbar OR XNAMEbar))')
|
||||
self.assertEqual(str(connections['default'].queries[1]['query_string']), u'Xapian::Query(((ZXNAMEbar OR XNAMEbar) AND (ZXTEXTmoof OR XTEXTmoof)))')
|
||||
|
||||
# Restore.
|
||||
settings.DEBUG = old_debug
|
||||
|
||||
|
@ -540,28 +526,34 @@ class LiveXapianSearchQuerySetTestCase(TestCase):
|
|||
SearchQuerySet specific tests
|
||||
"""
|
||||
fixtures = ['initial_data.json']
|
||||
|
||||
|
||||
def setUp(self):
|
||||
super(LiveXapianSearchQuerySetTestCase, self).setUp()
|
||||
|
||||
site = SearchSite()
|
||||
backend = SearchBackend(site=site)
|
||||
index = LiveXapianMockSearchIndex(MockModel, backend=backend)
|
||||
site.register(MockModel, LiveXapianMockSearchIndex)
|
||||
backend.update(index, MockModel.objects.all())
|
||||
|
||||
self.sq = SearchQuery(backend=backend)
|
||||
self.sqs = SearchQuerySet(query=self.sq)
|
||||
|
||||
|
||||
self.old_ui = connections['default'].get_unified_index()
|
||||
self.ui = UnifiedIndex()
|
||||
self.index = LiveXapianMockSearchIndex()
|
||||
self.ui.build(indexes=[self.index])
|
||||
self.backend = connections['default'].get_backend()
|
||||
connections['default']._index = self.ui
|
||||
self.backend.update(self.index, MockModel.objects.all())
|
||||
|
||||
self.sq = connections['default'].get_query()
|
||||
self.sqs = SearchQuerySet()
|
||||
|
||||
def tearDown(self):
|
||||
connections['default']._index = self.old_ui
|
||||
super(LiveXapianSearchQuerySetTestCase, self).tearDown()
|
||||
|
||||
def test_result_class(self):
|
||||
# Assert that we're defaulting to ``SearchResult``.
|
||||
sqs = self.sqs.all()
|
||||
self.assertTrue(isinstance(sqs[0], SearchResult))
|
||||
|
||||
|
||||
# Custom class.
|
||||
sqs = self.sqs.result_class(MockSearchResult).all()
|
||||
self.assertTrue(isinstance(sqs[0], MockSearchResult))
|
||||
|
||||
|
||||
# Reset to default.
|
||||
sqs = self.sqs.result_class(None).all()
|
||||
self.assertTrue(isinstance(sqs[0], SearchResult))
|
||||
|
@ -571,15 +563,13 @@ class XapianBoostBackendTestCase(TestCase):
|
|||
def setUp(self):
|
||||
super(XapianBoostBackendTestCase, self).setUp()
|
||||
|
||||
self.site = SearchSite()
|
||||
self.sb = SearchBackend(site=self.site)
|
||||
self.smmi = XapianBoostMockSearchIndex(AFourthMockModel, backend=self.sb)
|
||||
self.site.register(AFourthMockModel, XapianBoostMockSearchIndex)
|
||||
|
||||
# Stow.
|
||||
import haystack
|
||||
self.old_site = haystack.site
|
||||
haystack.site = self.site
|
||||
self.old_ui = connections['default'].get_unified_index()
|
||||
self.ui = UnifiedIndex()
|
||||
self.index = XapianBoostMockSearchIndex()
|
||||
self.ui.build(indexes=[self.index])
|
||||
self.sb = connections['default'].get_backend()
|
||||
connections['default']._index = self.ui
|
||||
|
||||
self.sample_objs = []
|
||||
|
||||
|
@ -596,15 +586,14 @@ class XapianBoostBackendTestCase(TestCase):
|
|||
self.sample_objs.append(mock)
|
||||
|
||||
def tearDown(self):
|
||||
import haystack
|
||||
haystack.site = self.old_site
|
||||
connections['default']._index = self.old_ui
|
||||
super(XapianBoostBackendTestCase, self).tearDown()
|
||||
|
||||
def test_boost(self):
|
||||
self.sb.update(self.smmi, self.sample_objs)
|
||||
|
||||
self.sb.update(self.index, self.sample_objs)
|
||||
|
||||
sqs = SearchQuerySet()
|
||||
|
||||
|
||||
self.assertEqual(len(sqs.all()), 4)
|
||||
|
||||
results = sqs.filter(SQ(author='daniel') | SQ(editor='daniel'))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2009, 2010, 2011 David Sauve
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 David Sauve
|
||||
# Copyright (C) 2009, 2010 Trapeze
|
||||
|
||||
import datetime
|
||||
|
@ -8,7 +8,7 @@ import shutil
|
|||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
|
||||
from haystack.backends.xapian_backend import SearchBackend, SearchQuery
|
||||
from haystack import connections
|
||||
from haystack.query import SQ
|
||||
|
||||
from core.models import MockModel, AnotherMockModel
|
||||
|
@ -17,41 +17,41 @@ from core.models import MockModel, AnotherMockModel
|
|||
class XapianSearchQueryTestCase(TestCase):
|
||||
def setUp(self):
|
||||
super(XapianSearchQueryTestCase, self).setUp()
|
||||
self.sq = SearchQuery(backend=SearchBackend())
|
||||
|
||||
self.sq = connections['default'].get_query()
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(settings.HAYSTACK_XAPIAN_PATH):
|
||||
shutil.rmtree(settings.HAYSTACK_XAPIAN_PATH)
|
||||
|
||||
if os.path.exists(settings.HAYSTACK_CONNECTIONS['default']['PATH']):
|
||||
shutil.rmtree(settings.HAYSTACK_CONNECTIONS['default']['PATH'])
|
||||
|
||||
super(XapianSearchQueryTestCase, self).tearDown()
|
||||
|
||||
|
||||
def test_build_query_all(self):
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(<alldocuments>)')
|
||||
|
||||
|
||||
def test_build_query_single_word(self):
|
||||
self.sq.add_filter(SQ(content='hello'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Zhello OR hello))')
|
||||
|
||||
|
||||
def test_build_query_single_word_not(self):
|
||||
self.sq.add_filter(~SQ(content='hello'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT (Zhello OR hello)))')
|
||||
|
||||
|
||||
def test_build_query_single_word_field_exact(self):
|
||||
self.sq.add_filter(SQ(foo='hello'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((ZXFOOhello OR XFOOhello))')
|
||||
|
||||
|
||||
def test_build_query_single_word_field_exact_not(self):
|
||||
self.sq.add_filter(~SQ(foo='hello'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)))')
|
||||
|
||||
|
||||
def test_build_query_boolean(self):
|
||||
self.sq.add_filter(SQ(content=True))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Ztrue OR true))')
|
||||
|
||||
|
||||
def test_build_query_date(self):
|
||||
self.sq.add_filter(SQ(content=datetime.date(2009, 5, 8)))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Z20090508000000 OR 20090508000000))')
|
||||
|
||||
|
||||
def test_build_query_date_not(self):
|
||||
self.sq.add_filter(~SQ(content=datetime.date(2009, 5, 8)))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT (Z20090508000000 OR 20090508000000)))')
|
||||
|
@ -59,7 +59,7 @@ class XapianSearchQueryTestCase(TestCase):
|
|||
def test_build_query_datetime(self):
|
||||
self.sq.add_filter(SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Z20090508112800 OR 20090508112800))')
|
||||
|
||||
|
||||
def test_build_query_datetime_not(self):
|
||||
self.sq.add_filter(~SQ(content=datetime.datetime(2009, 5, 8, 11, 28)))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT (Z20090508112800 OR 20090508112800)))')
|
||||
|
@ -67,68 +67,68 @@ class XapianSearchQueryTestCase(TestCase):
|
|||
def test_build_query_float(self):
|
||||
self.sq.add_filter(SQ(content=25.52))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Z25.52 OR 25.52))')
|
||||
|
||||
|
||||
def test_build_query_multiple_words_and(self):
|
||||
self.sq.add_filter(SQ(content='hello'))
|
||||
self.sq.add_filter(SQ(content='world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zhello OR hello) AND (Zworld OR 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(str(self.sq.build_query()), u'Xapian::Query(((<alldocuments> AND_NOT (Zhello OR hello)) AND (<alldocuments> AND_NOT (Zworld OR world))))')
|
||||
|
||||
|
||||
def test_build_query_multiple_words_or(self):
|
||||
self.sq.add_filter(SQ(content='hello') | SQ(content='world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Zhello OR hello OR Zworld OR world))')
|
||||
|
||||
|
||||
def test_build_query_multiple_words_or_not(self):
|
||||
self.sq.add_filter(~SQ(content='hello') | ~SQ(content='world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((<alldocuments> AND_NOT (Zhello OR hello)) OR (<alldocuments> AND_NOT (Zworld 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(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why OR Zhello OR hello) AND (<alldocuments> AND_NOT (Zworld OR world))))')
|
||||
|
||||
|
||||
def test_build_query_multiple_word_field_exact(self):
|
||||
self.sq.add_filter(SQ(foo='hello'))
|
||||
self.sq.add_filter(SQ(bar='world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((ZXFOOhello OR XFOOhello) AND (ZXBARworld OR XBARworld)))')
|
||||
|
||||
|
||||
def test_build_query_multiple_word_field_exact_not(self):
|
||||
self.sq.add_filter(~SQ(foo='hello'))
|
||||
self.sq.add_filter(~SQ(bar='world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((<alldocuments> AND_NOT (ZXFOOhello OR XFOOhello)) AND (<alldocuments> AND_NOT (ZXBARworld OR XBARworld))))')
|
||||
|
||||
|
||||
def test_build_query_phrase(self):
|
||||
self.sq.add_filter(SQ(content='hello world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((hello PHRASE 2 world))')
|
||||
|
||||
|
||||
def test_build_query_phrase_not(self):
|
||||
self.sq.add_filter(~SQ(content='hello world'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((<alldocuments> AND_NOT (hello PHRASE 2 world)))')
|
||||
|
||||
|
||||
def test_build_query_boost(self):
|
||||
self.sq.add_filter(SQ(content='hello'))
|
||||
self.sq.add_boost('world', 5)
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zhello OR hello) AND_MAYBE 5 * (Zworld OR world)))')
|
||||
|
||||
|
||||
def test_build_query_in_filter_single_words(self):
|
||||
self.sq.add_filter(SQ(content='why'))
|
||||
self.sq.add_filter(SQ(title__in=["Dune", "Jaws"]))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND (ZXTITLEdune OR XTITLEdune OR ZXTITLEjaw OR XTITLEjaws)))')
|
||||
|
||||
|
||||
def test_build_query_not_in_filter_single_words(self):
|
||||
self.sq.add_filter(SQ(content='why'))
|
||||
self.sq.add_filter(~SQ(title__in=["Dune", "Jaws"]))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND (<alldocuments> AND_NOT (ZXTITLEdune OR XTITLEdune OR ZXTITLEjaw OR XTITLEjaws))))')
|
||||
|
||||
|
||||
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(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND ((XTITLEa PHRASE 3 XTITLEfamous PHRASE 3 XTITLEpaper) OR (XTITLEan PHRASE 3 XTITLEinfamous PHRASE 3 XTITLEarticle))))')
|
||||
|
||||
|
||||
def test_build_query_in_filter_multiple_words_with_punctuation(self):
|
||||
self.sq.add_filter(SQ(title__in=["A Famous Paper", "An Infamous Article", "My Store Inc."]))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((XTITLEa PHRASE 3 XTITLEfamous PHRASE 3 XTITLEpaper) OR (XTITLEan PHRASE 3 XTITLEinfamous PHRASE 3 XTITLEarticle) OR (XTITLEmy PHRASE 3 XTITLEstore PHRASE 3 XTITLEinc.)))')
|
||||
|
@ -137,30 +137,30 @@ class XapianSearchQueryTestCase(TestCase):
|
|||
self.sq.add_filter(SQ(content='why'))
|
||||
self.sq.add_filter(~SQ(title__in=["A Famous Paper", "An Infamous Article"]))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND (<alldocuments> AND_NOT ((XTITLEa PHRASE 3 XTITLEfamous PHRASE 3 XTITLEpaper) OR (XTITLEan PHRASE 3 XTITLEinfamous PHRASE 3 XTITLEarticle)))))')
|
||||
|
||||
|
||||
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(str(self.sq.build_query()), u'Xapian::Query(((Zwhi OR why) AND (ZXPUB_DATE20090706015621 OR XPUB_DATE20090706015621)))')
|
||||
|
||||
|
||||
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 TO + - && || ! ( ) { } [ ] ^ " ~ * ? : \ world'), 'hello AND OR NOT TO + - && || ! ( ) { } [ ] ^ " ~ * ? : \ 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(str(self.sq.build_query()), u'Xapian::Query(((Zhello OR hello) AND 0 * XCONTENTTYPEcore.mockmodel))')
|
||||
|
||||
|
||||
self.sq.add_model(AnotherMockModel)
|
||||
self.assertTrue(str(self.sq.build_query()) in u'Xapian::Query(((Zhello OR hello) AND (0 * XCONTENTTYPEcore.anothermockmodel OR 0 * XCONTENTTYPEcore.mockmodel)))' or u'Xapian::Query(((Zhello OR hello) AND (0 * XCONTENTTYPEcore.mockmodel OR 0 * XCONTENTTYPEcore.anothermockmodel)))')
|
||||
|
||||
def test_build_query_with_punctuation(self):
|
||||
self.sq.add_filter(SQ(content='http://www.example.com'))
|
||||
self.assertEqual(str(self.sq.build_query()), u'Xapian::Query((Zhttp://www.example.com OR http://www.example.com))')
|
||||
|
||||
|
||||
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)))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue