Delete notes when deleting a custom column

Also change the data dir name
This commit is contained in:
Kovid Goyal 2023-08-22 12:28:13 +05:30
parent 4d7f5b18d1
commit bff37a8054
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 37 additions and 7 deletions

View File

@ -680,11 +680,11 @@ class DB:
def initialize_custom_columns(self): # {{{ def initialize_custom_columns(self): # {{{
self.custom_columns_deleted = False self.custom_columns_deleted = False
self.deleted_fields = []
with self.conn: with self.conn:
# Delete previously marked custom columns # Delete previously marked custom columns
for record in self.conn.get( for (num, label) in self.conn.get(
'SELECT id FROM custom_columns WHERE mark_for_delete=1'): 'SELECT id,label FROM custom_columns WHERE mark_for_delete=1'):
num = record[0]
table, lt = self.custom_table_names(num) table, lt = self.custom_table_names(num)
self.execute('''\ self.execute('''\
DROP INDEX IF EXISTS {table}_idx; DROP INDEX IF EXISTS {table}_idx;
@ -703,6 +703,7 @@ class DB:
'''.format(table=table, lt=lt) '''.format(table=table, lt=lt)
) )
self.prefs.set('update_all_last_mod_dates_on_start', True) self.prefs.set('update_all_last_mod_dates_on_start', True)
self.deleted_fields.append('#'+label)
self.execute('DELETE FROM custom_columns WHERE mark_for_delete=1') self.execute('DELETE FROM custom_columns WHERE mark_for_delete=1')
# Load metadata for custom columns # Load metadata for custom columns

View File

@ -8,7 +8,7 @@ COVER_FILE_NAME = 'cover.jpg'
METADATA_FILE_NAME = 'metadata.opf' METADATA_FILE_NAME = 'metadata.opf'
DEFAULT_TRASH_EXPIRY_TIME_SECONDS = 14 * 86400 DEFAULT_TRASH_EXPIRY_TIME_SECONDS = 14 * 86400
TRASH_DIR_NAME = '.caltrash' TRASH_DIR_NAME = '.caltrash'
NOTES_DIR_NAME = '.notes' NOTES_DIR_NAME = '.calnotes'
DATA_DIR_NAME = 'data' DATA_DIR_NAME = 'data'
DATA_FILE_PATTERN = f'{DATA_DIR_NAME}/**/*' DATA_FILE_PATTERN = f'{DATA_DIR_NAME}/**/*'
BOOK_ID_PATH_TEMPLATE = ' ({})' BOOK_ID_PATH_TEMPLATE = ' ({})'

View File

@ -87,6 +87,22 @@ class Notes:
) )
SchemaUpgrade(conn, '\n'.join(triggers)) SchemaUpgrade(conn, '\n'.join(triggers))
conn.notes_dbpath = dbpath conn.notes_dbpath = dbpath
for cat in backend.deleted_fields:
self.delete_field(conn, cat)
def delete_field(self, conn, field_name):
note_ids = conn.get('SELECT id from notes_db.notes WHERE colname=?', (field_name,))
if note_ids:
conn.execute(
'DELETE FROM notes_db.notes_resources_link WHERE note IN (SELECT id FROM notes_db.notes WHERE colname=?)', (field_name,)
)
conn.execute('DELETE FROM notes_db.notes WHERE colname=?', (field_name,))
self.remove_unreferenced_resources(conn)
def remove_unreferenced_resources(self, conn):
for (rhash,) in conn.get('SELECT hash FROM notes_db.resources WHERE id NOT IN (SELECT resource FROM notes_db.notes_resources_link)'):
remove_with_retry(self.path_for_resource(conn, rhash))
conn.execute('DELETE FROM notes_db.resources WHERE id NOT IN (SELECT resource FROM notes_db.notes_resources_link)')
def path_for_resource(self, conn, resource_hash_or_resource_id: Union[str,int]) -> str: def path_for_resource(self, conn, resource_hash_or_resource_id: Union[str,int]) -> str:
if isinstance(resource_hash_or_resource_id, str): if isinstance(resource_hash_or_resource_id, str):
@ -162,7 +178,7 @@ class Notes:
if x.startswith('res-'): if x.startswith('res-'):
rname = x.split('-', 1)[1] rname = x.split('-', 1)[1]
with open(os.path.join(srcdir, x), 'rb') as rsrc: with open(os.path.join(srcdir, x), 'rb') as rsrc:
resources.add(self.add_resource(conn, rsrc, rname)) resources.add(self.add_resource(conn, rsrc, rname, update_name=False))
note_id = self.set_note(conn, field_name, item_id, item_value, marked_up_text, resources, searchable_text) note_id = self.set_note(conn, field_name, item_id, item_value, marked_up_text, resources, searchable_text)
if note_id > -1: if note_id > -1:
remove_with_retry(srcdir, is_dir=True) remove_with_retry(srcdir, is_dir=True)
@ -242,7 +258,7 @@ class Notes:
for path in items[:extra]: for path in items[:extra]:
remove_with_retry(path, is_dir=True) remove_with_retry(path, is_dir=True)
def add_resource(self, conn, path_or_stream_or_data, name): def add_resource(self, conn, path_or_stream_or_data, name, update_name=True):
if isinstance(path_or_stream_or_data, bytes): if isinstance(path_or_stream_or_data, bytes):
data = path_or_stream_or_data data = path_or_stream_or_data
elif isinstance(path_or_stream_or_data, str): elif isinstance(path_or_stream_or_data, str):
@ -271,7 +287,7 @@ class Notes:
base_name, ext = os.path.splitext(name) base_name, ext = os.path.splitext(name)
c = 0 c = 0
for (resource_id, existing_name) in conn.execute('SELECT id,name FROM notes_db.resources WHERE hash=?', (resource_hash,)): for (resource_id, existing_name) in conn.execute('SELECT id,name FROM notes_db.resources WHERE hash=?', (resource_hash,)):
if existing_name != name: if existing_name != name and update_name:
while True: while True:
try: try:
conn.execute('UPDATE notes_db.resources SET name=? WHERE id=?', (name, resource_id)) conn.execute('UPDATE notes_db.resources SET name=? WHERE id=?', (name, resource_id))

View File

@ -87,6 +87,19 @@ def test_cache_api(self: 'NotesTest'):
self.ae(cache.get_notes_resource(h1)['data'], b'resource1') self.ae(cache.get_notes_resource(h1)['data'], b'resource1')
self.ae(cache.get_notes_resource(h2)['data'], b'resource2') self.ae(cache.get_notes_resource(h2)['data'], b'resource2')
self.assertFalse(os.listdir(notes.retired_dir)) self.assertFalse(os.listdir(notes.retired_dir))
# test delete custom column with notes
tags = cache.field_for('#tags', 1)
tag_id = cache.get_item_id('#tags', tags[0])
h1 = cache.add_notes_resource(b'resource1t', 'r1.jpg')
h2 = cache.add_notes_resource(b'resource2t', 'r1.jpg')
cache.set_notes_for('#tags', tag_id, doc, resource_ids=(h1, h2))
self.ae(cache.notes_for('#tags', tag_id), doc)
cache.delete_custom_column('tags')
cache.close()
cache = self.init_cache(cache.backend.library_path)
self.ae(cache.notes_for('#tags', tag_id), '')
self.assertIsNone(cache.get_notes_resource(h1))
self.assertIsNone(cache.get_notes_resource(h2))
def test_fts(self: 'NotesTest'): def test_fts(self: 'NotesTest'):