From 9827755a9e8d3cafcc93c6770760d070d9d0d3c0 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Tue, 4 May 2021 20:07:04 +0100 Subject: [PATCH 1/2] Bug #1927141: Exception when search testing the length of an is_multiple composite I made get_metadata a keyword argument for compatibility. There are no other uses in base calibre, but ... --- src/calibre/db/fields.py | 17 ++++++++++++++++- src/calibre/db/search.py | 5 +++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 8f37b1a08c..46c8b840cc 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -331,6 +331,21 @@ class CompositeField(OneToOneField): for val, book_ids in iteritems(val_map): yield val, book_ids + def iter_counts(self, candidates, get_metadata=None): + val_map = defaultdict(set) + splitter = self.splitter + for book_id in candidates: + vals = self.get_value_with_cache(book_id, get_metadata) + if splitter: + length = len(list(vv.strip() for vv in vals.split(splitter) if vv.strip())) + elif vals.strip: + length = 1 + else: + length = 0 + val_map[length].add(book_id) + for val, book_ids in iteritems(val_map): + yield val, book_ids + def get_composite_categories(self, tag_class, book_rating_map, book_ids, is_multiple, get_metadata): ans = [] @@ -542,7 +557,7 @@ class ManyToManyField(Field): if book_ids: yield val, book_ids - def iter_counts(self, candidates): + def iter_counts(self, candidates, get_metadata=None): val_map = defaultdict(set) cbm = self.table.book_col_map for book_id in candidates: diff --git a/src/calibre/db/search.py b/src/calibre/db/search.py index 246264b9ef..630ab0e638 100644 --- a/src/calibre/db/search.py +++ b/src/calibre/db/search.py @@ -265,7 +265,7 @@ class NumericSearch(object): # {{{ cast = lambda x: 0 if x is None else int(x) adjust = lambda x: x // 2 else: - # Datatype is empty if the source is a tempate. Assume float + # Datatype is empty if the source is a template. Assume float cast = float if dt in ('float', 'composite', 'half-rating', '') else int mult = 1.0 @@ -609,7 +609,8 @@ class Parser(SearchQueryParser): # {{{ if (fm['is_multiple'] and len(query) > 1 and query[0] == '#' and query[1] in '=<>!'): return self.num_search(icu_lower(query[1:]), partial( - self.dbcache.fields[location].iter_counts, candidates), + self.dbcache.fields[location].iter_counts, candidates, + get_metadata=self.dbcache._get_proxy_metadata), location, dt, candidates) # take care of boolean special case From f6de283e7b72f14195d0e3663f41a06972a0b506 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Tue, 4 May 2021 20:08:49 +0100 Subject: [PATCH 2/2] Ooops ... --- src/calibre/db/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/db/fields.py b/src/calibre/db/fields.py index 46c8b840cc..5d3d7c0808 100644 --- a/src/calibre/db/fields.py +++ b/src/calibre/db/fields.py @@ -338,7 +338,7 @@ class CompositeField(OneToOneField): vals = self.get_value_with_cache(book_id, get_metadata) if splitter: length = len(list(vv.strip() for vv in vals.split(splitter) if vv.strip())) - elif vals.strip: + elif vals.strip(): length = 1 else: length = 0