From 00892d695e994539021c9a81e9fc4ab599d0af8c Mon Sep 17 00:00:00 2001 From: David Sauve Date: Thu, 9 Jul 2009 14:04:06 -0400 Subject: [PATCH] Fixed sorting by integer and added tests to prove it --- tests/models.py | 1 + tests/xapian_backend.py | 18 ++++++++++++++++-- xapian_backend.py | 14 ++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/models.py b/tests/models.py index cb53b04..d459464 100644 --- a/tests/models.py +++ b/tests/models.py @@ -7,6 +7,7 @@ class MockModel(models.Model): user = models.CharField(max_length=255) foo = models.CharField(max_length=255, blank=True) pub_date = models.DateTimeField(default=datetime.datetime.now) + value = models.IntegerField() def __unicode__(self): return self.user diff --git a/tests/xapian_backend.py b/tests/xapian_backend.py index 86ce19a..1a720c3 100644 --- a/tests/xapian_backend.py +++ b/tests/xapian_backend.py @@ -18,6 +18,7 @@ class XapianMockSearchIndex(indexes.SearchIndex): text = indexes.CharField(document=True, use_template=True) name = indexes.CharField(model_attr='author') pub_date = indexes.DateField(model_attr='pub_date') + value = indexes.IntegerField(model_attr='value') class XapianSearchSite(sites.SearchSite): @@ -44,6 +45,7 @@ class XapianSearchBackendTestCase(TestCase): mock.id = i mock.author = 'david%s' % i mock.pub_date = datetime.date(2009, 2, 25) - datetime.timedelta(days=i) + mock.value = i * 5 self.sample_objs.append(mock) def tearDown(self): @@ -87,7 +89,7 @@ class XapianSearchBackendTestCase(TestCase): self.sb.update(self.msi, self.sample_objs) # Duplicates should be updated, not appended -- http://github.com/notanumber/xapian-haystack/issues/#issue/6 self.assertEqual(len(self.xapian_search('')), 3) - self.assertEqual([dict(doc) for doc in self.xapian_search('')], [{'name': u'david1', 'text': u'Indexed!\n1', 'pub_date': u'2009-02-24T00:00:00', 'id': u'tests.mockmodel.1'}, {'name': u'david2', 'text': u'Indexed!\n2', 'pub_date': u'2009-02-23T00:00:00', 'id': u'tests.mockmodel.2'}, {'name': u'david3', 'text': u'Indexed!\n3', 'pub_date': u'2009-02-22T00:00:00', 'id': u'tests.mockmodel.3'}]) + self.assertEqual([dict(doc) for doc in self.xapian_search('')], [{'name': u'david1', 'text': u'Indexed!\n1', 'pub_date': u'2009-02-24T00:00:00', 'value': u'5', 'id': u'tests.mockmodel.1'}, {'name': u'david2', 'text': u'Indexed!\n2', 'pub_date': u'2009-02-23T00:00:00', 'value': u'10', 'id': u'tests.mockmodel.2'}, {'name': u'david3', 'text': u'Indexed!\n3', 'pub_date': u'2009-02-22T00:00:00', 'value': u'15', 'id': u'tests.mockmodel.3'}]) def test_remove(self): self.sb.update(self.msi, self.sample_objs) @@ -95,7 +97,7 @@ class XapianSearchBackendTestCase(TestCase): self.sb.remove(self.sample_objs[0]) self.assertEqual(len(self.xapian_search('')), 2) - self.assertEqual([dict(doc) for doc in self.xapian_search('')], [{'name': u'david2', 'text': u'Indexed!\n2', 'pub_date': u'2009-02-23T00:00:00', 'id': u'tests.mockmodel.2'}, {'name': u'david3', 'text': u'Indexed!\n3', 'pub_date': u'2009-02-22T00:00:00', 'id': u'tests.mockmodel.3'}]) + self.assertEqual([dict(doc) for doc in self.xapian_search('')], [{'name': u'david2', 'text': u'Indexed!\n2', 'pub_date': u'2009-02-23T00:00:00', 'value': u'10', 'id': u'tests.mockmodel.2'}, {'name': u'david3', 'text': u'Indexed!\n3', 'pub_date': u'2009-02-22T00:00:00', 'value': u'15', 'id': u'tests.mockmodel.3'}]) def test_clear(self): self.sb.update(self.msi, self.sample_objs) @@ -197,6 +199,18 @@ class XapianSearchBackendTestCase(TestCase): results = self.sb.search('*', sort_by=['-pub_date']) self.assertEqual([result.pk for result in results['results']], [u'3', u'2', u'1']) + + results = self.sb.search('*', sort_by=['id']) + self.assertEqual([result.pk for result in results['results']], [u'3', u'2', u'1']) + + results = self.sb.search('*', sort_by=['-id']) + self.assertEqual([result.pk for result in results['results']], [u'1', u'2', u'3']) + + results = self.sb.search('*', sort_by=['value']) + self.assertEqual([result.pk for result in results['results']], [u'3', u'2', u'1']) + + results = self.sb.search('*', sort_by=['-value']) + self.assertEqual([result.pk for result in results['results']], [u'1', u'2', u'3']) def test__from_python(self): self.assertEqual(self.sb._from_python('abc'), u'abc') diff --git a/xapian_backend.py b/xapian_backend.py index 143f790..80e5d4d 100644 --- a/xapian_backend.py +++ b/xapian_backend.py @@ -114,7 +114,7 @@ class SearchBackend(BaseSearchBackend): The document also contains a pickled version of the object itself in the document data field. - Finally, the database itself maintains a list of all index field names + Also, the database itself maintains a list of all index field names in use through the database meta data field with the name `schema`. This is a pickled data that can be loaded on demand and used to assign prefixes to query parsers so that a user can perform field name @@ -123,6 +123,12 @@ class SearchBackend(BaseSearchBackend): `:` eg.: `'foo:bar'` will filter based on the `foo` field for `bar`. + + Finally, we also store field values to be used for sorting data. We + store these in the document value slots (position zero is reserver + for the document ID). All values are stored as unicode strings with + conversion of float, int, double, values being done by Xapian itself + through the use of the :method:xapian.sortable_serialise method. """ schema = self._build_schema() @@ -148,7 +154,11 @@ class SearchBackend(BaseSearchBackend): data = self._from_python(value) indexer.index_text(data) indexer.index_text(data, 1, prefix) - document.add_value(i + 1, data) + + if isinstance(value, (int, long, float)): + document.add_value(i + 1, xapian.sortable_serialise(value)) + else: + document.add_value(i + 1, data) document.set_data(pickle.dumps(document_data, pickle.HIGHEST_PROTOCOL)) document.add_term(DOCUMENT_ID_TERM_PREFIX + document_id)