Fix sorting for composite cols that are marked as numeric

Incidentally, the implementation of size suffixes in the old db was
broken.
This commit is contained in:
Kovid Goyal 2013-08-25 10:08:29 +05:30
parent 109066baf3
commit 4cf1539c37
2 changed files with 31 additions and 4 deletions

View File

@ -8,6 +8,7 @@ __license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from locale import atof
from threading import Lock from threading import Lock
from collections import defaultdict, Counter from collections import defaultdict, Counter
from functools import partial from functools import partial
@ -175,17 +176,35 @@ class OneToOneField(Field):
class CompositeField(OneToOneField): class CompositeField(OneToOneField):
is_composite = True is_composite = True
SIZE_SUFFIX_MAP = {suffix:i for i, suffix in enumerate(('', 'K', 'M', 'G', 'T', 'P', 'E'))}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
OneToOneField.__init__(self, *args, **kwargs) OneToOneField.__init__(self, *args, **kwargs)
self._render_cache = {} self._render_cache = {}
self._lock = Lock() self._lock = Lock()
self._composite_name = '#' + self.metadata['label'] m = self.metadata
self._composite_name = '#' + m['label']
try: try:
self.splitter = self.metadata['is_multiple'].get('cache_to_list', None) self.splitter = m['is_multiple'].get('cache_to_list', None)
except AttributeError: except AttributeError:
self.splitter = None self.splitter = None
composite_sort = m.get('display', {}).get('composite_sort', None)
if composite_sort == 'number':
self._sort_key = self.number_sort_key
else:
self._sort_key = sort_key
def number_sort_key(self, val):
try:
p = 1
if val and val.endswith('B'):
p = 1 << (10 * self.SIZE_SUFFIX_MAP.get(val[-2:-1], 0))
val = val[:(-2 if p > 1 else -1)].strip()
val = atof(val) * p
except (TypeError, AttributeError, ValueError):
val = 0.0
return val
def render_composite(self, book_id, mi): def render_composite(self, book_id, mi):
with self._lock: with self._lock:
@ -215,7 +234,7 @@ class CompositeField(OneToOneField):
return ans return ans
def sort_keys_for_books(self, get_metadata, lang_map, all_book_ids): def sort_keys_for_books(self, get_metadata, lang_map, all_book_ids):
return {id_: sort_key(self.get_value_with_cache(id_, get_metadata)) for id_ in return {id_: self._sort_key(self.get_value_with_cache(id_, get_metadata)) for id_ in
all_book_ids} all_book_ids}
def iter_searchable_values(self, get_metadata, candidates, default_value=None): def iter_searchable_values(self, get_metadata, candidates, default_value=None):

View File

@ -558,7 +558,9 @@ class ReadingTest(BaseTest):
def test_composites(self): # {{{ def test_composites(self): # {{{
cache = self.init_cache() cache = self.init_cache()
cache.create_custom_column('mult', 'CC1', 'composite', True, display={'composite_template': 'b,a,c'}) cache.create_custom_column('mult', 'CC1', 'composite', True, display={'composite_template': 'b,a,c'})
cache.create_custom_column('single', 'CC1', 'composite', False, display={'composite_template': 'b,a,c'}) cache.create_custom_column('single', 'CC2', 'composite', False, display={'composite_template': 'b,a,c'})
cache.create_custom_column('number', 'CC3', 'composite', False, display={'composite_template': '{#float}', 'composite_sort':'number'})
cache.create_custom_column('size', 'CC4', 'composite', False, display={'composite_template': '{#float:human_readable()}', 'composite_sort':'number'})
cache = self.init_cache() cache = self.init_cache()
# Test searching # Test searching
@ -566,5 +568,11 @@ class ReadingTest(BaseTest):
self.assertEqual(set(), cache.search('#mult:=b,a,c')) self.assertEqual(set(), cache.search('#mult:=b,a,c'))
self.assertEqual({1,2,3}, cache.search('#single:=b,a,c')) self.assertEqual({1,2,3}, cache.search('#single:=b,a,c'))
self.assertEqual(set(), cache.search('#single:=b')) self.assertEqual(set(), cache.search('#single:=b'))
# Test numeric sorting
cache.set_field('#float', {1:2, 2:10, 3:0.0001})
self.assertEqual([3, 1, 2], cache.multisort([('#number', True)]))
cache.set_field('#float', {1:3, 2:2*1024, 3:3*1024*1024})
self.assertEqual([1, 2, 3], cache.multisort([('#size', True)]))
# }}} # }}}