Allow searching for books by id and uuid using the id: and uuid: prefixes

Also create a nicer API for refreshing the set of search prefixes
This commit is contained in:
Kovid Goyal 2014-04-08 10:19:13 +05:30
parent 4a56a211fe
commit 68f20774fc
6 changed files with 29 additions and 12 deletions

View File

@ -157,7 +157,7 @@ class Cache(object):
self.field_metadata.add_grouped_search_terms( self.field_metadata.add_grouped_search_terms(
self._pref('grouped_search_terms', {})) self._pref('grouped_search_terms', {}))
self._search_api.change_locations(self.field_metadata.get_search_terms()) self._refresh_search_locations()
self.dirtied_cache = {x:i for i, (x,) in enumerate( self.dirtied_cache = {x:i for i, (x,) in enumerate(
self.backend.execute('SELECT book FROM metadata_dirtied'))} self.backend.execute('SELECT book FROM metadata_dirtied'))}
@ -1758,6 +1758,10 @@ class Cache(object):
def change_search_locations(self, newlocs): def change_search_locations(self, newlocs):
self._search_api.change_locations(newlocs) self._search_api.change_locations(newlocs)
@write_api
def refresh_search_locations(self):
self._search_api.change_locations(self.field_metadata.get_search_terms())
@write_api @write_api
def dump_and_restore(self, callback=None, sql=None): def dump_and_restore(self, callback=None, sql=None):
return self.backend.dump_and_restore(callback=callback, sql=sql) return self.backend.dump_and_restore(callback=callback, sql=sql)

View File

@ -562,10 +562,16 @@ class Parser(SearchQueryParser): # {{{
if (dt in ('rating', 'int', 'float') or if (dt in ('rating', 'int', 'float') or
(dt == 'composite' and (dt == 'composite' and
fm['display'].get('composite_sort', '') == 'number')): fm['display'].get('composite_sort', '') == 'number')):
field = self.dbcache.fields[location] if location == 'id':
is_many = False
def fi(default_value=None):
for qid in candidates:
yield qid, {qid}
else:
field = self.dbcache.fields[location]
fi, is_many = partial(self.field_iter, location, candidates), field.is_many
return self.num_search( return self.num_search(
icu_lower(query), partial(self.field_iter, location, candidates), icu_lower(query), fi, location, dt, candidates, is_many=is_many)
location, dt, candidates, is_many=field.is_many)
# take care of the 'count' operator for is_multiples # take care of the 'count' operator for is_multiples
if (fm['is_multiple'] and if (fm['is_multiple'] and
@ -602,8 +608,8 @@ class Parser(SearchQueryParser): # {{{
for x, fm in self.field_metadata.iteritems(): for x, fm in self.field_metadata.iteritems():
if x.startswith('@'): if x.startswith('@'):
continue continue
if fm['search_terms'] and x != 'series_sort': if fm['search_terms'] and x not in {'series_sort', 'id'}:
if x not in self.virtual_fields: if x not in self.virtual_fields and x != 'uuid':
# We dont search virtual fields because if we do, search # We dont search virtual fields because if we do, search
# caching will not be used # caching will not be used
all_locs.add(x) all_locs.add(x)

View File

@ -274,7 +274,7 @@ class ReadingTest(BaseTest):
'rating:false', 'rating:>4', 'tags:#<2', 'tags:#>7', 'rating:false', 'rating:>4', 'tags:#<2', 'tags:#>7',
'cover:false', 'cover:true', '#float:>11', '#float:<1k', 'cover:false', 'cover:true', '#float:>11', '#float:<1k',
'#float:10.01', '#float:false', 'series_index:1', '#float:10.01', '#float:false', 'series_index:1',
'series_index:<3', 'id:1', 'id:>2', 'series_index:<3',
# Bool tests # Bool tests
'#yesno:true', '#yesno:false', '#yesno:yes', '#yesno:no', '#yesno:true', '#yesno:false', '#yesno:yes', '#yesno:no',
@ -289,7 +289,7 @@ class ReadingTest(BaseTest):
# Text tests # Text tests
'title:="Title One"', 'title:~title', '#enum:=one', '#enum:tw', 'title:="Title One"', 'title:~title', '#enum:=one', '#enum:tw',
'#enum:false', '#enum:true', 'series:one', 'tags:one', 'tags:true', '#enum:false', '#enum:true', 'series:one', 'tags:one', 'tags:true',
'tags:false', '2', 'one', '20.02', '"publisher one"', 'tags:false', 'uuid:2', 'one', '20.02', '"publisher one"',
'"my comments one"', '"my comments one"',
# User categories # User categories
@ -312,6 +312,13 @@ class ReadingTest(BaseTest):
'Old result: %r != New result: %r for search: %s'%( 'Old result: %r != New result: %r for search: %s'%(
ans, nr, query)) ans, nr, query))
# Test searching by id, which was introduced in the new backend
self.assertEqual(cache.search('id:1', ''), {1})
self.assertEqual(cache.search('id:>1', ''), {2, 3})
# Note that the old db searched uuid for un-prefixed searches, the new
# db does not, for performance
# }}} # }}}
def test_get_categories(self): # {{{ def test_get_categories(self): # {{{

View File

@ -876,7 +876,7 @@ class TagsModel(QAbstractItemModel): # {{{
tb_cats.add_user_category(label=u'@' + cat, name=cat) tb_cats.add_user_category(label=u'@' + cat, name=cat)
except ValueError: except ValueError:
traceback.print_exc() traceback.print_exc()
self.db.data.change_search_locations(self.db.field_metadata.get_search_terms()) self.db.new_api.refresh_search_locations()
if len(self.db.saved_search_names()): if len(self.db.saved_search_names()):
tb_cats.add_search_category(label='search', name=_('Searches')) tb_cats.add_search_category(label='search', name=_('Searches'))

View File

@ -111,7 +111,7 @@ class TagBrowserMixin(object): # {{{
db.field_metadata.remove_user_categories() db.field_metadata.remove_user_categories()
for k in d.categories: for k in d.categories:
db.field_metadata.add_user_category('@' + k, k) db.field_metadata.add_user_category('@' + k, k)
db.data.change_search_locations(db.field_metadata.get_search_terms()) db.new_api.refresh_search_locations()
self.tags_view.recount() self.tags_view.recount()
def do_delete_user_category(self, category_name): def do_delete_user_category(self, category_name):

View File

@ -209,7 +209,7 @@ def _builtin_field_metadata():
'is_multiple':{}, 'is_multiple':{},
'kind':'field', 'kind':'field',
'name':None, 'name':None,
'search_terms':[], 'search_terms':['id'],
'is_custom':False, 'is_custom':False,
'is_category':False, 'is_category':False,
'is_csp': False}), 'is_csp': False}),
@ -329,7 +329,7 @@ def _builtin_field_metadata():
'is_multiple':{}, 'is_multiple':{},
'kind':'field', 'kind':'field',
'name':None, 'name':None,
'search_terms':[], 'search_terms':['uuid'],
'is_custom':False, 'is_custom':False,
'is_category':False, 'is_category':False,
'is_csp': False}), 'is_csp': False}),