import sqlite3 import pathlib import uuid class Database: def __init__(self, filename=None): filename = filename or pathlib.Path(__file__).parent.parent.absolute() / "database.sqlite3" self._con = sqlite3.connect(filename) self.migrate() def _execute(self, query, parameters=None): cur = self.getCursor() cur.execute(query, parameters) self.commit() def commit(self): return self._con.commit() def getCursor(self): return self._con.cursor() def getVersion(self): cur = self.getCursor() try: cur.execute("SELECT value FROM contentmonster_settings WHERE key = 'dbversion'") assert (version := cur.fetchone()) return int(version[0]) except (sqlite3.OperationalError, AssertionError): return 0 def getFileUUID(self, fileobj): hash = fileobj.getHash() cur = self.getCursor() cur.execute("SELECT uuid, checksum FROM contentmonster_file WHERE directory = ? AND name = ?", (fileobj.directory.name, fileobj.name)) fileuuid = None for result in cur.fetchall(): if result[1] == hash: fileuuid = result[0] else: self.removeFileByUUID(result[0]) return fileuuid or self.addFile(fileobj, hash) def addFile(self, fileobj, hash=None): hash = hash or fileobj.getHash() fileuuid = str(uuid.uuid4()) self._execute("INSERT INTO contentmonster_file(uuid, directory, name, checksum) VALUES (?, ?, ?, ?)", (fileuuid, fileobj.directory.name, fileobj.name, hash)) return fileuuid def removeFileByUUID(self, fileuuid): self._execute("DELETE FROM contentmonster_file WHERE uuid = ?", (fileuuid,)) def logStart(self, file, vessel): self._execute("INSERT INTO contentmonster_file_log(file, vessel, status) VALUES(?, ?, ?)", (file.uuid, vessel.name, False)) def logCompletion(self, file, vessel): self._execute("UPDATE contentmonster_file_log SET status = ? WHERE file = ? AND vessel = ?", (True, file.uuid, vessel.name)) def migrate(self): cur = self.getCursor() if self.getVersion() == 0: cur.execute("CREATE TABLE IF NOT EXISTS contentmonster_settings(key VARCHAR(64) PRIMARY KEY, value TEXT)") cur.execute("INSERT INTO contentmonster_settings(key, value) VALUES ('dbversion', '1')") self.commit() if self.getVersion() == 1: cur.execute("CREATE TABLE IF NOT EXISTS contentmonster_file(uuid VARCHAR(36) PRIMARY KEY, directory VARCHAR(128), name VARCHAR(128), checksum VARCHAR(64))") cur.execute("CREATE TABLE IF NOT EXISTS contentmonster_file_log(file VARCHAR(36), vessel VARCHAR(128), status BOOLEAN, PRIMARY KEY (file, vessel), FOREIGN KEY (file) REFERENCES contentmonster_files(uuid) ON DELETE CASCADE)") cur.execute("UPDATE contentmonster_settings SET value = '2' WHERE key = 'dbversion'") self.commit() def __del__(self): self._con.close()