From 78dcbdcbaaba319cc59ab93c28b7855e37090563 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 29 Nov 2020 21:36:16 +0100 Subject: [PATCH 1/7] Improved structure and added basics for database module --- src/sh_edraft/coding/model/version.py | 2 + src/sh_edraft/configuration/configuration.py | 4 +- src/sh_edraft/database/__init__.py | 3 + src/sh_edraft/database/base/__init__.py | 3 + .../database/base/database_connection_base.py | 10 +++ src/sh_edraft/database/database_connection.py | 35 ++++++++ src/sh_edraft/database/model/__init__.py | 0 .../database/model/database_settings.py | 80 +++++++++++++++++++ .../database/model/database_settings_name.py | 10 +++ src/sh_edraft/hosting/application_host.py | 4 +- .../hosting/base/application_host_base.py | 2 +- src/sh_edraft/logging/logger.py | 4 +- .../model/publish_settings_model.py | 4 +- src/sh_edraft/publishing/model/template.py | 1 + src/sh_edraft/service/__init__.py | 1 - src/sh_edraft/service/base/__init__.py | 1 - src/sh_edraft/service/model/__init__.py | 1 - src/sh_edraft/service/providing/__init__.py | 3 + .../service/providing/base/__init__.py | 3 + .../base/service_provider_base.py | 0 .../service/providing/model/__init__.py | 3 + .../{ => providing}/model/provide_state.py | 2 +- .../{ => providing}/service_provider.py | 6 +- src/sh_edraft/utils/__init__.py | 1 + src/sh_edraft/utils/credential_manager.py | 17 ++++ src/tests_dev/appsettings.development.json | 6 ++ src/tests_dev/program.py | 15 +++- 27 files changed, 202 insertions(+), 19 deletions(-) create mode 100644 src/sh_edraft/database/__init__.py create mode 100644 src/sh_edraft/database/base/__init__.py create mode 100644 src/sh_edraft/database/base/database_connection_base.py create mode 100644 src/sh_edraft/database/database_connection.py create mode 100644 src/sh_edraft/database/model/__init__.py create mode 100644 src/sh_edraft/database/model/database_settings.py create mode 100644 src/sh_edraft/database/model/database_settings_name.py create mode 100644 src/sh_edraft/service/providing/__init__.py create mode 100644 src/sh_edraft/service/providing/base/__init__.py rename src/sh_edraft/service/{ => providing}/base/service_provider_base.py (100%) create mode 100644 src/sh_edraft/service/providing/model/__init__.py rename src/sh_edraft/service/{ => providing}/model/provide_state.py (85%) rename src/sh_edraft/service/{ => providing}/service_provider.py (93%) create mode 100644 src/sh_edraft/utils/credential_manager.py diff --git a/src/sh_edraft/coding/model/version.py b/src/sh_edraft/coding/model/version.py index 26e4f9c0..be2d5a3d 100644 --- a/src/sh_edraft/coding/model/version.py +++ b/src/sh_edraft/coding/model/version.py @@ -12,6 +12,8 @@ class Version(ConfigurationModelBase): minor: int = None, micro: float = None ): + ConfigurationModelBase.__init__(self) + self._major: Optional[int] = major self._minor: Optional[int] = minor self._micro: Optional[int] = micro diff --git a/src/sh_edraft/configuration/configuration.py b/src/sh_edraft/configuration/configuration.py index dc0ef33f..f32148f0 100644 --- a/src/sh_edraft/configuration/configuration.py +++ b/src/sh_edraft/configuration/configuration.py @@ -7,8 +7,8 @@ from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.configuration.model.configuration_variable_name import ConfigurationVariableName from sh_edraft.environment.base.environment_base import EnvironmentBase from sh_edraft.environment.hosting_environment import HostingEnvironment -from sh_edraft.environment.model import EnvironmentName -from sh_edraft.utils import Console +from sh_edraft.environment.model.environment_name import EnvironmentName +from sh_edraft.utils.console import Console class Configuration(ConfigurationBase): diff --git a/src/sh_edraft/database/__init__.py b/src/sh_edraft/database/__init__.py new file mode 100644 index 00000000..eae4c82d --- /dev/null +++ b/src/sh_edraft/database/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .database_connection import DatabaseConnection diff --git a/src/sh_edraft/database/base/__init__.py b/src/sh_edraft/database/base/__init__.py new file mode 100644 index 00000000..876327c9 --- /dev/null +++ b/src/sh_edraft/database/base/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .database_connection_base import DatabaseConnectionBase diff --git a/src/sh_edraft/database/base/database_connection_base.py b/src/sh_edraft/database/base/database_connection_base.py new file mode 100644 index 00000000..9307c9b1 --- /dev/null +++ b/src/sh_edraft/database/base/database_connection_base.py @@ -0,0 +1,10 @@ +from abc import abstractmethod + +from sh_edraft.service.base.service_base import ServiceBase + + +class DatabaseConnectionBase(ServiceBase): + + @abstractmethod + def __init__(self): + ServiceBase.__init__(self) diff --git a/src/sh_edraft/database/database_connection.py b/src/sh_edraft/database/database_connection.py new file mode 100644 index 00000000..799f714b --- /dev/null +++ b/src/sh_edraft/database/database_connection.py @@ -0,0 +1,35 @@ +from typing import Optional + +from sqlalchemy import engine, create_engine +from sqlalchemy.orm import session, sessionmaker + +from sh_edraft.database.base.database_connection_base import DatabaseConnectionBase +from sh_edraft.database.model.database_settings import DatabaseSettings + + +class DatabaseConnection(DatabaseConnectionBase): + + def __init__(self, database_settings: DatabaseSettings): + DatabaseConnectionBase.__init__(self) + + self._db_settings = database_settings + + self._engine: Optional[engine] = None + self._session: Optional[session] = None + self._credentials: Optional[str] = None + + def create(self): + self._engine = create_engine(self._db_settings.decrypted_connection_string) + + if self._db_settings.encoding is not None: + self._engine.encoding = self._db_settings.encoding + + if self._db_settings.case_sensitive is not None: + self._engine.case_sensitive = self._db_settings.case_sensitive + + if self._db_settings.echo is not None: + self._engine.echo = self._db_settings.echo + + db_session = sessionmaker(bind=self._engine) + self._session = db_session() + diff --git a/src/sh_edraft/database/model/__init__.py b/src/sh_edraft/database/model/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/sh_edraft/database/model/database_settings.py b/src/sh_edraft/database/model/database_settings.py new file mode 100644 index 00000000..8c2def60 --- /dev/null +++ b/src/sh_edraft/database/model/database_settings.py @@ -0,0 +1,80 @@ +import traceback +from typing import Optional + +from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase +from sh_edraft.database.model.database_settings_name import DatabaseSettingsName +from sh_edraft.utils.credential_manager import CredentialManager +from sh_edraft.utils.console import Console + + +class DatabaseSettings(ConfigurationModelBase): + + def __init__(self): + ConfigurationModelBase.__init__(self) + + self._connection_string: Optional[str] = None + self._credentials: Optional[str] = None + self._encoding: Optional[str] = None + self._case_sensitive: Optional[bool] = None + self._echo: Optional[bool] = None + + @property + def connection_string(self) -> str: + return self._connection_string + + @connection_string.setter + def connection_string(self, connection_string: str): + self._connection_string = connection_string + + @property + def decrypted_connection_string(self) -> str: + return CredentialManager.build_string(self._connection_string, self._credentials) + + @property + def credentials(self) -> str: + return self._credentials + + @credentials.setter + def credentials(self, credentials: str): + self._credentials = credentials + + @property + def encoding(self) -> str: + return self._encoding + + @encoding.setter + def encoding(self, encoding: str) -> None: + self._encoding = encoding + + @property + def case_sensitive(self) -> bool: + return self._case_sensitive + + @case_sensitive.setter + def case_sensitive(self, case_sensitive: bool) -> None: + self._case_sensitive = case_sensitive + + @property + def echo(self) -> bool: + return self._echo + + @echo.setter + def echo(self, echo: bool) -> None: + self._echo = echo + + def from_dict(self, settings: dict): + try: + self._connection_string = settings[DatabaseSettingsName.connection_string.value] + self._credentials = settings[DatabaseSettingsName.credentials.value] + + if DatabaseSettingsName.encoding.value in settings: + self._encoding = settings[DatabaseSettingsName.encoding.value] + + if DatabaseSettingsName.case_sensitive.value in settings: + self._case_sensitive = bool(settings[DatabaseSettingsName.case_sensitive.value]) + + if DatabaseSettingsName.echo.value in settings: + self._echo = bool(settings[DatabaseSettingsName.echo.value]) + except Exception as e: + Console.write_line(f'[ ERROR ] [ {__name__} ]: Reading error in {self.__name__} settings', 'red') + Console.write_line(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}', 'red') diff --git a/src/sh_edraft/database/model/database_settings_name.py b/src/sh_edraft/database/model/database_settings_name.py new file mode 100644 index 00000000..57ece941 --- /dev/null +++ b/src/sh_edraft/database/model/database_settings_name.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class DatabaseSettingsName(Enum): + + connection_string = 'ConnectionString' + credentials = 'Credentials' + encoding = 'Encoding' + case_sensitive = 'CaseSensitive' + echo = 'Echo' diff --git a/src/sh_edraft/hosting/application_host.py b/src/sh_edraft/hosting/application_host.py index e5e6b362..d86283d0 100644 --- a/src/sh_edraft/hosting/application_host.py +++ b/src/sh_edraft/hosting/application_host.py @@ -5,8 +5,8 @@ from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.hosting.application_runtime import ApplicationRuntime from sh_edraft.hosting.base.application_host_base import ApplicationHostBase -from sh_edraft.service.service_provider import ServiceProvider -from sh_edraft.service.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.providing.service_provider import ServiceProvider +from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase class ApplicationHost(ApplicationHostBase): diff --git a/src/sh_edraft/hosting/base/application_host_base.py b/src/sh_edraft/hosting/base/application_host_base.py index 4ee8c0f5..fb816ccb 100644 --- a/src/sh_edraft/hosting/base/application_host_base.py +++ b/src/sh_edraft/hosting/base/application_host_base.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase -from sh_edraft.service.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase class ApplicationHostBase(ABC): diff --git a/src/sh_edraft/logging/logger.py b/src/sh_edraft/logging/logger.py index 01b58937..f2159ad2 100644 --- a/src/sh_edraft/logging/logger.py +++ b/src/sh_edraft/logging/logger.py @@ -5,9 +5,9 @@ from string import Template from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.logging.base.logger_base import LoggerBase -from sh_edraft.logging.model import LoggingSettings +from sh_edraft.logging.model.logging_settings import LoggingSettings from sh_edraft.logging.model.logging_level import LoggingLevel -from sh_edraft.time.model import TimeFormatSettings +from sh_edraft.time.model.time_format_settings import TimeFormatSettings from sh_edraft.utils.console import Console diff --git a/src/sh_edraft/publishing/model/publish_settings_model.py b/src/sh_edraft/publishing/model/publish_settings_model.py index 3886262d..a743692a 100644 --- a/src/sh_edraft/publishing/model/publish_settings_model.py +++ b/src/sh_edraft/publishing/model/publish_settings_model.py @@ -2,9 +2,9 @@ import traceback from typing import Optional from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase -from sh_edraft.publishing.model import Template +from sh_edraft.publishing.model.template import Template from sh_edraft.publishing.model.publish_settings_name import PublishSettingsName -from sh_edraft.utils import Console +from sh_edraft.utils.console import Console class PublishSettings(ConfigurationModelBase): diff --git a/src/sh_edraft/publishing/model/template.py b/src/sh_edraft/publishing/model/template.py index 922a5df5..91ba29e3 100644 --- a/src/sh_edraft/publishing/model/template.py +++ b/src/sh_edraft/publishing/model/template.py @@ -21,6 +21,7 @@ class Template(ConfigurationModelBase): author: Optional[str] = None, version: Optional[dict] = None ): + ConfigurationModelBase.__init__(self) self._template_path: Optional[str] = template_path self._name: Optional[str] = name self._description: Optional[str] = description diff --git a/src/sh_edraft/service/__init__.py b/src/sh_edraft/service/__init__.py index 52003f0b..abfc6044 100644 --- a/src/sh_edraft/service/__init__.py +++ b/src/sh_edraft/service/__init__.py @@ -20,7 +20,6 @@ __version__ = '2020.12.5' from collections import namedtuple # imports: -from .service_provider import ServiceProvider VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/base/__init__.py b/src/sh_edraft/service/base/__init__.py index 6ce7f45b..d3d865d7 100644 --- a/src/sh_edraft/service/base/__init__.py +++ b/src/sh_edraft/service/base/__init__.py @@ -21,7 +21,6 @@ from collections import namedtuple # imports: from .service_base import ServiceBase -from .service_provider_base import ServiceProviderBase VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/model/__init__.py b/src/sh_edraft/service/model/__init__.py index b95fe3c2..05760565 100644 --- a/src/sh_edraft/service/model/__init__.py +++ b/src/sh_edraft/service/model/__init__.py @@ -20,7 +20,6 @@ __version__ = '2020.12.5' from collections import namedtuple # imports: -from .provide_state import ProvideState VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/providing/__init__.py b/src/sh_edraft/service/providing/__init__.py new file mode 100644 index 00000000..b8bf2077 --- /dev/null +++ b/src/sh_edraft/service/providing/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .service_provider import ServiceProviderBase diff --git a/src/sh_edraft/service/providing/base/__init__.py b/src/sh_edraft/service/providing/base/__init__.py new file mode 100644 index 00000000..4b5ed5b7 --- /dev/null +++ b/src/sh_edraft/service/providing/base/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .service_provider_base import ServiceProviderBase diff --git a/src/sh_edraft/service/base/service_provider_base.py b/src/sh_edraft/service/providing/base/service_provider_base.py similarity index 100% rename from src/sh_edraft/service/base/service_provider_base.py rename to src/sh_edraft/service/providing/base/service_provider_base.py diff --git a/src/sh_edraft/service/providing/model/__init__.py b/src/sh_edraft/service/providing/model/__init__.py new file mode 100644 index 00000000..7c4dd264 --- /dev/null +++ b/src/sh_edraft/service/providing/model/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .provide_state import ProvideState diff --git a/src/sh_edraft/service/model/provide_state.py b/src/sh_edraft/service/providing/model/provide_state.py similarity index 85% rename from src/sh_edraft/service/model/provide_state.py rename to src/sh_edraft/service/providing/model/provide_state.py index 619e0ed5..52d0af05 100644 --- a/src/sh_edraft/service/model/provide_state.py +++ b/src/sh_edraft/service/providing/model/provide_state.py @@ -1,6 +1,6 @@ from typing import Type -from sh_edraft.service.base import ServiceBase +from sh_edraft.service.base.service_base import ServiceBase class ProvideState: diff --git a/src/sh_edraft/service/service_provider.py b/src/sh_edraft/service/providing/service_provider.py similarity index 93% rename from src/sh_edraft/service/service_provider.py rename to src/sh_edraft/service/providing/service_provider.py index 4207b0f5..205f8359 100644 --- a/src/sh_edraft/service/service_provider.py +++ b/src/sh_edraft/service/providing/service_provider.py @@ -4,7 +4,7 @@ from typing import Type from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase -from sh_edraft.service.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase from sh_edraft.service.base.service_base import ServiceBase @@ -45,8 +45,8 @@ class ServiceProvider(ServiceProviderBase): def add_singleton(self, service_type: Type[ServiceBase], service: Callable[ServiceBase]): for known_service in self._singleton_services: - if type(known_service) == type(service_type): - raise Exception(f'Service with type {type(service_type)} already exists') + if type(known_service) == service_type: + raise Exception(f'Service with type {service_type} already exists') self._singleton_services[service_type] = self._create_instance(service) diff --git a/src/sh_edraft/utils/__init__.py b/src/sh_edraft/utils/__init__.py index 4130c05d..10d2e9e5 100644 --- a/src/sh_edraft/utils/__init__.py +++ b/src/sh_edraft/utils/__init__.py @@ -21,6 +21,7 @@ from collections import namedtuple # imports: from .console import Console +from .credential_manager import CredentialManager VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/utils/credential_manager.py b/src/sh_edraft/utils/credential_manager.py new file mode 100644 index 00000000..7f9977d1 --- /dev/null +++ b/src/sh_edraft/utils/credential_manager.py @@ -0,0 +1,17 @@ +import base64 + + +class CredentialManager: + + @staticmethod + def encrypt(string: str) -> str: + return base64.b64encode(string.encode('utf-8')).decode('utf-8') + + @staticmethod + def decrypt(string: str) -> str: + return base64.b64decode(string).decode('utf-8') + + @staticmethod + def build_string(string: str, credentials: str): + return string.replace('$credentials', CredentialManager.decrypt(credentials)) + diff --git a/src/tests_dev/appsettings.development.json b/src/tests_dev/appsettings.development.json index 62ec6c61..aa370960 100644 --- a/src/tests_dev/appsettings.development.json +++ b/src/tests_dev/appsettings.development.json @@ -4,5 +4,11 @@ "Filename": "log_$start_time.log", "ConsoleLogLevel": "TRACE", "FileLogLevel": "TRACE" + }, + + "DatabaseSettings": { + "ConnectionString": "mysql+mysqlconnector://sh_messenger_server:$credentials@localhost/sh_messenger_server", + "Credentials": "ZkM1U1dyU0hXM3oyI3BfXg==", + "Encoding": "utf8mb4" } } \ No newline at end of file diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index 2ee1b09b..e17733be 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -1,11 +1,13 @@ from typing import Optional from sh_edraft.configuration.base import ConfigurationBase +from sh_edraft.database import DatabaseConnection +from sh_edraft.database.base import DatabaseConnectionBase from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting.base import ApplicationBase from sh_edraft.logging import Logger from sh_edraft.logging.base import LoggerBase -from sh_edraft.service.base import ServiceProviderBase +from sh_edraft.service.providing.base import ServiceProviderBase class Program(ApplicationBase): @@ -17,6 +19,7 @@ class Program(ApplicationBase): self._services: Optional[ServiceProviderBase] = None self._configuration: Optional[ConfigurationBase] = None self._logger: Optional[LoggerBase] = None + self._db_connection: Optional[DatabaseConnectionBase] = None def create_application_host(self): self._app_host = ApplicationHost() @@ -30,13 +33,19 @@ class Program(ApplicationBase): self._configuration.add_argument_variables() self._configuration.add_json_file(f'appsettings.json') self._configuration.add_json_file(f'appsettings.{self._configuration.environment.environment_name}.json') - self._configuration.add_json_file(f'appsettings.{self._configuration.environment.host_name}.json', optional=True) + self._configuration.add_json_file( + f'appsettings.{self._configuration.environment.host_name}.json', + optional=True + ) def create_services(self): self._services.create() self._services.add_singleton(LoggerBase, Logger) - self._logger = self._services.get_service(LoggerBase) + self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) + self._logger: Logger = self._services.get_service(LoggerBase) self._logger.create() + self._db_connection: DatabaseConnection = self._services.get_service(DatabaseConnectionBase) + self._db_connection.create() def main(self): self._logger.header(f'{self._configuration.environment.application_name}:') From 8551a0b7b736cb408204a6549eb2f5d668b03106 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 29 Nov 2020 21:48:17 +0100 Subject: [PATCH 2/7] Improved database connection --- src/sh_edraft/database/database_connection.py | 26 ++++++++++++------- src/sh_edraft/logging/logger.py | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/sh_edraft/database/database_connection.py b/src/sh_edraft/database/database_connection.py index 799f714b..31db403a 100644 --- a/src/sh_edraft/database/database_connection.py +++ b/src/sh_edraft/database/database_connection.py @@ -5,6 +5,7 @@ from sqlalchemy.orm import session, sessionmaker from sh_edraft.database.base.database_connection_base import DatabaseConnectionBase from sh_edraft.database.model.database_settings import DatabaseSettings +from sh_edraft.utils.console import Console class DatabaseConnection(DatabaseConnectionBase): @@ -19,17 +20,24 @@ class DatabaseConnection(DatabaseConnectionBase): self._credentials: Optional[str] = None def create(self): - self._engine = create_engine(self._db_settings.decrypted_connection_string) + try: + self._engine = create_engine(self._db_settings.decrypted_connection_string) - if self._db_settings.encoding is not None: - self._engine.encoding = self._db_settings.encoding + if self._db_settings.encoding is not None: + self._engine.encoding = self._db_settings.encoding - if self._db_settings.case_sensitive is not None: - self._engine.case_sensitive = self._db_settings.case_sensitive + if self._db_settings.case_sensitive is not None: + self._engine.case_sensitive = self._db_settings.case_sensitive - if self._db_settings.echo is not None: - self._engine.echo = self._db_settings.echo + if self._db_settings.echo is not None: + self._engine.echo = self._db_settings.echo - db_session = sessionmaker(bind=self._engine) - self._session = db_session() + self._engine.connect() + + db_session = sessionmaker(bind=self._engine) + self._session = db_session() + Console.write_line(f'[{__name__}] Connected to database', 'green') + except Exception as e: + Console.write_line(f'[{__name__}] Database connection failed -> {e}', 'red') + exit() diff --git a/src/sh_edraft/logging/logger.py b/src/sh_edraft/logging/logger.py index f2159ad2..dbc54740 100644 --- a/src/sh_edraft/logging/logger.py +++ b/src/sh_edraft/logging/logger.py @@ -54,7 +54,7 @@ class Logger(LoggerBase): # open log file, create if not exists path = f'{self._path}{self._log}' f = open(path, "w+") - Console.write_line(f'[{__name__}]: Using log file: {path}') + Console.write_line(f'[{__name__}]: Using log file: {path}', 'green') f.close() except Exception as e: self._fatal_console(__name__, 'Cannot open log file', ex=e) From 6977b9ae05d6b7a8eca8aa7d88c35c5de5bc7817 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 6 Dec 2020 21:14:57 +0100 Subject: [PATCH 3/7] Improved database module structure --- src/sh_edraft/hosting/application_host.py | 4 ++-- .../hosting/base/application_host_base.py | 2 +- src/sh_edraft/logging/logger.py | 2 +- src/sh_edraft/service/__init__.py | 1 + src/sh_edraft/service/base/__init__.py | 1 + src/sh_edraft/service/model/__init__.py | 1 + src/sh_edraft/utils/__init__.py | 1 - src/tests_dev/appsettings.development.json | 6 ------ src/tests_dev/program.py | 15 +++------------ 9 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/sh_edraft/hosting/application_host.py b/src/sh_edraft/hosting/application_host.py index d86283d0..e5e6b362 100644 --- a/src/sh_edraft/hosting/application_host.py +++ b/src/sh_edraft/hosting/application_host.py @@ -5,8 +5,8 @@ from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.hosting.application_runtime import ApplicationRuntime from sh_edraft.hosting.base.application_host_base import ApplicationHostBase -from sh_edraft.service.providing.service_provider import ServiceProvider -from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.service_provider import ServiceProvider +from sh_edraft.service.base.service_provider_base import ServiceProviderBase class ApplicationHost(ApplicationHostBase): diff --git a/src/sh_edraft/hosting/base/application_host_base.py b/src/sh_edraft/hosting/base/application_host_base.py index fb816ccb..4ee8c0f5 100644 --- a/src/sh_edraft/hosting/base/application_host_base.py +++ b/src/sh_edraft/hosting/base/application_host_base.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase -from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.base.service_provider_base import ServiceProviderBase class ApplicationHostBase(ABC): diff --git a/src/sh_edraft/logging/logger.py b/src/sh_edraft/logging/logger.py index dbc54740..f2159ad2 100644 --- a/src/sh_edraft/logging/logger.py +++ b/src/sh_edraft/logging/logger.py @@ -54,7 +54,7 @@ class Logger(LoggerBase): # open log file, create if not exists path = f'{self._path}{self._log}' f = open(path, "w+") - Console.write_line(f'[{__name__}]: Using log file: {path}', 'green') + Console.write_line(f'[{__name__}]: Using log file: {path}') f.close() except Exception as e: self._fatal_console(__name__, 'Cannot open log file', ex=e) diff --git a/src/sh_edraft/service/__init__.py b/src/sh_edraft/service/__init__.py index abfc6044..52003f0b 100644 --- a/src/sh_edraft/service/__init__.py +++ b/src/sh_edraft/service/__init__.py @@ -20,6 +20,7 @@ __version__ = '2020.12.5' from collections import namedtuple # imports: +from .service_provider import ServiceProvider VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/base/__init__.py b/src/sh_edraft/service/base/__init__.py index d3d865d7..6ce7f45b 100644 --- a/src/sh_edraft/service/base/__init__.py +++ b/src/sh_edraft/service/base/__init__.py @@ -21,6 +21,7 @@ from collections import namedtuple # imports: from .service_base import ServiceBase +from .service_provider_base import ServiceProviderBase VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/model/__init__.py b/src/sh_edraft/service/model/__init__.py index 05760565..b95fe3c2 100644 --- a/src/sh_edraft/service/model/__init__.py +++ b/src/sh_edraft/service/model/__init__.py @@ -20,6 +20,7 @@ __version__ = '2020.12.5' from collections import namedtuple # imports: +from .provide_state import ProvideState VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/utils/__init__.py b/src/sh_edraft/utils/__init__.py index 10d2e9e5..4130c05d 100644 --- a/src/sh_edraft/utils/__init__.py +++ b/src/sh_edraft/utils/__init__.py @@ -21,7 +21,6 @@ from collections import namedtuple # imports: from .console import Console -from .credential_manager import CredentialManager VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/tests_dev/appsettings.development.json b/src/tests_dev/appsettings.development.json index aa370960..62ec6c61 100644 --- a/src/tests_dev/appsettings.development.json +++ b/src/tests_dev/appsettings.development.json @@ -4,11 +4,5 @@ "Filename": "log_$start_time.log", "ConsoleLogLevel": "TRACE", "FileLogLevel": "TRACE" - }, - - "DatabaseSettings": { - "ConnectionString": "mysql+mysqlconnector://sh_messenger_server:$credentials@localhost/sh_messenger_server", - "Credentials": "ZkM1U1dyU0hXM3oyI3BfXg==", - "Encoding": "utf8mb4" } } \ No newline at end of file diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index e17733be..2ee1b09b 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -1,13 +1,11 @@ from typing import Optional from sh_edraft.configuration.base import ConfigurationBase -from sh_edraft.database import DatabaseConnection -from sh_edraft.database.base import DatabaseConnectionBase from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting.base import ApplicationBase from sh_edraft.logging import Logger from sh_edraft.logging.base import LoggerBase -from sh_edraft.service.providing.base import ServiceProviderBase +from sh_edraft.service.base import ServiceProviderBase class Program(ApplicationBase): @@ -19,7 +17,6 @@ class Program(ApplicationBase): self._services: Optional[ServiceProviderBase] = None self._configuration: Optional[ConfigurationBase] = None self._logger: Optional[LoggerBase] = None - self._db_connection: Optional[DatabaseConnectionBase] = None def create_application_host(self): self._app_host = ApplicationHost() @@ -33,19 +30,13 @@ class Program(ApplicationBase): self._configuration.add_argument_variables() self._configuration.add_json_file(f'appsettings.json') self._configuration.add_json_file(f'appsettings.{self._configuration.environment.environment_name}.json') - self._configuration.add_json_file( - f'appsettings.{self._configuration.environment.host_name}.json', - optional=True - ) + self._configuration.add_json_file(f'appsettings.{self._configuration.environment.host_name}.json', optional=True) def create_services(self): self._services.create() self._services.add_singleton(LoggerBase, Logger) - self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) - self._logger: Logger = self._services.get_service(LoggerBase) + self._logger = self._services.get_service(LoggerBase) self._logger.create() - self._db_connection: DatabaseConnection = self._services.get_service(DatabaseConnectionBase) - self._db_connection.create() def main(self): self._logger.header(f'{self._configuration.environment.application_name}:') From d2dc57bc76b925b706e2a79fa51fcc721c2a4d8d Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Thu, 10 Dec 2020 18:11:05 +0100 Subject: [PATCH 4/7] Improved database module structure --- src/sh_edraft/database/__init__.py | 2 -- src/sh_edraft/database/connection/__init__.py | 3 +++ .../database/{ => connection}/base/__init__.py | 0 .../base/database_connection_base.py | 3 +++ .../{ => connection}/database_connection.py | 10 +++++++--- src/sh_edraft/database/model/__init__.py | 4 ++++ .../database/model/database_settings.py | 5 ----- src/sh_edraft/hosting/application_host.py | 11 +++++++++-- .../hosting/base/application_host_base.py | 2 +- src/sh_edraft/logging/logger.py | 2 ++ src/sh_edraft/service/__init__.py | 1 - src/sh_edraft/service/base/__init__.py | 1 - src/sh_edraft/service/providing/__init__.py | 1 + src/tests_dev/appsettings.development.json | 5 +++++ src/tests_dev/program.py | 16 ++++++++++++---- 15 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 src/sh_edraft/database/connection/__init__.py rename src/sh_edraft/database/{ => connection}/base/__init__.py (100%) rename src/sh_edraft/database/{ => connection}/base/database_connection_base.py (74%) rename src/sh_edraft/database/{ => connection}/database_connection.py (83%) diff --git a/src/sh_edraft/database/__init__.py b/src/sh_edraft/database/__init__.py index eae4c82d..8b137891 100644 --- a/src/sh_edraft/database/__init__.py +++ b/src/sh_edraft/database/__init__.py @@ -1,3 +1 @@ -# imports: -from .database_connection import DatabaseConnection diff --git a/src/sh_edraft/database/connection/__init__.py b/src/sh_edraft/database/connection/__init__.py new file mode 100644 index 00000000..eae4c82d --- /dev/null +++ b/src/sh_edraft/database/connection/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .database_connection import DatabaseConnection diff --git a/src/sh_edraft/database/base/__init__.py b/src/sh_edraft/database/connection/base/__init__.py similarity index 100% rename from src/sh_edraft/database/base/__init__.py rename to src/sh_edraft/database/connection/base/__init__.py diff --git a/src/sh_edraft/database/base/database_connection_base.py b/src/sh_edraft/database/connection/base/database_connection_base.py similarity index 74% rename from src/sh_edraft/database/base/database_connection_base.py rename to src/sh_edraft/database/connection/base/database_connection_base.py index 9307c9b1..f97859bc 100644 --- a/src/sh_edraft/database/base/database_connection_base.py +++ b/src/sh_edraft/database/connection/base/database_connection_base.py @@ -8,3 +8,6 @@ class DatabaseConnectionBase(ServiceBase): @abstractmethod def __init__(self): ServiceBase.__init__(self) + + @abstractmethod + def use_mysql(self, connection_string: str): pass diff --git a/src/sh_edraft/database/database_connection.py b/src/sh_edraft/database/connection/database_connection.py similarity index 83% rename from src/sh_edraft/database/database_connection.py rename to src/sh_edraft/database/connection/database_connection.py index 31db403a..7d02c382 100644 --- a/src/sh_edraft/database/database_connection.py +++ b/src/sh_edraft/database/connection/database_connection.py @@ -3,7 +3,7 @@ from typing import Optional from sqlalchemy import engine, create_engine from sqlalchemy.orm import session, sessionmaker -from sh_edraft.database.base.database_connection_base import DatabaseConnectionBase +from sh_edraft.database.connection.base.database_connection_base import DatabaseConnectionBase from sh_edraft.database.model.database_settings import DatabaseSettings from sh_edraft.utils.console import Console @@ -19,9 +19,13 @@ class DatabaseConnection(DatabaseConnectionBase): self._session: Optional[session] = None self._credentials: Optional[str] = None - def create(self): + self.create() + + def create(self): pass + + def use_mysql(self, connection_string: str): try: - self._engine = create_engine(self._db_settings.decrypted_connection_string) + self._engine = create_engine(connection_string) if self._db_settings.encoding is not None: self._engine.encoding = self._db_settings.encoding diff --git a/src/sh_edraft/database/model/__init__.py b/src/sh_edraft/database/model/__init__.py index e69de29b..c13a207e 100644 --- a/src/sh_edraft/database/model/__init__.py +++ b/src/sh_edraft/database/model/__init__.py @@ -0,0 +1,4 @@ +# imports: + +from .database_settings import DatabaseSettings +from .database_settings_name import DatabaseSettingsName diff --git a/src/sh_edraft/database/model/database_settings.py b/src/sh_edraft/database/model/database_settings.py index 8c2def60..a8df384d 100644 --- a/src/sh_edraft/database/model/database_settings.py +++ b/src/sh_edraft/database/model/database_settings.py @@ -3,7 +3,6 @@ from typing import Optional from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase from sh_edraft.database.model.database_settings_name import DatabaseSettingsName -from sh_edraft.utils.credential_manager import CredentialManager from sh_edraft.utils.console import Console @@ -26,10 +25,6 @@ class DatabaseSettings(ConfigurationModelBase): def connection_string(self, connection_string: str): self._connection_string = connection_string - @property - def decrypted_connection_string(self) -> str: - return CredentialManager.build_string(self._connection_string, self._credentials) - @property def credentials(self) -> str: return self._credentials diff --git a/src/sh_edraft/hosting/application_host.py b/src/sh_edraft/hosting/application_host.py index e5e6b362..fa4b2182 100644 --- a/src/sh_edraft/hosting/application_host.py +++ b/src/sh_edraft/hosting/application_host.py @@ -5,18 +5,25 @@ from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.hosting.application_runtime import ApplicationRuntime from sh_edraft.hosting.base.application_host_base import ApplicationHostBase -from sh_edraft.service.service_provider import ServiceProvider -from sh_edraft.service.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.providing.service_provider import ServiceProvider +from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase class ApplicationHost(ApplicationHostBase): def __init__(self): ApplicationHostBase.__init__(self) + + # Init self._config = Configuration() self._app_runtime = ApplicationRuntime(self._config) self._services = ServiceProvider(self._app_runtime) + # Create + self._config.create() + self._services.create() + + # Set vars self._start_time: datetime = datetime.now() self._end_time: datetime = datetime.now() diff --git a/src/sh_edraft/hosting/base/application_host_base.py b/src/sh_edraft/hosting/base/application_host_base.py index 4ee8c0f5..fb816ccb 100644 --- a/src/sh_edraft/hosting/base/application_host_base.py +++ b/src/sh_edraft/hosting/base/application_host_base.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod from sh_edraft.configuration.base.configuration_base import ConfigurationBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase -from sh_edraft.service.base.service_provider_base import ServiceProviderBase +from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase class ApplicationHostBase(ABC): diff --git a/src/sh_edraft/logging/logger.py b/src/sh_edraft/logging/logger.py index f2159ad2..a043b21b 100644 --- a/src/sh_edraft/logging/logger.py +++ b/src/sh_edraft/logging/logger.py @@ -28,6 +28,8 @@ class Logger(LoggerBase): self._level = self._log_settings.level self._console = self._log_settings.console + self.create() + def _get_datetime_now(self) -> str: try: return datetime.datetime.now().strftime(self._time_format_settings.date_time_format) diff --git a/src/sh_edraft/service/__init__.py b/src/sh_edraft/service/__init__.py index 52003f0b..abfc6044 100644 --- a/src/sh_edraft/service/__init__.py +++ b/src/sh_edraft/service/__init__.py @@ -20,7 +20,6 @@ __version__ = '2020.12.5' from collections import namedtuple # imports: -from .service_provider import ServiceProvider VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/base/__init__.py b/src/sh_edraft/service/base/__init__.py index 6ce7f45b..d3d865d7 100644 --- a/src/sh_edraft/service/base/__init__.py +++ b/src/sh_edraft/service/base/__init__.py @@ -21,7 +21,6 @@ from collections import namedtuple # imports: from .service_base import ServiceBase -from .service_provider_base import ServiceProviderBase VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/sh_edraft/service/providing/__init__.py b/src/sh_edraft/service/providing/__init__.py index b8bf2077..7817c7f3 100644 --- a/src/sh_edraft/service/providing/__init__.py +++ b/src/sh_edraft/service/providing/__init__.py @@ -1,3 +1,4 @@ # imports: +from .service_provider import ServiceProvider from .service_provider import ServiceProviderBase diff --git a/src/tests_dev/appsettings.development.json b/src/tests_dev/appsettings.development.json index 62ec6c61..3a54f3cc 100644 --- a/src/tests_dev/appsettings.development.json +++ b/src/tests_dev/appsettings.development.json @@ -4,5 +4,10 @@ "Filename": "log_$start_time.log", "ConsoleLogLevel": "TRACE", "FileLogLevel": "TRACE" + }, + "DatabaseSettings": { + "ConnectionString": "mysql+mysqlconnector://sh_cpl:$credentials@localhost/sh_cpl", + "Credentials": "MHZhc0Y2bjhKc1VUMWV0Qw==", + "Encoding": "utf8mb4" } } \ No newline at end of file diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index 2ee1b09b..d780d0c7 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -1,11 +1,15 @@ from typing import Optional from sh_edraft.configuration.base import ConfigurationBase +from sh_edraft.database.connection import DatabaseConnection +from sh_edraft.database.connection.base import DatabaseConnectionBase +from sh_edraft.database.model import DatabaseSettings from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting.base import ApplicationBase from sh_edraft.logging import Logger from sh_edraft.logging.base import LoggerBase -from sh_edraft.service.base import ServiceProviderBase +from sh_edraft.service.providing.base import ServiceProviderBase +from sh_edraft.utils.credential_manager import CredentialManager class Program(ApplicationBase): @@ -24,7 +28,6 @@ class Program(ApplicationBase): self._services = self._app_host.services def create_configuration(self): - self._configuration.create() self._configuration.add_environment_variables('PYTHON_') self._configuration.add_environment_variables('CPL_') self._configuration.add_argument_variables() @@ -33,10 +36,15 @@ class Program(ApplicationBase): self._configuration.add_json_file(f'appsettings.{self._configuration.environment.host_name}.json', optional=True) def create_services(self): - self._services.create() + # Create and connect to database + db_settings: DatabaseSettings = self._configuration.get_configuration(DatabaseSettings) + self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) + db: DatabaseConnectionBase = self._services.get_service(DatabaseConnectionBase) + db.use_mysql(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials)) + + # Add and create logger self._services.add_singleton(LoggerBase, Logger) self._logger = self._services.get_service(LoggerBase) - self._logger.create() def main(self): self._logger.header(f'{self._configuration.environment.application_name}:') From ee60be98808333f192d39eb45616e728fb2485b8 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 11 Dec 2020 19:42:09 +0100 Subject: [PATCH 5/7] Changed DatabaseConnection --- src/sh_edraft/database/__init__.py | 2 +- .../connection/base/database_connection_base.py | 13 ++++++++++++- .../database/connection/database_connection.py | 10 +++++++++- src/tests_dev/program.py | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/sh_edraft/database/__init__.py b/src/sh_edraft/database/__init__.py index 8b137891..52f86f25 100644 --- a/src/sh_edraft/database/__init__.py +++ b/src/sh_edraft/database/__init__.py @@ -1 +1 @@ - +# imports: diff --git a/src/sh_edraft/database/connection/base/database_connection_base.py b/src/sh_edraft/database/connection/base/database_connection_base.py index f97859bc..c530f593 100644 --- a/src/sh_edraft/database/connection/base/database_connection_base.py +++ b/src/sh_edraft/database/connection/base/database_connection_base.py @@ -1,5 +1,8 @@ from abc import abstractmethod +from sqlalchemy import engine +from sqlalchemy.orm import session + from sh_edraft.service.base.service_base import ServiceBase @@ -9,5 +12,13 @@ class DatabaseConnectionBase(ServiceBase): def __init__(self): ServiceBase.__init__(self) + @property @abstractmethod - def use_mysql(self, connection_string: str): pass + def engine(self) -> engine: pass + + @property + @abstractmethod + def session(self) -> session: pass + + @abstractmethod + def connect(self, connection_string: str): pass diff --git a/src/sh_edraft/database/connection/database_connection.py b/src/sh_edraft/database/connection/database_connection.py index 7d02c382..2c274ccf 100644 --- a/src/sh_edraft/database/connection/database_connection.py +++ b/src/sh_edraft/database/connection/database_connection.py @@ -21,9 +21,17 @@ class DatabaseConnection(DatabaseConnectionBase): self.create() + @property + def engine(self) -> engine: + return self._engine + + @property + def session(self) -> session: + return self._session + def create(self): pass - def use_mysql(self, connection_string: str): + def connect(self, connection_string: str): try: self._engine = create_engine(connection_string) diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index d780d0c7..94796c55 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -40,7 +40,7 @@ class Program(ApplicationBase): db_settings: DatabaseSettings = self._configuration.get_configuration(DatabaseSettings) self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) db: DatabaseConnectionBase = self._services.get_service(DatabaseConnectionBase) - db.use_mysql(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials)) + db.connect(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials)) # Add and create logger self._services.add_singleton(LoggerBase, Logger) From 03ba1d1847dec44ec9fa1131901f4c76df9962c0 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 11 Dec 2020 21:48:46 +0100 Subject: [PATCH 6/7] Added first version of database and orm --- .../base/database_connection_base.py | 9 ++-- .../connection/database_connection.py | 4 -- src/sh_edraft/database/context/__init__.py | 3 ++ .../database/context/base/__init__.py | 3 ++ .../context/base/database_context_base.py | 27 +++++++++++ .../database/context/database_context.py | 45 +++++++++++++++++++ src/sh_edraft/database/model/__init__.py | 1 + src/sh_edraft/database/model/dbmodel.py | 3 ++ .../providing/base/service_provider_base.py | 14 ++++-- .../service/providing/service_provider.py | 13 +++++- src/sh_edraft/utils/__init__.py | 1 + src/tests_dev/db/__init__.py | 0 src/tests_dev/db/city.py | 14 ++++++ src/tests_dev/db/user.py | 18 ++++++++ src/tests_dev/db/user_repo.py | 23 ++++++++++ src/tests_dev/db/user_repo_base.py | 10 +++++ src/tests_dev/program.py | 15 ++++--- 17 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 src/sh_edraft/database/context/__init__.py create mode 100644 src/sh_edraft/database/context/base/__init__.py create mode 100644 src/sh_edraft/database/context/base/database_context_base.py create mode 100644 src/sh_edraft/database/context/database_context.py create mode 100644 src/sh_edraft/database/model/dbmodel.py create mode 100644 src/tests_dev/db/__init__.py create mode 100644 src/tests_dev/db/city.py create mode 100644 src/tests_dev/db/user.py create mode 100644 src/tests_dev/db/user_repo.py create mode 100644 src/tests_dev/db/user_repo_base.py diff --git a/src/sh_edraft/database/connection/base/database_connection_base.py b/src/sh_edraft/database/connection/base/database_connection_base.py index c530f593..8a3e28ec 100644 --- a/src/sh_edraft/database/connection/base/database_connection_base.py +++ b/src/sh_edraft/database/connection/base/database_connection_base.py @@ -1,16 +1,13 @@ -from abc import abstractmethod +from abc import abstractmethod, ABC from sqlalchemy import engine from sqlalchemy.orm import session -from sh_edraft.service.base.service_base import ServiceBase - -class DatabaseConnectionBase(ServiceBase): +class DatabaseConnectionBase(ABC): @abstractmethod - def __init__(self): - ServiceBase.__init__(self) + def __init__(self): pass @property @abstractmethod diff --git a/src/sh_edraft/database/connection/database_connection.py b/src/sh_edraft/database/connection/database_connection.py index 2c274ccf..eac20341 100644 --- a/src/sh_edraft/database/connection/database_connection.py +++ b/src/sh_edraft/database/connection/database_connection.py @@ -19,8 +19,6 @@ class DatabaseConnection(DatabaseConnectionBase): self._session: Optional[session] = None self._credentials: Optional[str] = None - self.create() - @property def engine(self) -> engine: return self._engine @@ -29,8 +27,6 @@ class DatabaseConnection(DatabaseConnectionBase): def session(self) -> session: return self._session - def create(self): pass - def connect(self, connection_string: str): try: self._engine = create_engine(connection_string) diff --git a/src/sh_edraft/database/context/__init__.py b/src/sh_edraft/database/context/__init__.py new file mode 100644 index 00000000..0e46ede4 --- /dev/null +++ b/src/sh_edraft/database/context/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .database_context import DatabaseContext diff --git a/src/sh_edraft/database/context/base/__init__.py b/src/sh_edraft/database/context/base/__init__.py new file mode 100644 index 00000000..ad5b61fb --- /dev/null +++ b/src/sh_edraft/database/context/base/__init__.py @@ -0,0 +1,3 @@ +# imports: + +from .database_context_base import DatabaseContextBase diff --git a/src/sh_edraft/database/context/base/database_context_base.py b/src/sh_edraft/database/context/base/database_context_base.py new file mode 100644 index 00000000..a18b6efe --- /dev/null +++ b/src/sh_edraft/database/context/base/database_context_base.py @@ -0,0 +1,27 @@ +from abc import abstractmethod + +from sqlalchemy import engine +from sqlalchemy.orm import session + +from sh_edraft.service.base.service_base import ServiceBase + + +class DatabaseContextBase(ServiceBase): + + @abstractmethod + def __init__(self): + ServiceBase.__init__(self) + + @property + @abstractmethod + def engine(self) -> engine: pass + + @property + @abstractmethod + def session(self) -> session: pass + + @abstractmethod + def connect(self, connection_string: str): pass + + @abstractmethod + def _create_tables(self): pass diff --git a/src/sh_edraft/database/context/database_context.py b/src/sh_edraft/database/context/database_context.py new file mode 100644 index 00000000..a9fd1b7e --- /dev/null +++ b/src/sh_edraft/database/context/database_context.py @@ -0,0 +1,45 @@ +from sqlalchemy import engine, Table +from sqlalchemy.orm import session + +from sh_edraft.database.connection.database_connection import DatabaseConnection +from sh_edraft.database.connection.base.database_connection_base import DatabaseConnectionBase +from sh_edraft.database.context.base.database_context_base import DatabaseContextBase +from sh_edraft.database.model.dbmodel import DBModel +from sh_edraft.database.model.database_settings import DatabaseSettings +from sh_edraft.utils.console import Console + + +class DatabaseContext(DatabaseContextBase): + + def __init__(self, database_settings: DatabaseSettings): + DatabaseContextBase.__init__(self) + + self._db: DatabaseConnectionBase = DatabaseConnection(database_settings) + self._tables: list[Table] = [] + + @property + def engine(self) -> engine: + return self._db.engine + + @property + def session(self) -> session: + return self._db.session + + def create(self): + pass + + def connect(self, connection_string: str): + self._db.connect(connection_string) + self._create_tables() + + def _create_tables(self): + try: + for subclass in DBModel.__subclasses__(): + self._tables.append(subclass.__table__) + + DBModel.metadata.drop_all(self._db.engine, self._tables) + DBModel.metadata.create_all(self._db.engine, self._tables, checkfirst=True) + Console.write_line(f'[{__name__}] Created tables', 'green') + except Exception as e: + Console.write_line(f'[{__name__}] Creating tables failed -> {e}', 'red') + exit() diff --git a/src/sh_edraft/database/model/__init__.py b/src/sh_edraft/database/model/__init__.py index c13a207e..b51f2dca 100644 --- a/src/sh_edraft/database/model/__init__.py +++ b/src/sh_edraft/database/model/__init__.py @@ -2,3 +2,4 @@ from .database_settings import DatabaseSettings from .database_settings_name import DatabaseSettingsName +from .dbmodel import DBModel diff --git a/src/sh_edraft/database/model/dbmodel.py b/src/sh_edraft/database/model/dbmodel.py new file mode 100644 index 00000000..145da02b --- /dev/null +++ b/src/sh_edraft/database/model/dbmodel.py @@ -0,0 +1,3 @@ +from sqlalchemy.ext.declarative import declarative_base + +DBModel: declarative_base = declarative_base() diff --git a/src/sh_edraft/service/providing/base/service_provider_base.py b/src/sh_edraft/service/providing/base/service_provider_base.py index 58d3a64f..28c986f0 100644 --- a/src/sh_edraft/service/providing/base/service_provider_base.py +++ b/src/sh_edraft/service/providing/base/service_provider_base.py @@ -1,15 +1,21 @@ -from abc import abstractmethod +from abc import abstractmethod, ABC from collections import Callable from typing import Type +from sh_edraft.database.context.base.database_context_base import DatabaseContextBase from sh_edraft.service.base.service_base import ServiceBase -class ServiceProviderBase(ServiceBase): +class ServiceProviderBase(ABC): @abstractmethod - def __init__(self): - ServiceBase.__init__(self) + def __init__(self): pass + + @abstractmethod + def add_db_context(self, db_context: Type[DatabaseContextBase]): pass + + @abstractmethod + def get_db_context(self) -> Callable[DatabaseContextBase]: pass @abstractmethod def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass diff --git a/src/sh_edraft/service/providing/service_provider.py b/src/sh_edraft/service/providing/service_provider.py index 205f8359..b4defc4b 100644 --- a/src/sh_edraft/service/providing/service_provider.py +++ b/src/sh_edraft/service/providing/service_provider.py @@ -1,8 +1,9 @@ from collections import Callable from inspect import signature, Parameter -from typing import Type +from typing import Type, Optional from sh_edraft.configuration.base.configuration_model_base import ConfigurationModelBase +from sh_edraft.database.context.base.database_context_base import DatabaseContextBase from sh_edraft.hosting.base.application_runtime_base import ApplicationRuntimeBase from sh_edraft.service.providing.base.service_provider_base import ServiceProviderBase from sh_edraft.service.base.service_base import ServiceBase @@ -13,6 +14,7 @@ class ServiceProvider(ServiceProviderBase): def __init__(self, app_runtime: ApplicationRuntimeBase): ServiceProviderBase.__init__(self) self._app_runtime: ApplicationRuntimeBase = app_runtime + self._database_context: Optional[DatabaseContextBase] = None self._transient_services: dict[Type[ServiceBase], Type[ServiceBase]] = {} self._scoped_services: dict[Type[ServiceBase], Type[ServiceBase]] = {} @@ -29,6 +31,9 @@ class ServiceProvider(ServiceProviderBase): if issubclass(parameter.annotation, ApplicationRuntimeBase): params.append(self._app_runtime) + elif issubclass(parameter.annotation, DatabaseContextBase): + params.append(self._database_context) + elif issubclass(parameter.annotation, ServiceBase): params.append(self.get_service(parameter.annotation)) @@ -37,6 +42,12 @@ class ServiceProvider(ServiceProviderBase): return service(*params) + def add_db_context(self, db_context: Type[DatabaseContextBase]): + self._database_context = self._create_instance(db_context) + + def get_db_context(self) -> Callable[DatabaseContextBase]: + return self._database_context + def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): self._transient_services[service_type] = service diff --git a/src/sh_edraft/utils/__init__.py b/src/sh_edraft/utils/__init__.py index 4130c05d..10d2e9e5 100644 --- a/src/sh_edraft/utils/__init__.py +++ b/src/sh_edraft/utils/__init__.py @@ -21,6 +21,7 @@ from collections import namedtuple # imports: from .console import Console +from .credential_manager import CredentialManager VersionInfo = namedtuple('VersionInfo', 'major minor micro') version_info = VersionInfo(major=2020, minor=12, micro=5) diff --git a/src/tests_dev/db/__init__.py b/src/tests_dev/db/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/tests_dev/db/city.py b/src/tests_dev/db/city.py new file mode 100644 index 00000000..baf07ded --- /dev/null +++ b/src/tests_dev/db/city.py @@ -0,0 +1,14 @@ +from sqlalchemy import Column, Integer, String + +from sh_edraft.database.model import DBModel + + +class City(DBModel): + __tablename__ = 'Cities' + Id = Column(Integer, primary_key=True, nullable=False, autoincrement=True) + Name = Column(String(64), nullable=False) + ZIP = Column(String(5), nullable=False) + + def __init__(self, name: str, zip_code: str): + self.Name = name + self.ZIP = zip_code diff --git a/src/tests_dev/db/user.py b/src/tests_dev/db/user.py new file mode 100644 index 00000000..e840df86 --- /dev/null +++ b/src/tests_dev/db/user.py @@ -0,0 +1,18 @@ +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship + +from sh_edraft.database.model import DBModel +from tests_dev.db.city import City as CityModel + + +class User(DBModel): + __tablename__ = 'Users' + Id = Column(Integer, primary_key=True, nullable=False, autoincrement=True) + Name = Column(String(64), nullable=False) + City_Id = Column(Integer, ForeignKey('Cities.Id'), nullable=False) + City = relationship("City") + + def __init__(self, name: str, city: CityModel): + self.Name = name + self.City_Id = city.Id + self.City = city diff --git a/src/tests_dev/db/user_repo.py b/src/tests_dev/db/user_repo.py new file mode 100644 index 00000000..a1b3cffc --- /dev/null +++ b/src/tests_dev/db/user_repo.py @@ -0,0 +1,23 @@ +from sh_edraft.database.context.base import DatabaseContextBase +from tests_dev.db.city import City +from tests_dev.db.user import User +from tests_dev.db.user_repo_base import UserRepoBase + + +class UserRepo(UserRepoBase): + + def __init__(self, db_context: DatabaseContextBase): + UserRepoBase.__init__(self) + + self._session = db_context.session + self._user_query = db_context.session.query(User) + + def create(self): pass + + def add_test_user(self): + city = City('Haren', '49733') + city2 = City('Meppen', '49716') + self._session.add(city2) + user = User('TestUser', city) + self._session.add(user) + self._session.commit() diff --git a/src/tests_dev/db/user_repo_base.py b/src/tests_dev/db/user_repo_base.py new file mode 100644 index 00000000..c48be0b2 --- /dev/null +++ b/src/tests_dev/db/user_repo_base.py @@ -0,0 +1,10 @@ +from abc import abstractmethod + +from sh_edraft.service.base import ServiceBase + + +class UserRepoBase(ServiceBase): + + @abstractmethod + def __init__(self): + ServiceBase.__init__(self) diff --git a/src/tests_dev/program.py b/src/tests_dev/program.py index 94796c55..baf29064 100644 --- a/src/tests_dev/program.py +++ b/src/tests_dev/program.py @@ -1,15 +1,17 @@ from typing import Optional from sh_edraft.configuration.base import ConfigurationBase -from sh_edraft.database.connection import DatabaseConnection -from sh_edraft.database.connection.base import DatabaseConnectionBase +from sh_edraft.database.context import DatabaseContext from sh_edraft.database.model import DatabaseSettings from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting.base import ApplicationBase from sh_edraft.logging import Logger from sh_edraft.logging.base import LoggerBase from sh_edraft.service.providing.base import ServiceProviderBase -from sh_edraft.utils.credential_manager import CredentialManager +from sh_edraft.utils import CredentialManager + +from tests_dev.db.user_repo import UserRepo +from tests_dev.db.user_repo_base import UserRepoBase class Program(ApplicationBase): @@ -38,10 +40,12 @@ class Program(ApplicationBase): def create_services(self): # Create and connect to database db_settings: DatabaseSettings = self._configuration.get_configuration(DatabaseSettings) - self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) - db: DatabaseConnectionBase = self._services.get_service(DatabaseConnectionBase) + self._services.add_db_context(DatabaseContext) + db: DatabaseContext = self._services.get_db_context() db.connect(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials)) + self._services.add_scoped(UserRepoBase, UserRepo) + # Add and create logger self._services.add_singleton(LoggerBase, Logger) self._logger = self._services.get_service(LoggerBase) @@ -51,3 +55,4 @@ class Program(ApplicationBase): self._logger.debug(__name__, f'Host: {self._configuration.environment.host_name}') self._logger.debug(__name__, f'Environment: {self._configuration.environment.environment_name}') self._logger.debug(__name__, f'Customer: {self._configuration.environment.customer}') + self._services.get_service(UserRepoBase).add_test_user() From 96625845605a653f49028438474d3789347878e7 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 14 Dec 2020 19:51:25 +0100 Subject: [PATCH 7/7] Improved session reference --- .../database/connection/base/database_connection_base.py | 4 ++-- src/sh_edraft/database/connection/database_connection.py | 6 +++--- .../database/context/base/database_context_base.py | 4 ++-- src/sh_edraft/database/context/database_context.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sh_edraft/database/connection/base/database_connection_base.py b/src/sh_edraft/database/connection/base/database_connection_base.py index 8a3e28ec..9bc31427 100644 --- a/src/sh_edraft/database/connection/base/database_connection_base.py +++ b/src/sh_edraft/database/connection/base/database_connection_base.py @@ -1,7 +1,7 @@ from abc import abstractmethod, ABC from sqlalchemy import engine -from sqlalchemy.orm import session +from sqlalchemy.orm import Session class DatabaseConnectionBase(ABC): @@ -15,7 +15,7 @@ class DatabaseConnectionBase(ABC): @property @abstractmethod - def session(self) -> session: pass + def session(self) -> Session: pass @abstractmethod def connect(self, connection_string: str): pass diff --git a/src/sh_edraft/database/connection/database_connection.py b/src/sh_edraft/database/connection/database_connection.py index eac20341..9c50ae79 100644 --- a/src/sh_edraft/database/connection/database_connection.py +++ b/src/sh_edraft/database/connection/database_connection.py @@ -1,7 +1,7 @@ from typing import Optional from sqlalchemy import engine, create_engine -from sqlalchemy.orm import session, sessionmaker +from sqlalchemy.orm import Session, sessionmaker from sh_edraft.database.connection.base.database_connection_base import DatabaseConnectionBase from sh_edraft.database.model.database_settings import DatabaseSettings @@ -16,7 +16,7 @@ class DatabaseConnection(DatabaseConnectionBase): self._db_settings = database_settings self._engine: Optional[engine] = None - self._session: Optional[session] = None + self._session: Optional[Session] = None self._credentials: Optional[str] = None @property @@ -24,7 +24,7 @@ class DatabaseConnection(DatabaseConnectionBase): return self._engine @property - def session(self) -> session: + def session(self) -> Session: return self._session def connect(self, connection_string: str): diff --git a/src/sh_edraft/database/context/base/database_context_base.py b/src/sh_edraft/database/context/base/database_context_base.py index a18b6efe..b8294e64 100644 --- a/src/sh_edraft/database/context/base/database_context_base.py +++ b/src/sh_edraft/database/context/base/database_context_base.py @@ -1,7 +1,7 @@ from abc import abstractmethod from sqlalchemy import engine -from sqlalchemy.orm import session +from sqlalchemy.orm import Session from sh_edraft.service.base.service_base import ServiceBase @@ -18,7 +18,7 @@ class DatabaseContextBase(ServiceBase): @property @abstractmethod - def session(self) -> session: pass + def session(self) -> Session: pass @abstractmethod def connect(self, connection_string: str): pass diff --git a/src/sh_edraft/database/context/database_context.py b/src/sh_edraft/database/context/database_context.py index a9fd1b7e..07ba3719 100644 --- a/src/sh_edraft/database/context/database_context.py +++ b/src/sh_edraft/database/context/database_context.py @@ -1,5 +1,5 @@ from sqlalchemy import engine, Table -from sqlalchemy.orm import session +from sqlalchemy.orm import Session from sh_edraft.database.connection.database_connection import DatabaseConnection from sh_edraft.database.connection.base.database_connection_base import DatabaseConnectionBase @@ -22,7 +22,7 @@ class DatabaseContext(DatabaseContextBase): return self._db.engine @property - def session(self) -> session: + def session(self) -> Session: return self._db.session def create(self):