mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Initial implementation of remove_book(), needs testing
This commit is contained in:
parent
20920b37b2
commit
0711e03bd4
@ -29,7 +29,7 @@ from calibre.utils.magick.draw import save_cover_data_to
|
||||
from calibre.utils.recycle_bin import delete_tree, delete_file
|
||||
from calibre.db.tables import (OneToOneTable, ManyToOneTable, ManyToManyTable,
|
||||
SizeTable, FormatsTable, AuthorsTable, IdentifiersTable, PathTable,
|
||||
CompositeTable, LanguagesTable, UUIDTable)
|
||||
CompositeTable, UUIDTable)
|
||||
# }}}
|
||||
|
||||
'''
|
||||
@ -711,7 +711,6 @@ class DB(object):
|
||||
'authors':AuthorsTable,
|
||||
'formats':FormatsTable,
|
||||
'identifiers':IdentifiersTable,
|
||||
'languages':LanguagesTable,
|
||||
}.get(col, ManyToManyTable)
|
||||
tables[col] = cls(col, self.field_metadata[col].copy())
|
||||
|
||||
@ -1165,5 +1164,16 @@ class DB(object):
|
||||
with lopen(path, 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
def remove_books(self, path_map, permanent=False):
|
||||
for book_id, path in path_map.iteritems():
|
||||
if path:
|
||||
path = os.path.join(self.library_path, path)
|
||||
if os.path.exists(path):
|
||||
self.rmtree(path, permanent=permanent)
|
||||
parent = os.path.dirname(path)
|
||||
if len(os.listdir(parent)) == 0:
|
||||
self.rmtree(parent, permanent=permanent)
|
||||
self.conn.executemany(
|
||||
'DELETE FROM books WHERE id=?', [(x,) for x in path_map])
|
||||
# }}}
|
||||
|
||||
|
@ -1129,6 +1129,19 @@ class Cache(object):
|
||||
self._add_format(book_id, fmt, stream_or_path, dbapi=dbapi)
|
||||
return ids, duplicates
|
||||
|
||||
@write_api
|
||||
def remove_books(self, book_ids, permanent=False):
|
||||
path_map = {}
|
||||
for book_id in book_ids:
|
||||
try:
|
||||
path = self._field_for('path', book_id).replace('/', os.sep)
|
||||
except:
|
||||
path = None
|
||||
path_map[book_id] = path
|
||||
self.backend.remove_books(path_map, permanent=permanent)
|
||||
for field in self.fields.itervalues():
|
||||
field.table.remove_books(book_ids, self.backend)
|
||||
|
||||
# }}}
|
||||
|
||||
class SortKey(object): # {{{
|
||||
|
@ -20,6 +20,10 @@ _c_speedup = plugins['speedup'][0]
|
||||
|
||||
ONE_ONE, MANY_ONE, MANY_MANY = xrange(3)
|
||||
|
||||
class Null:
|
||||
pass
|
||||
null = Null()
|
||||
|
||||
def _c_convert_timestamp(val):
|
||||
if not val:
|
||||
return None
|
||||
@ -55,6 +59,9 @@ class Table(object):
|
||||
self.link_table = (link_table if link_table else
|
||||
'books_%s_link'%self.metadata['table'])
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
return set()
|
||||
|
||||
class VirtualTable(Table):
|
||||
|
||||
'''
|
||||
@ -83,6 +90,14 @@ class OneToOneTable(Table):
|
||||
self.metadata['column'], self.metadata['table'])):
|
||||
self.book_col_map[row[0]] = self.unserialize(row[1])
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = set()
|
||||
for book_id in book_ids:
|
||||
val = self.book_col_map.pop(book_id, null)
|
||||
if val is not null:
|
||||
clean.add(val)
|
||||
return clean
|
||||
|
||||
class PathTable(OneToOneTable):
|
||||
|
||||
def set_path(self, book_id, path, db):
|
||||
@ -113,6 +128,15 @@ class UUIDTable(OneToOneTable):
|
||||
self.uuid_to_id_map.pop(self.book_col_map.get(book_id, None), None) # discard old uuid
|
||||
self.uuid_to_id_map[uuid] = book_id
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = set()
|
||||
for book_id in book_ids:
|
||||
val = self.book_col_map.pop(book_id, null)
|
||||
if val is not null:
|
||||
self.uuid_to_id_map.pop(val, None)
|
||||
clean.add(val)
|
||||
return clean
|
||||
|
||||
class CompositeTable(OneToOneTable):
|
||||
|
||||
def read(self, db):
|
||||
@ -124,6 +148,9 @@ class CompositeTable(OneToOneTable):
|
||||
self.composite_sort = d.get('composite_sort', False)
|
||||
self.use_decorations = d.get('use_decorations', False)
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
return set()
|
||||
|
||||
class ManyToOneTable(Table):
|
||||
|
||||
'''
|
||||
@ -156,6 +183,27 @@ class ManyToOneTable(Table):
|
||||
self.col_book_map[row[1]].add(row[0])
|
||||
self.book_col_map[row[0]] = row[1]
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = set()
|
||||
for book_id in book_ids:
|
||||
item_id = self.book_col_map.pop(book_id, None)
|
||||
if item_id is not None:
|
||||
try:
|
||||
self.col_book_map[item_id].discard(book_id)
|
||||
except KeyError:
|
||||
if self.id_map.pop(item_id, null) is not null:
|
||||
clean.add(item_id)
|
||||
else:
|
||||
if not self.col_book_map[item_id]:
|
||||
del self.col_book_map[item_id]
|
||||
if self.id_map.pop(item_id, null) is not null:
|
||||
clean.add(item_id)
|
||||
if clean:
|
||||
db.conn.executemany(
|
||||
'DELETE FROM {0} WHERE id=?'.format(self.metadata['table']),
|
||||
[(x,) for x in clean])
|
||||
return clean
|
||||
|
||||
class ManyToManyTable(ManyToOneTable):
|
||||
|
||||
'''
|
||||
@ -166,6 +214,7 @@ class ManyToManyTable(ManyToOneTable):
|
||||
|
||||
table_type = MANY_MANY
|
||||
selectq = 'SELECT book, {0} FROM {1} ORDER BY id'
|
||||
do_clean_on_remove = True
|
||||
|
||||
def read_maps(self, db):
|
||||
for row in db.conn.execute(
|
||||
@ -180,6 +229,27 @@ class ManyToManyTable(ManyToOneTable):
|
||||
for key in tuple(self.book_col_map.iterkeys()):
|
||||
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = set()
|
||||
for book_id in book_ids:
|
||||
item_ids = self.book_col_map.pop(book_id, ())
|
||||
for item_id in item_ids:
|
||||
try:
|
||||
self.col_book_map[item_id].discard(book_id)
|
||||
except KeyError:
|
||||
if self.id_map.pop(item_id, null) is not null:
|
||||
clean.add(item_id)
|
||||
else:
|
||||
if not self.col_book_map[item_id]:
|
||||
del self.col_book_map[item_id]
|
||||
if self.id_map.pop(item_id, null) is not null:
|
||||
clean.add(item_id)
|
||||
if clean and self.do_clean_on_remove:
|
||||
db.conn.executemany(
|
||||
'DELETE FROM {0} WHERE id=?'.format(self.metadata['table']),
|
||||
[(x,) for x in clean])
|
||||
return clean
|
||||
|
||||
class AuthorsTable(ManyToManyTable):
|
||||
|
||||
def read_id_maps(self, db):
|
||||
@ -197,8 +267,17 @@ class AuthorsTable(ManyToManyTable):
|
||||
db.conn.executemany('UPDATE authors SET sort=? WHERE id=?',
|
||||
[(v, k) for k, v in aus_map.iteritems()])
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = ManyToManyTable.remove_books(self, book_ids, db)
|
||||
for item_id in clean:
|
||||
self.alink_map.pop(item_id, None)
|
||||
self.asort_map.pop(item_id, None)
|
||||
return clean
|
||||
|
||||
class FormatsTable(ManyToManyTable):
|
||||
|
||||
do_clean_on_remove = False
|
||||
|
||||
def read_id_maps(self, db):
|
||||
pass
|
||||
|
||||
@ -220,6 +299,13 @@ class FormatsTable(ManyToManyTable):
|
||||
for key in tuple(self.book_col_map.iterkeys()):
|
||||
self.book_col_map[key] = tuple(sorted(self.book_col_map[key]))
|
||||
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = ManyToManyTable.remove_books(self, book_ids, db)
|
||||
for book_id in book_ids:
|
||||
self.fname_map.pop(book_id, None)
|
||||
self.size_map.pop(book_id, None)
|
||||
return clean
|
||||
|
||||
def set_fname(self, book_id, fmt, fname, db):
|
||||
self.fname_map[book_id][fmt] = fname
|
||||
db.conn.execute('UPDATE data SET name=? WHERE book=? AND format=?',
|
||||
@ -280,8 +366,19 @@ class IdentifiersTable(ManyToManyTable):
|
||||
self.book_col_map[row[0]] = {}
|
||||
self.book_col_map[row[0]][row[1]] = row[2]
|
||||
|
||||
class LanguagesTable(ManyToManyTable):
|
||||
def remove_books(self, book_ids, db):
|
||||
clean = set()
|
||||
for book_id in book_ids:
|
||||
item_map = self.book_col_map.pop(book_id, {})
|
||||
for item_id in item_map:
|
||||
try:
|
||||
self.col_book_map[item_id].discard(book_id)
|
||||
except KeyError:
|
||||
clean.add(item_id)
|
||||
else:
|
||||
if not self.col_book_map[item_id]:
|
||||
del self.col_book_map[item_id]
|
||||
clean.add(item_id)
|
||||
return clean
|
||||
|
||||
def read_id_maps(self, db):
|
||||
ManyToManyTable.read_id_maps(self, db)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user