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,
|
colname TEXT NOT NULL COLLATE NOCASE,
|
||||||
doc TEXT NOT NULL DEFAULT '',
|
doc TEXT NOT NULL DEFAULT '',
|
||||||
searchable_text TEXT NOT NULL DEFAULT '',
|
searchable_text TEXT NOT NULL DEFAULT '',
|
||||||
|
ctime REAL DEFAULT (unixepoch('subsec')),
|
||||||
|
mtime REAL DEFAULT (unixepoch('subsec')),
|
||||||
UNIQUE(item, colname)
|
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(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(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);
|
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;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER notes_db.notes_db_resources_delete_trg BEFORE DELETE ON notes_db.resources
|
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)
|
srcdir = self.path_to_retired_dir_for_item(field_name, item_id, item_value)
|
||||||
remove_with_retry(srcdir, is_dir=True)
|
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:
|
if searchable_text is copy_marked_up_text:
|
||||||
searchable_text = marked_up_text
|
searchable_text = marked_up_text
|
||||||
searchable_text = item_value + '\n' + searchable_text
|
searchable_text = item_value + '\n' + searchable_text
|
||||||
@ -228,6 +231,16 @@ class Notes:
|
|||||||
resources_to_add = new_resources - old_resources
|
resources_to_add = new_resources - old_resources
|
||||||
if note_id is None:
|
if note_id is None:
|
||||||
self.remove_retired_entry(field_name, item_id, item_value)
|
self.remove_retired_entry(field_name, item_id, item_value)
|
||||||
|
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('''
|
note_id = conn.get('''
|
||||||
INSERT INTO notes_db.notes (item,colname,doc,searchable_text) VALUES (?,?,?,?) RETURNING notes.id;
|
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)
|
''', (item_id, field_name, marked_up_text, searchable_text), all=False)
|
||||||
@ -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)
|
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):
|
def get_note_data(self, conn, field_name, item_id):
|
||||||
for (note_id, doc, searchable_text) in conn.execute(
|
for (note_id, doc, searchable_text, ctime, mtime) in conn.execute(
|
||||||
'SELECT id,doc,searchable_text FROM notes_db.notes WHERE item=? AND colname=?', (item_id, field_name)
|
'SELECT id,doc,searchable_text,ctime,mtime FROM notes_db.notes WHERE item=? AND colname=?', (item_id, field_name)
|
||||||
):
|
):
|
||||||
return {
|
return {
|
||||||
'id': note_id, 'doc': doc, 'searchable_text': searchable_text,
|
'id': note_id, 'doc': doc, 'searchable_text': searchable_text,
|
||||||
|
'ctime': ctime, 'mtime': mtime,
|
||||||
'resource_hashes': frozenset(self.resources_used_by(conn, note_id)),
|
'resource_hashes': frozenset(self.resources_used_by(conn, note_id)),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,6 +441,7 @@ class Notes:
|
|||||||
try:
|
try:
|
||||||
with open(make_long_path_useable(os.path.join(self.backup_dir, field, str(item_id)))) as f:
|
with open(make_long_path_useable(os.path.join(self.backup_dir, field, str(item_id)))) as f:
|
||||||
raw = f.read()
|
raw = f.read()
|
||||||
|
st = os.stat(f.fileno())
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
errors.append(_('Failed to read from document for {path} with error: {error}').format(path=item_val, error=e))
|
errors.append(_('Failed to read from document for {path} with error: {error}').format(path=item_val, error=e))
|
||||||
continue
|
continue
|
||||||
@ -441,7 +456,7 @@ class Notes:
|
|||||||
errors.append(_('Some resources for {} were missing').format(item_val))
|
errors.append(_('Some resources for {} were missing').format(item_val))
|
||||||
resources &= known_resources
|
resources &= known_resources
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
errors.append(_('Failed to set note for {path} with error: {error}').format(path=item_val, error=e))
|
errors.append(_('Failed to set note for {path} with error: {error}').format(path=item_val, error=e))
|
||||||
else:
|
else:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2023, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os, time
|
||||||
|
|
||||||
from calibre.db.tests.base import BaseTest
|
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')
|
h2 = cache.add_notes_resource(b'resource2', 'r1.jpg')
|
||||||
cache.set_notes_for('authors', author_id, doc, resource_hashes=(h1, h2))
|
cache.set_notes_for('authors', author_id, doc, resource_hashes=(h1, h2))
|
||||||
nd = cache.notes_data_for('authors', author_id)
|
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
|
# test renaming to a new author preserves notes
|
||||||
cache.rename_items('authors', {author_id: 'renamed author'})
|
cache.rename_items('authors', {author_id: 'renamed author'})
|
||||||
raid = cache.get_item_id('authors', 'renamed author')
|
raid = cache.get_item_id('authors', 'renamed author')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user