mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Track creation and modified timestamps for notes
This commit is contained in:
parent
652fb651cb
commit
b0766d7a62
@ -3,6 +3,8 @@ CREATE TABLE notes_db.notes ( id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
colname TEXT NOT NULL COLLATE NOCASE,
|
||||
doc TEXT NOT NULL DEFAULT '',
|
||||
searchable_text TEXT NOT NULL DEFAULT '',
|
||||
ctime REAL DEFAULT (unixepoch('subsec')),
|
||||
mtime REAL DEFAULT (unixepoch('subsec')),
|
||||
UNIQUE(item, colname)
|
||||
);
|
||||
|
||||
@ -41,6 +43,7 @@ BEGIN
|
||||
INSERT INTO notes_fts(rowid, searchable_text) VALUES (NEW.id, NEW.searchable_text);
|
||||
INSERT INTO notes_fts_stemmed(notes_fts_stemmed, rowid, searchable_text) VALUES('delete', OLD.id, OLD.searchable_text);
|
||||
INSERT INTO notes_fts_stemmed(rowid, searchable_text) VALUES (NEW.id, NEW.searchable_text);
|
||||
UPDATE notes SET mtime=unixepoch('subsec') WHERE id = OLD.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER notes_db.notes_db_resources_delete_trg BEFORE DELETE ON notes_db.resources
|
||||
|
@ -205,7 +205,10 @@ class Notes:
|
||||
srcdir = self.path_to_retired_dir_for_item(field_name, item_id, item_value)
|
||||
remove_with_retry(srcdir, is_dir=True)
|
||||
|
||||
def set_note(self, conn, field_name, item_id, item_value, marked_up_text='', used_resource_hashes=(), searchable_text=copy_marked_up_text):
|
||||
def set_note(
|
||||
self, conn, field_name, item_id, item_value, marked_up_text='', used_resource_hashes=(),
|
||||
searchable_text=copy_marked_up_text, ctime=None, mtime=None
|
||||
):
|
||||
if searchable_text is copy_marked_up_text:
|
||||
searchable_text = marked_up_text
|
||||
searchable_text = item_value + '\n' + searchable_text
|
||||
@ -228,9 +231,19 @@ class Notes:
|
||||
resources_to_add = new_resources - old_resources
|
||||
if note_id is None:
|
||||
self.remove_retired_entry(field_name, item_id, item_value)
|
||||
note_id = conn.get('''
|
||||
INSERT INTO notes_db.notes (item,colname,doc,searchable_text) VALUES (?,?,?,?) RETURNING notes.id;
|
||||
''', (item_id, field_name, marked_up_text, searchable_text), all=False)
|
||||
if ctime is not None or mtime is not None:
|
||||
now = time.time()
|
||||
if ctime is None:
|
||||
ctime = now
|
||||
if mtime is None:
|
||||
mtime = now
|
||||
note_id = conn.get('''
|
||||
INSERT INTO notes_db.notes (item,colname,doc,searchable_text,ctime,mtime) VALUES (?,?,?,?,?,?) RETURNING notes.id;
|
||||
''', (item_id, field_name, marked_up_text, searchable_text, ctime, mtime), all=False)
|
||||
else:
|
||||
note_id = conn.get('''
|
||||
INSERT INTO notes_db.notes (item,colname,doc,searchable_text) VALUES (?,?,?,?) RETURNING notes.id;
|
||||
''', (item_id, field_name, marked_up_text, searchable_text), all=False)
|
||||
else:
|
||||
conn.execute('UPDATE notes_db.notes SET doc=?,searchable_text=? WHERE id=?', (marked_up_text, searchable_text, note_id))
|
||||
if resources_to_potentially_remove:
|
||||
@ -246,11 +259,12 @@ class Notes:
|
||||
return conn.get('SELECT doc FROM notes_db.notes WHERE item=? AND colname=?', (item_id, field_name), all=False)
|
||||
|
||||
def get_note_data(self, conn, field_name, item_id):
|
||||
for (note_id, doc, searchable_text) in conn.execute(
|
||||
'SELECT id,doc,searchable_text FROM notes_db.notes WHERE item=? AND colname=?', (item_id, field_name)
|
||||
for (note_id, doc, searchable_text, ctime, mtime) in conn.execute(
|
||||
'SELECT id,doc,searchable_text,ctime,mtime FROM notes_db.notes WHERE item=? AND colname=?', (item_id, field_name)
|
||||
):
|
||||
return {
|
||||
'id': note_id, 'doc': doc, 'searchable_text': searchable_text,
|
||||
'ctime': ctime, 'mtime': mtime,
|
||||
'resource_hashes': frozenset(self.resources_used_by(conn, note_id)),
|
||||
}
|
||||
|
||||
@ -427,6 +441,7 @@ class Notes:
|
||||
try:
|
||||
with open(make_long_path_useable(os.path.join(self.backup_dir, field, str(item_id)))) as f:
|
||||
raw = f.read()
|
||||
st = os.stat(f.fileno())
|
||||
except OSError as e:
|
||||
errors.append(_('Failed to read from document for {path} with error: {error}').format(path=item_val, error=e))
|
||||
continue
|
||||
@ -441,7 +456,7 @@ class Notes:
|
||||
errors.append(_('Some resources for {} were missing').format(item_val))
|
||||
resources &= known_resources
|
||||
try:
|
||||
self.set_note(conn, field, item_id, item_val, doc, resources, searchable_text)
|
||||
self.set_note(conn, field, item_id, item_val, doc, resources, searchable_text, ctime=st.st_ctime, mtime=st.st_mtime)
|
||||
except Exception as e:
|
||||
errors.append(_('Failed to set note for {path} with error: {error}').format(path=item_val, error=e))
|
||||
else:
|
||||
|
@ -2,7 +2,7 @@
|
||||
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
import os
|
||||
import os, time
|
||||
|
||||
from calibre.db.tests.base import BaseTest
|
||||
|
||||
@ -75,7 +75,14 @@ def test_cache_api(self: 'NotesTest'):
|
||||
h2 = cache.add_notes_resource(b'resource2', 'r1.jpg')
|
||||
cache.set_notes_for('authors', author_id, doc, resource_hashes=(h1, h2))
|
||||
nd = cache.notes_data_for('authors', author_id)
|
||||
self.ae(nd, {'id': 1, 'searchable_text': authors[0] + '\n' + doc, 'doc': doc, 'resource_hashes': frozenset({h1, h2})})
|
||||
self.ae(nd, {'id': 1, 'ctime': nd['ctime'], 'mtime': nd['ctime'], 'searchable_text': authors[0] + '\n' + doc,
|
||||
'doc': doc, 'resource_hashes': frozenset({h1, h2})})
|
||||
time.sleep(0.01)
|
||||
cache.set_notes_for('authors', author_id, doc, resource_hashes=(h1, h2))
|
||||
n2d = cache.notes_data_for('authors', author_id)
|
||||
self.ae(nd['ctime'], n2d['ctime'])
|
||||
self.assertGreater(n2d['mtime'], nd['mtime'])
|
||||
|
||||
# test renaming to a new author preserves notes
|
||||
cache.rename_items('authors', {author_id: 'renamed author'})
|
||||
raid = cache.get_item_id('authors', 'renamed author')
|
||||
|
Loading…
x
Reference in New Issue
Block a user