From 4b2e7b883b26b163139b4815ceab5b69b7da6edf Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 26 Apr 2023 15:27:41 +0200 Subject: [PATCH] Changed the quick search behavior so that it allows title and author in the same query. Also word order does not matter anymore. +some more comments --- cps/db.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/cps/db.py b/cps/db.py index 8eef992d..644041da 100644 --- a/cps/db.py +++ b/cps/db.py @@ -887,14 +887,12 @@ class CalibreDB: self.session.connection().connection.connection.create_function("lower", 1, lcase) q = list() #splits search term into single words - author_terms = re.split("[, ]+", term) - + words = re.split("[, ]+", term) + #put the longest words first to make queries more efficient + words.sort(key=len,reverse=True) #search authors for match - for author_term in author_terms: - q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + author_term + "%"))) - - - + for word in words: + q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + word + "%"))) query = self.generate_linked_query(config.config_read_column, Books) if len(join) == 6: @@ -906,25 +904,29 @@ class CalibreDB: elif len(join) == 1: query = query.outerjoin(join[0]) + filter_expression=[] cc = self.get_cc_columns(config, filter_config_custom_read=True) - - #search each category for exact matches with the tag - filter_expression = [Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")), - Books.series.any(func.lower(Series.name).ilike("%" + term + "%")), - Books.authors.any(and_(*q)), - Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")), - func.lower(Books.title).ilike("%" + term + "%")] - - for c in cc: if c.datatype not in ["datetime", "rating", "bool", "int", "float"]: filter_expression.append( getattr(Books, 'custom_column_' + str(c.id)).any( - func.lower(cc_classes[c.id].value).ilike("%" + term + "%"))) + func.lower(cc_classes[c.id].value).ilike("%" + term + "%"))) #TODO ? + # filter out multiple languages and archived books, + results=query.filter(self.common_filters(True)) - #filter out multiple languages and archived books, then return all that match at least one of filter_expression - return query.filter(self.common_filters(True)).filter(or_(*filter_expression)) + for word in words: + filter_expression=[ + Books.tags.any(func.lower(Tags.name).ilike("%" + word + "%")), + Books.series.any(func.lower(Series.name).ilike("%" + word + "%")), + #change to or_ to allow mix of title and author in query term + Books.authors.any(or_(*q)), + Books.publishers.any(func.lower(Publishers.name).ilike("%" + word + "%")), + func.lower(Books.title).ilike("%" + word + "%") + ] + results=results.filter(or_(*filter_expression)) + + return results def get_cc_columns(self, config, filter_config_custom_read=False): tmp_cc = self.session.query(CustomColumns).filter(CustomColumns.datatype.notin_(cc_exceptions)).all()