diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index f8235d5b85..9ba5a3e348 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -949,9 +949,12 @@ class DB: from .notes.connect import Notes self.notes = Notes(self) - def delete_category_items(self, field_name, table_name, item_map, link_table_name='', link_col_name=''): + def clear_notes_for_category_items(self, field_name, item_map): for item_id, item_val in item_map.items(): self.notes.set_note(self.conn, field_name, item_id, item_val or '') + + def delete_category_items(self, field_name, table_name, item_map, link_table_name='', link_col_name=''): + self.clear_notes_for_category_items(field_name, item_map) bindings = tuple((x,) for x in item_map) if link_table_name and link_col_name: self.executemany(f'DELETE FROM {link_table_name} WHERE {link_col_name}=?', bindings) diff --git a/src/calibre/db/tests/notes.py b/src/calibre/db/tests/notes.py index 6c785ae59d..0b9e3c60fa 100644 --- a/src/calibre/db/tests/notes.py +++ b/src/calibre/db/tests/notes.py @@ -58,13 +58,37 @@ def test_notes_api(self: 'NotesTest'): def test_cache_api(self): cache, notes = self.create_notes_db() + authors = cache.field_for('authors', 1) + author_id = cache.get_item_id('authors', authors[0]) + doc = 'simple notes for an author' + h1 = cache.add_notes_resource(b'resource1', 'r1.jpg') + h2 = cache.add_notes_resource(b'resource2', 'r1.jpg') + cache.set_notes_for('authors', author_id, doc, resource_ids=(h1, h2)) + # test renaming to a new author preserves notes + cache.rename_items('authors', {author_id: 'renamed author'}) + raid = cache.get_item_id('authors', 'renamed author') + self.ae(cache.notes_resources_used_by('authors', raid), frozenset({h1, h2})) + self.ae(cache.get_notes_resource(h1)['data'], b'resource1') + self.ae(cache.get_notes_resource(h2)['data'], b'resource2') + # test renaming to an existing author preserves notes + cache.rename_items('authors', {raid: 'Author One'}) + raid = cache.get_item_id('authors', 'Author One') + self.ae(cache.notes_resources_used_by('authors', raid), frozenset({h1, h2})) + self.ae(cache.get_notes_resource(h1)['data'], b'resource1') + self.ae(cache.get_notes_resource(h2)['data'], b'resource2') + # test removing author from db retires notes + cache.set_field('authors', {bid:('New Author',) for bid in cache.all_book_ids()}) + self.ae(len(cache.all_field_ids('authors')), 1) + before = os.listdir(notes.retired_dir) + self.ae(len(before), 1) + class NotesTest(BaseTest): ae = BaseTest.assertEqual def create_notes_db(self): - cache = self.init_cache() + cache = self.init_cache(self.cloned_library) cache.backend.notes.max_retired_items = 1 return cache, cache.backend.notes diff --git a/src/calibre/db/write.py b/src/calibre/db/write.py index 48ebd1fd03..27bf6879fc 100644 --- a/src/calibre/db/write.py +++ b/src/calibre/db/write.py @@ -378,9 +378,9 @@ def many_one(book_id_val_map, db, field, allow_case_change, *args): iteritems(updated))) # Remove no longer used items - remove = {item_id for item_id in table.id_map if not - table.col_book_map.get(item_id, False)} + remove = {item_id:item_val for item_id, item_val in table.id_map.items() if not table.col_book_map.get(item_id, False)} if remove: + db.clear_notes_for_category_items(table.name, remove) db.executemany('DELETE FROM %s WHERE id=?'%m['table'], ((item_id,) for item_id in remove)) for item_id in remove: @@ -482,9 +482,9 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): field.author_sort_field.writer.set_books(aus_map, db) # Remove no longer used items - remove = {item_id for item_id in table.id_map if not - table.col_book_map.get(item_id, False)} + remove = {item_id:item_val for item_id, item_val in table.id_map.items() if not table.col_book_map.get(item_id, False)} if remove: + db.clear_notes_for_category_items(table.name, remove) db.executemany('DELETE FROM %s WHERE id=?'%m['table'], ((item_id,) for item_id in remove)) for item_id in remove: @@ -494,7 +494,6 @@ def many_many(book_id_val_map, db, field, allow_case_change, *args): table.asort_map.pop(item_id, None) if hasattr(table, 'link_map'): table.link_map.pop(item_id, None) - return dirtied # }}}