mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement saved searches API
This commit is contained in:
parent
72849dfee6
commit
b60530fafe
@ -89,7 +89,7 @@ class Cache(object):
|
||||
self.formatter_template_cache = {}
|
||||
self.dirtied_cache = {}
|
||||
self.dirtied_sequence = 0
|
||||
self._search_api = Search(self.field_metadata.get_search_terms())
|
||||
self._search_api = Search(self, 'saved_searches', self.field_metadata.get_search_terms())
|
||||
|
||||
# Implement locking for all simple read/write API methods
|
||||
# An unlocked version of the method is stored with the name starting
|
||||
@ -127,9 +127,8 @@ class Cache(object):
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
# TODO: Saved searches
|
||||
# if len(saved_searches().names()):
|
||||
# self.field_metadata.add_search_category(label='search', name=_('Searches'))
|
||||
if len(self._search_api.get_saved_searches().names()):
|
||||
self.field_metadata.add_search_category(label='search', name=_('Searches'))
|
||||
|
||||
self.field_metadata.add_grouped_search_terms(
|
||||
self._pref('grouped_search_terms', {}))
|
||||
@ -141,6 +140,11 @@ class Cache(object):
|
||||
if self.dirtied_cache:
|
||||
self.dirtied_sequence = max(self.dirtied_cache.itervalues())+1
|
||||
|
||||
@property
|
||||
def prefs(self):
|
||||
'For internal use only (used by SavedSearchQueries). For thread-safe access to the preferences, use the pref() and set_pref() methods.'
|
||||
return self.backend.prefs
|
||||
|
||||
@write_api
|
||||
def initialize_template_cache(self):
|
||||
self.formatter_template_cache = {}
|
||||
|
@ -22,6 +22,7 @@ from calibre.db.categories import CATEGORY_SORTS
|
||||
from calibre.db.view import View
|
||||
from calibre.db.write import clean_identifier
|
||||
from calibre.utils.date import utcnow
|
||||
from calibre.utils.search_query_parser import set_saved_searches
|
||||
|
||||
def cleanup_tags(tags):
|
||||
tags = [x.strip().replace(',', ';') for x in tags if x.strip()]
|
||||
@ -73,6 +74,9 @@ class LibraryDatabase(object):
|
||||
|
||||
self.last_update_check = self.last_modified()
|
||||
|
||||
if not self.is_second_db:
|
||||
set_saved_searches(self, 'saved_searches')
|
||||
|
||||
def close(self):
|
||||
self.backend.close()
|
||||
|
||||
|
@ -15,7 +15,7 @@ from calibre.utils.config_base import prefs
|
||||
from calibre.utils.date import parse_date, UNDEFINED_DATE, now
|
||||
from calibre.utils.icu import primary_find
|
||||
from calibre.utils.localization import lang_map, canonicalize_lang
|
||||
from calibre.utils.search_query_parser import SearchQueryParser, ParseException
|
||||
from calibre.utils.search_query_parser import SearchQueryParser, ParseException, SavedSearchQueries
|
||||
|
||||
CONTAINS_MATCH = 0
|
||||
EQUALS_MATCH = 1
|
||||
@ -392,7 +392,7 @@ class Parser(SearchQueryParser):
|
||||
|
||||
def __init__(self, dbcache, all_book_ids, gst, date_search, num_search,
|
||||
bool_search, keypair_search, limit_search_columns, limit_search_columns_to,
|
||||
locations, virtual_fields):
|
||||
locations, virtual_fields, get_saved_searches):
|
||||
self.dbcache, self.all_book_ids = dbcache, all_book_ids
|
||||
self.all_search_locations = frozenset(locations)
|
||||
self.grouped_search_terms = gst
|
||||
@ -403,7 +403,7 @@ class Parser(SearchQueryParser):
|
||||
self.virtual_fields = virtual_fields or {}
|
||||
if 'marked' not in self.virtual_fields:
|
||||
self.virtual_fields['marked'] = self
|
||||
super(Parser, self).__init__(locations, optimize=True)
|
||||
super(Parser, self).__init__(locations, optimize=True, get_saved_searches=get_saved_searches)
|
||||
|
||||
@property
|
||||
def field_metadata(self):
|
||||
@ -651,12 +651,16 @@ class Parser(SearchQueryParser):
|
||||
|
||||
class Search(object):
|
||||
|
||||
def __init__(self, all_search_locations=()):
|
||||
def __init__(self, db, opt_name, all_search_locations=()):
|
||||
self.all_search_locations = all_search_locations
|
||||
self.date_search = DateSearch()
|
||||
self.num_search = NumericSearch()
|
||||
self.bool_search = BooleanSearch()
|
||||
self.keypair_search = KeyPairSearch()
|
||||
self.saved_searches = SavedSearchQueries(db, opt_name)
|
||||
|
||||
def get_saved_searches(self):
|
||||
return self.saved_searches
|
||||
|
||||
def change_locations(self, newlocs):
|
||||
self.all_search_locations = newlocs
|
||||
@ -689,11 +693,11 @@ class Search(object):
|
||||
self.keypair_search,
|
||||
prefs['limit_search_columns'],
|
||||
prefs['limit_search_columns_to'], self.all_search_locations,
|
||||
virtual_fields)
|
||||
virtual_fields, self.get_saved_searches)
|
||||
|
||||
try:
|
||||
ret = sqp.parse(q)
|
||||
finally:
|
||||
sqp.dbcache = None
|
||||
sqp.dbcache = sqp.get_saved_searches = None
|
||||
return ret
|
||||
|
||||
|
@ -149,8 +149,6 @@ class ReadingTest(BaseTest):
|
||||
'#tags':[3, 2, 1],
|
||||
'#yesno':[3, 1, 2],
|
||||
'#comments':[3, 2, 1],
|
||||
# TODO: Add an empty book to the db and ensure that empty
|
||||
# fields sort the same as they do in db2
|
||||
}.iteritems():
|
||||
x = list(reversed(order))
|
||||
self.assertEqual(order, cache.multisort([(field, True)],
|
||||
|
@ -40,7 +40,7 @@ class SavedSearchQueries(object):
|
||||
self.queries = {}
|
||||
try:
|
||||
self._db = weakref.ref(db)
|
||||
except:
|
||||
except TypeError:
|
||||
# db could be None
|
||||
self._db = lambda : None
|
||||
|
||||
@ -292,9 +292,10 @@ class SearchQueryParser(object):
|
||||
failed.append(test[0])
|
||||
return failed
|
||||
|
||||
def __init__(self, locations, test=False, optimize=False):
|
||||
def __init__(self, locations, test=False, optimize=False, get_saved_searches=None):
|
||||
self.sqp_initialize(locations, test=test, optimize=optimize)
|
||||
self.parser = Parser()
|
||||
self.get_saved_searches = saved_searches if get_saved_searches is None else get_saved_searches
|
||||
|
||||
def sqp_change_locations(self, locations):
|
||||
self.sqp_initialize(locations, optimize=self.optimize)
|
||||
@ -367,7 +368,7 @@ class SearchQueryParser(object):
|
||||
raise ParseException(_('Recursive saved search: {0}').format(query))
|
||||
if self.recurse_level > 5:
|
||||
self.searches_seen.add(query)
|
||||
return self._parse(saved_searches().lookup(query), candidates)
|
||||
return self._parse(self.get_saved_searches().lookup(query), candidates)
|
||||
except ParseException as e:
|
||||
raise e
|
||||
except: # convert all exceptions (e.g., missing key) to a parse error
|
||||
|
Loading…
x
Reference in New Issue
Block a user