mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
remove_items() API
This commit is contained in:
parent
9ea6e0d2a9
commit
b2163e3846
@ -265,8 +265,10 @@ class Cache(object):
|
|||||||
for name, field in self.fields.iteritems():
|
for name, field in self.fields.iteritems():
|
||||||
if name[0] == '#' and name.endswith('_index'):
|
if name[0] == '#' and name.endswith('_index'):
|
||||||
field.series_field = self.fields[name[:-len('_index')]]
|
field.series_field = self.fields[name[:-len('_index')]]
|
||||||
|
self.fields[name[:-len('_index')]].index_field = field
|
||||||
elif name == 'series_index':
|
elif name == 'series_index':
|
||||||
field.series_field = self.fields['series']
|
field.series_field = self.fields['series']
|
||||||
|
self.fields['series'].index_field = field
|
||||||
elif name == 'authors':
|
elif name == 'authors':
|
||||||
field.author_sort_field = self.fields['author_sort']
|
field.author_sort_field = self.fields['author_sort']
|
||||||
elif name == 'title':
|
elif name == 'title':
|
||||||
@ -1179,6 +1181,18 @@ class Cache(object):
|
|||||||
else:
|
else:
|
||||||
table.remove_books(book_ids, self.backend)
|
table.remove_books(book_ids, self.backend)
|
||||||
|
|
||||||
|
@write_api
|
||||||
|
def remove_items(self, field, item_ids):
|
||||||
|
''' Delete all items in the specified field with the specified ids. Returns the set of affected book ids. '''
|
||||||
|
field = self.fields[field]
|
||||||
|
affected_books = field.table.remove_items(item_ids, self.backend)
|
||||||
|
if affected_books:
|
||||||
|
if hasattr(field, 'index_field'):
|
||||||
|
self._set_field(field.index_field.name, {bid:1.0 for bid in affected_books})
|
||||||
|
else:
|
||||||
|
self._mark_as_dirty(affected_books)
|
||||||
|
return affected_books
|
||||||
|
|
||||||
@write_api
|
@write_api
|
||||||
def add_custom_book_data(self, name, val_map, delete_first=False):
|
def add_custom_book_data(self, name, val_map, delete_first=False):
|
||||||
''' Add data for name where val_map is a map of book_ids to values. If
|
''' Add data for name where val_map is a map of book_ids to values. If
|
||||||
|
@ -204,6 +204,21 @@ class ManyToOneTable(Table):
|
|||||||
[(x,) for x in clean])
|
[(x,) for x in clean])
|
||||||
return clean
|
return clean
|
||||||
|
|
||||||
|
def remove_items(self, item_ids, db):
|
||||||
|
affected_books = set()
|
||||||
|
for item_id in item_ids:
|
||||||
|
val = self.id_map.pop(item_id, null)
|
||||||
|
if val is null:
|
||||||
|
continue
|
||||||
|
book_ids = self.col_book_map.pop(item_id, set())
|
||||||
|
for book_id in book_ids:
|
||||||
|
self.book_col_map.pop(book_id, None)
|
||||||
|
affected_books.update(book_ids)
|
||||||
|
item_ids = tuple((x,) for x in item_ids)
|
||||||
|
db.conn.executemany('DELETE FROM {0} WHERE {1}=?'.format(self.link_table, self.metadata['link_column']), item_ids)
|
||||||
|
db.conn.executemany('DELETE FROM {0} WHERE id=?'.format(self.metadata['table']), item_ids)
|
||||||
|
return affected_books
|
||||||
|
|
||||||
class ManyToManyTable(ManyToOneTable):
|
class ManyToManyTable(ManyToOneTable):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -250,6 +265,21 @@ class ManyToManyTable(ManyToOneTable):
|
|||||||
[(x,) for x in clean])
|
[(x,) for x in clean])
|
||||||
return clean
|
return clean
|
||||||
|
|
||||||
|
def remove_items(self, item_ids, db):
|
||||||
|
affected_books = set()
|
||||||
|
for item_id in item_ids:
|
||||||
|
val = self.id_map.pop(item_id, null)
|
||||||
|
if val is null:
|
||||||
|
continue
|
||||||
|
book_ids = self.col_book_map.pop(item_id, set())
|
||||||
|
for book_id in book_ids:
|
||||||
|
self.book_col_map[book_id] = tuple(x for x in self.book_col_map.get(book_id, ()) if x != item_id)
|
||||||
|
affected_books.update(book_ids)
|
||||||
|
item_ids = tuple((x,) for x in item_ids)
|
||||||
|
db.conn.executemany('DELETE FROM {0} WHERE {1}=?'.format(self.link_table, self.metadata['link_column']), item_ids)
|
||||||
|
db.conn.executemany('DELETE FROM {0} WHERE id=?'.format(self.metadata['table']), item_ids)
|
||||||
|
return affected_books
|
||||||
|
|
||||||
class AuthorsTable(ManyToManyTable):
|
class AuthorsTable(ManyToManyTable):
|
||||||
|
|
||||||
def read_id_maps(self, db):
|
def read_id_maps(self, db):
|
||||||
@ -274,6 +304,9 @@ class AuthorsTable(ManyToManyTable):
|
|||||||
self.asort_map.pop(item_id, None)
|
self.asort_map.pop(item_id, None)
|
||||||
return clean
|
return clean
|
||||||
|
|
||||||
|
def remove_items(self, item_ids, db):
|
||||||
|
raise ValueError('Direct removal of authors is not allowed')
|
||||||
|
|
||||||
class FormatsTable(ManyToManyTable):
|
class FormatsTable(ManyToManyTable):
|
||||||
|
|
||||||
do_clean_on_remove = False
|
do_clean_on_remove = False
|
||||||
@ -331,6 +364,9 @@ class FormatsTable(ManyToManyTable):
|
|||||||
|
|
||||||
return {book_id:zero_max(book_id) for book_id in formats_map}
|
return {book_id:zero_max(book_id) for book_id in formats_map}
|
||||||
|
|
||||||
|
def remove_items(self, item_ids, db):
|
||||||
|
raise NotImplementedError('Cannot delete a format directly')
|
||||||
|
|
||||||
def update_fmt(self, book_id, fmt, fname, size, db):
|
def update_fmt(self, book_id, fmt, fname, size, db):
|
||||||
fmts = list(self.book_col_map.get(book_id, []))
|
fmts = list(self.book_col_map.get(book_id, []))
|
||||||
try:
|
try:
|
||||||
@ -381,4 +417,6 @@ class IdentifiersTable(ManyToManyTable):
|
|||||||
clean.add(item_id)
|
clean.add(item_id)
|
||||||
return clean
|
return clean
|
||||||
|
|
||||||
|
def remove_items(self, item_ids, db):
|
||||||
|
raise NotImplementedError('Direct deletion of identifiers is not implemented')
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ class LegacyTest(BaseTest):
|
|||||||
'clean_user_categories', 'cleanup_tags', 'books_list_filter', 'conn', 'connect', 'construct_file_name',
|
'clean_user_categories', 'cleanup_tags', 'books_list_filter', 'conn', 'connect', 'construct_file_name',
|
||||||
'construct_path_name', 'clear_dirtied', 'commit_dirty_cache', 'initialize_database', 'initialize_dynamic',
|
'construct_path_name', 'clear_dirtied', 'commit_dirty_cache', 'initialize_database', 'initialize_dynamic',
|
||||||
'run_import_plugins', 'vacuum', 'set_path', 'row', 'row_factory', 'rows', 'rmtree', 'series_index_pat',
|
'run_import_plugins', 'vacuum', 'set_path', 'row', 'row_factory', 'rows', 'rmtree', 'series_index_pat',
|
||||||
'import_old_database', 'dirtied_lock', 'dirtied_cache', 'dirty_queue_length',
|
'import_old_database', 'dirtied_lock', 'dirtied_cache', 'dirty_queue_length', 'dirty_books_referencing',
|
||||||
}
|
}
|
||||||
SKIP_ARGSPEC = {
|
SKIP_ARGSPEC = {
|
||||||
'__init__', 'get_next_series_num_for', 'has_book', 'author_sort_from_authors',
|
'__init__', 'get_next_series_num_for', 'has_book', 'author_sort_from_authors',
|
||||||
|
@ -436,3 +436,41 @@ class WritingTest(BaseTest):
|
|||||||
self.assertFalse(cache.has_conversion_options(all_ids))
|
self.assertFalse(cache.has_conversion_options(all_ids))
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
def test_remove_items(self): # {{{
|
||||||
|
' Test removal of many-(many,one) items '
|
||||||
|
cache = self.init_cache()
|
||||||
|
tmap = cache.get_id_map('tags')
|
||||||
|
self.assertEqual(cache.remove_items('tags', tmap), {1, 2})
|
||||||
|
tmap = cache.get_id_map('#tags')
|
||||||
|
t = {v:k for k, v in tmap.iteritems()}['My Tag Two']
|
||||||
|
self.assertEqual(cache.remove_items('#tags', (t,)), {1, 2})
|
||||||
|
|
||||||
|
smap = cache.get_id_map('series')
|
||||||
|
self.assertEqual(cache.remove_items('series', smap), {1, 2})
|
||||||
|
smap = cache.get_id_map('#series')
|
||||||
|
s = {v:k for k, v in smap.iteritems()}['My Series Two']
|
||||||
|
self.assertEqual(cache.remove_items('#series', (s,)), {1})
|
||||||
|
|
||||||
|
for c in (cache, self.init_cache()):
|
||||||
|
self.assertFalse(c.get_id_map('tags'))
|
||||||
|
self.assertFalse(c.all_field_names('tags'))
|
||||||
|
for bid in c.all_book_ids():
|
||||||
|
self.assertFalse(c.field_for('tags', bid))
|
||||||
|
|
||||||
|
self.assertEqual(len(c.get_id_map('#tags')), 1)
|
||||||
|
self.assertEqual(c.all_field_names('#tags'), {'My Tag One'})
|
||||||
|
for bid in c.all_book_ids():
|
||||||
|
self.assertIn(c.field_for('#tags', bid), ((), ('My Tag One',)))
|
||||||
|
|
||||||
|
for bid in (1, 2):
|
||||||
|
self.assertEqual(c.field_for('series_index', bid), 1.0)
|
||||||
|
self.assertFalse(c.get_id_map('series'))
|
||||||
|
self.assertFalse(c.all_field_names('series'))
|
||||||
|
for bid in c.all_book_ids():
|
||||||
|
self.assertFalse(c.field_for('series', bid))
|
||||||
|
|
||||||
|
self.assertEqual(c.field_for('series_index', 1), 1.0)
|
||||||
|
self.assertEqual(c.all_field_names('#series'), {'My Series One'})
|
||||||
|
for bid in c.all_book_ids():
|
||||||
|
self.assertIn(c.field_for('#series', bid), (None, 'My Series One'))
|
||||||
|
# }}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user