1 """Database management."""
2 from os.path import isfile
3 from difflib import Differ
4 from sqlite3 import connect as sql_connect
5 from plomtask.misc import HandledException
7 PATH_DB_SCHEMA = 'scripts/init.sql'
10 class DatabaseFile: # pylint: disable=too-few-public-methods
11 """Represents the sqlite3 database's file."""
13 def __init__(self, path):
18 """Create tables in self.path file as per PATH_DB_SCHEMA sql file."""
19 with sql_connect(self.path) as conn:
20 with open(PATH_DB_SCHEMA, 'r', encoding='utf-8') as f:
21 conn.executescript(f.read())
25 """Check file exists and is of proper schema."""
26 self.exists = isfile(self.path)
28 self._validate_schema()
30 def _validate_schema(self):
31 """Compare found schema with what's stored at PATH_DB_SCHEMA."""
32 sql_for_schema = 'SELECT sql FROM sqlite_master ORDER BY sql'
33 msg_err = 'Database has wrong tables schema. Diff:\n'
34 with sql_connect(self.path) as conn:
35 schema_rows = [r[0] for r in conn.execute(sql_for_schema) if r[0]]
36 retrieved_schema = ';\n'.join(schema_rows) + ';'
37 with open(PATH_DB_SCHEMA, 'r', encoding='utf-8') as f:
38 stored_schema = f.read().rstrip()
39 if stored_schema != retrieved_schema:
40 diff_msg = Differ().compare(retrieved_schema.splitlines(),
41 stored_schema.splitlines())
42 raise HandledException(msg_err + '\n'.join(diff_msg))
45 class DatabaseConnection:
46 """A single connection to the database."""
48 def __init__(self, db_file: DatabaseFile):
50 self.conn = sql_connect(self.file.path)
53 """Commit SQL transaction."""
56 def exec(self, code: str, inputs: tuple = ()):
57 """Add commands to SQL transaction."""
58 return self.conn.execute(code, inputs)
61 """Close DB connection."""