mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
newdb: Fix sorting of is_multiple fields
Fix sorting of book list by multi-valued fields like tags not correct in the new backend. Fixes #1215820 [different ordering by tags in the 1.0 version](https://bugs.launchpad.net/calibre/+bug/1215820)
This commit is contained in:
parent
189a280bb7
commit
aa58f3a559
@ -13,7 +13,7 @@ from collections import defaultdict, Counter
|
||||
|
||||
from calibre.db.tables import ONE_ONE, MANY_ONE, MANY_MANY, null
|
||||
from calibre.db.write import Writer
|
||||
from calibre.ebooks.metadata import title_sort
|
||||
from calibre.ebooks.metadata import title_sort, author_to_author_sort
|
||||
from calibre.utils.config_base import tweaks
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.utils.date import UNDEFINED_DATE
|
||||
@ -48,6 +48,10 @@ class Field(object):
|
||||
self._sort_key = lambda x:sort_key(calibre_langcode_to_name(x))
|
||||
self.is_multiple = (bool(self.metadata['is_multiple']) or self.name ==
|
||||
'formats')
|
||||
self.sort_sort_key = True
|
||||
if self.is_multiple and '&' in self.metadata['is_multiple']['list_to_ui']:
|
||||
self._sort_key = lambda x: sort_key(author_to_author_sort(x))
|
||||
self.sort_sort_key = False
|
||||
self.default_value = {} if name == 'identifiers' else () if self.is_multiple else None
|
||||
self.category_formatter = type(u'')
|
||||
if dt == 'rating':
|
||||
@ -378,9 +382,9 @@ class ManyToManyField(Field):
|
||||
all_cids = set()
|
||||
for cids in ans.itervalues():
|
||||
all_cids = all_cids.union(set(cids))
|
||||
sk_map = {cid: self._sort_key(self.table.id_map[cid])
|
||||
for cid in all_cids}
|
||||
return {id_: (tuple(sk_map[cid] for cid in cids) if cids else
|
||||
sk_map = {cid: self._sort_key(self.table.id_map[cid]) for cid in all_cids}
|
||||
sort_func = (lambda x:tuple(sorted(x))) if self.sort_sort_key else tuple
|
||||
return {id_: (sort_func(sk_map[cid] for cid in cids) if cids else
|
||||
(self._default_sort_key,))
|
||||
for id_, cids in ans.iteritems()}
|
||||
|
||||
|
@ -161,6 +161,25 @@ class ReadingTest(BaseTest):
|
||||
# Test subsorting
|
||||
self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True),
|
||||
('title', True)]), 'Subsort failed')
|
||||
|
||||
# Test sorting of is_multiple fields.
|
||||
|
||||
# Author like fields should be sorted by generating sort names from the
|
||||
# actual values in entry order
|
||||
for field in ('authors', '#authors'):
|
||||
self.assertEqual(
|
||||
cache.set_field(field, {1:('aa bb', 'bb cc', 'cc dd'), 2:('bb aa', 'xx yy'), 3: ('aa bb', 'bb aa')}), {1, 2, 3})
|
||||
self.assertEqual([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3)))
|
||||
self.assertEqual([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3)))
|
||||
|
||||
# All other is_multiple fields should be sorted by sorting the values
|
||||
# for each book and using that as the sort key
|
||||
for field in ('tags', '#tags'):
|
||||
self.assertEqual(
|
||||
cache.set_field(field, {1:('b', 'a'), 2:('c', 'y'), 3: ('b', 'z')}), {1, 2, 3})
|
||||
self.assertEqual([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3)))
|
||||
self.assertEqual([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3)))
|
||||
|
||||
# }}}
|
||||
|
||||
def test_get_metadata(self): # {{{
|
||||
|
@ -685,7 +685,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
elif dt in {'text', 'comments', 'composite', 'enumeration'}:
|
||||
if m['is_multiple'] and not field_obj.is_composite:
|
||||
jv = m['is_multiple']['list_to_ui']
|
||||
do_sort = field == 'tags'
|
||||
do_sort = '&' not in jv
|
||||
if do_sort:
|
||||
def func(idx):
|
||||
return QVariant(jv.join(sorted(fffunc(field_obj, idfunc(idx), default_value=()), key=sort_key)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user