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.tables import ONE_ONE, MANY_ONE, MANY_MANY, null
|
||||||
from calibre.db.write import Writer
|
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.config_base import tweaks
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.utils.date import UNDEFINED_DATE
|
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._sort_key = lambda x:sort_key(calibre_langcode_to_name(x))
|
||||||
self.is_multiple = (bool(self.metadata['is_multiple']) or self.name ==
|
self.is_multiple = (bool(self.metadata['is_multiple']) or self.name ==
|
||||||
'formats')
|
'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.default_value = {} if name == 'identifiers' else () if self.is_multiple else None
|
||||||
self.category_formatter = type(u'')
|
self.category_formatter = type(u'')
|
||||||
if dt == 'rating':
|
if dt == 'rating':
|
||||||
@ -378,9 +382,9 @@ class ManyToManyField(Field):
|
|||||||
all_cids = set()
|
all_cids = set()
|
||||||
for cids in ans.itervalues():
|
for cids in ans.itervalues():
|
||||||
all_cids = all_cids.union(set(cids))
|
all_cids = all_cids.union(set(cids))
|
||||||
sk_map = {cid: self._sort_key(self.table.id_map[cid])
|
sk_map = {cid: self._sort_key(self.table.id_map[cid]) for cid in all_cids}
|
||||||
for cid in all_cids}
|
sort_func = (lambda x:tuple(sorted(x))) if self.sort_sort_key else tuple
|
||||||
return {id_: (tuple(sk_map[cid] for cid in cids) if cids else
|
return {id_: (sort_func(sk_map[cid] for cid in cids) if cids else
|
||||||
(self._default_sort_key,))
|
(self._default_sort_key,))
|
||||||
for id_, cids in ans.iteritems()}
|
for id_, cids in ans.iteritems()}
|
||||||
|
|
||||||
|
@ -161,6 +161,25 @@ class ReadingTest(BaseTest):
|
|||||||
# Test subsorting
|
# Test subsorting
|
||||||
self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True),
|
self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True),
|
||||||
('title', True)]), 'Subsort failed')
|
('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): # {{{
|
def test_get_metadata(self): # {{{
|
||||||
|
@ -685,7 +685,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
elif dt in {'text', 'comments', 'composite', 'enumeration'}:
|
elif dt in {'text', 'comments', 'composite', 'enumeration'}:
|
||||||
if m['is_multiple'] and not field_obj.is_composite:
|
if m['is_multiple'] and not field_obj.is_composite:
|
||||||
jv = m['is_multiple']['list_to_ui']
|
jv = m['is_multiple']['list_to_ui']
|
||||||
do_sort = field == 'tags'
|
do_sort = '&' not in jv
|
||||||
if do_sort:
|
if do_sort:
|
||||||
def func(idx):
|
def func(idx):
|
||||||
return QVariant(jv.join(sorted(fffunc(field_obj, idfunc(idx), default_value=()), key=sort_key)))
|
return QVariant(jv.join(sorted(fffunc(field_obj, idfunc(idx), default_value=()), key=sort_key)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user