From e8c31435c567232b6be5a83ba2c654278de7e66c Mon Sep 17 00:00:00 2001 From: Rebecca Breu Date: Tue, 28 May 2024 22:10:33 +0200 Subject: [PATCH] Save upddate in bee files --- beeref/fileio/schema.py | 14 ++++++++++--- beeref/fileio/sql.py | 23 ++++++++++++++++++++- tests/fileio/test_sql.py | 43 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/beeref/fileio/schema.py b/beeref/fileio/schema.py index 6ca7f1b..7214305 100644 --- a/beeref/fileio/schema.py +++ b/beeref/fileio/schema.py @@ -1,4 +1,4 @@ -USER_VERSION = 2 +USER_VERSION = 3 APPLICATION_ID = 2060242126 @@ -30,12 +30,20 @@ ON UPDATE NO ACTION ) """, + """CREATE TABLE info ( + key TEXT PRIMARY KEY, + value TEXT + ) + """, ] MIGRATIONS = { - 2: [ + 2: ( "ALTER TABLE items ADD COLUMN data JSON", "UPDATE items SET data = json_object('filename', filename)", - ], + ), + 3: ( + "CREATE TABLE info (key TEXT PRIMARY KEY, value TEXT)", + ), } diff --git a/beeref/fileio/sql.py b/beeref/fileio/sql.py index de98686..648f185 100644 --- a/beeref/fileio/sql.py +++ b/beeref/fileio/sql.py @@ -23,6 +23,7 @@ https://www.sqlite.org/sqlar.html """ +import datetime import json import logging import os @@ -51,7 +52,7 @@ def is_bee_file(path): def handle_sqlite_errors(func): def wrapper(self, *args, **kwargs): try: - func(self, *args, **kwargs) + return func(self, *args, **kwargs) except Exception as e: logger.exception(f'Error while reading/writing {self.filename}') try: @@ -187,6 +188,22 @@ def create_schema_on_new(self): for schema in SCHEMA: self.ex(schema) + @handle_sqlite_errors + def read_info_value(self, key, default=None): + """Reads a value from the info table.""" + + rows = self.fetchone('SELECT value FROM info WHERE key=?', (key,)) + return rows[0] if rows else default + + @handle_sqlite_errors + def write_info_value(self, key, value): + """Writes a value into the info table.""" + + self.ex( + 'INSERT INTO info (key, value) VALUES (?, ?) ' + 'ON CONFLICT(key) DO UPDATE SET value=excluded.value', + (key, value)) + @handle_sqlite_errors def read(self): rows = self.fetchall( @@ -283,6 +300,10 @@ def write_data(self): if self.worker.canceled: break self.delete_items(to_delete) + + timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat() + self.write_info_value('upddate', timestamp) + self.connection.commit() self.ex('VACUUM') self.connection.commit() if self.worker: diff --git a/tests/fileio/test_sql.py b/tests/fileio/test_sql.py index c459dde..0dc0ee8 100644 --- a/tests/fileio/test_sql.py +++ b/tests/fileio/test_sql.py @@ -1,3 +1,4 @@ +import datetime import json import os import os.path @@ -120,6 +121,36 @@ def test_all_migrations(tmpfile): assert result[3] == b'bla' +def test_sqliteio_read_info_value_when_exists(tmpfile): + io = SQLiteIO(tmpfile, MagicMock(), create_new=True) + io.create_schema_on_new() + io.ex('INSERT INTO info (key, value) VALUES ("foo", "bar")') + io.read_info_value('foo') == 'bar' + + +def test_sqliteio_read_info_value_returns_default_when_doesnt_exists(tmpfile): + io = SQLiteIO(tmpfile, MagicMock(), create_new=True) + io.create_schema_on_new() + io.read_info_value('foo', 'baz') == 'baz' + + +def test_sqliteio_write_info_value_when_doesnt_exist(tmpfile): + io = SQLiteIO(tmpfile, MagicMock(), create_new=True) + io.create_schema_on_new() + io.write_info_value('foo', 'bar') + io.read_info_value('foo') == 'bar' + + +def test_sqliteio_write_info_value_when_exist_updates(tmpfile): + io = SQLiteIO(tmpfile, MagicMock(), create_new=True) + io.create_schema_on_new() + io.ex('INSERT INTO info (key, value) VALUES ("foo", "bar")') + io.write_info_value('foo', 'baz') + io.read_info_value('foo') == 'baz' + row = io.fetchone('SELECT COUNT(*) FROM info WHERE key="foo"') + assert row[0] == 1 + + def test_sqliteio_write_meta_application_id(tmpfile): io = SQLiteIO(tmpfile, MagicMock(), create_new=True) io.write_meta() @@ -148,7 +179,7 @@ def test_sqliteio_create_schema_on_new_when_create_new(tmpfile): result = io.fetchone( 'SELECT COUNT(*) FROM sqlite_master ' 'WHERE type="table" AND name NOT LIKE "sqlite_%"') - assert result[0] == 2 + assert result[0] == 3 scene_mock.clear_save_ids.assert_called_once() @@ -196,6 +227,16 @@ def test_sqliteio_write_calls_write_meta(tmpfile, view): metamock.assert_called_once() +def test_sqliteio_write_writes_upddate(tmpfile, view): + item = BeeTextItem(text='foo bar') + view.scene.addItem(item) + io = SQLiteIO(tmpfile, view.scene, create_new=True) + io.write() + year = datetime.datetime.utcnow().year + upddate = io.read_info_value('upddate') + assert upddate.startswith(str(year)) + + def test_sqliteio_write_inserts_new_text_item(tmpfile, view): item = BeeTextItem(text='foo bar') view.scene.addItem(item)