1
|
|
|
import logging |
2
|
|
|
import os |
3
|
|
|
from typing import Final |
4
|
|
|
|
5
|
|
|
from sqlalchemy import Engine, create_engine, URL, inspect, text |
6
|
|
|
from sqlalchemy.sql.ddl import CreateSchema |
7
|
|
|
|
8
|
|
|
from src.singleton import Singleton |
9
|
|
|
|
10
|
|
|
# future: swith to SQLAlchemy ORM when https://youtrack.jetbrains.com/issue/PY-4536 is fixed |
11
|
|
|
|
12
|
|
|
|
13
|
|
|
class Database(metaclass=Singleton): |
14
|
|
|
def __init__(self) -> None: |
15
|
|
|
self.logger = logging.getLogger(__name__) |
16
|
|
|
|
17
|
|
|
self._DRIVERNAME: Final = "mysql+mysqlconnector" |
18
|
|
|
self._HOST: Final = "localhost" |
19
|
|
|
self._PORT: Final = 3306 |
20
|
|
|
self._USERNAME: Final = "root" |
21
|
|
|
self._PASSWORD: Final = self.get_password() |
22
|
|
|
self.DATABASE_NAME: Final = "kalauz" |
23
|
|
|
|
24
|
|
|
self.engine = self.connect_to_database_server() |
25
|
|
|
self.engine = self.connect_to_database() |
26
|
|
|
|
27
|
|
|
self.logger.info(f"{self.__class__.__name__} initialized!") |
28
|
|
|
|
29
|
|
|
def get_password(self) -> str: |
30
|
|
|
try: |
31
|
|
|
database_password = os.getenv("DATABASE_PASSWORD") |
32
|
|
|
if not database_password: |
33
|
|
|
raise ValueError( |
34
|
|
|
"No password found in the .env file for the database server!" |
35
|
|
|
) |
36
|
|
|
except ValueError as error: |
37
|
|
|
self.logger.critical(error) |
38
|
|
|
raise |
39
|
|
|
return database_password |
40
|
|
|
|
41
|
|
|
def connect_to_database_server(self) -> Engine: |
42
|
|
|
try: |
43
|
|
|
database_url = URL.create( |
44
|
|
|
drivername=self._DRIVERNAME, |
45
|
|
|
host=self._HOST, |
46
|
|
|
port=self._PORT, |
47
|
|
|
username=self._USERNAME, |
48
|
|
|
password=self._PASSWORD, |
49
|
|
|
) |
50
|
|
|
return create_engine(database_url) |
51
|
|
|
finally: |
52
|
|
|
self.logger.debug("Successfully connected to the database server!") |
53
|
|
|
|
54
|
|
|
def connect_to_database(self) -> Engine: |
55
|
|
|
if not inspect(self.engine).has_schema(self.DATABASE_NAME): |
56
|
|
|
with self.engine.begin() as connection: |
57
|
|
|
connection.execute(CreateSchema(self.DATABASE_NAME)) |
58
|
|
|
|
59
|
|
|
return self.connect_to_created_database() |
60
|
|
|
|
61
|
|
|
def connect_to_created_database(self) -> Engine: |
62
|
|
|
try: |
63
|
|
|
database_url = URL.create( |
64
|
|
|
drivername=self._DRIVERNAME, |
65
|
|
|
host=self._HOST, |
66
|
|
|
port=self._PORT, |
67
|
|
|
username=self._USERNAME, |
68
|
|
|
password=self._PASSWORD, |
69
|
|
|
database=self.DATABASE_NAME, |
70
|
|
|
) |
71
|
|
|
return create_engine(database_url) |
72
|
|
|
finally: |
73
|
|
|
self.logger.debug( |
74
|
|
|
f"Successfully connected to the {self.DATABASE_NAME} database of the server!" |
75
|
|
|
) |
76
|
|
|
|