mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
109066baf3
commit
4cf1539c37
@ -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):
|
||||||
|
@ -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)]))
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user