Added first version of database and orm

This commit is contained in:
Sven Heidemann 2020-12-11 21:48:46 +01:00
parent ee60be9880
commit 03ba1d1847
17 changed files with 183 additions and 20 deletions

View File

@ -1,16 +1,13 @@
from abc import abstractmethod from abc import abstractmethod, ABC
from sqlalchemy import engine from sqlalchemy import engine
from sqlalchemy.orm import session from sqlalchemy.orm import session
from sh_edraft.service.base.service_base import ServiceBase
class DatabaseConnectionBase(ABC):
class DatabaseConnectionBase(ServiceBase):
@abstractmethod @abstractmethod
def __init__(self): def __init__(self): pass
ServiceBase.__init__(self)
@property @property
@abstractmethod @abstractmethod

View File

@ -19,8 +19,6 @@ class DatabaseConnection(DatabaseConnectionBase):
self._session: Optional[session] = None self._session: Optional[session] = None
self._credentials: Optional[str] = None self._credentials: Optional[str] = None
self.create()
@property @property
def engine(self) -> engine: def engine(self) -> engine:
return self._engine return self._engine
@ -29,8 +27,6 @@ class DatabaseConnection(DatabaseConnectionBase):
def session(self) -> session: def session(self) -> session:
return self._session return self._session
def create(self): pass
def connect(self, connection_string: str): def connect(self, connection_string: str):
try: try:
self._engine = create_engine(connection_string) self._engine = create_engine(connection_string)

View File

@ -0,0 +1,3 @@
# imports:
from .database_context import DatabaseContext

View File

@ -0,0 +1,3 @@
# imports:
from .database_context_base import DatabaseContextBase

View File

@ -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

View File

@ -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()

View File

@ -2,3 +2,4 @@
from .database_settings import DatabaseSettings from .database_settings import DatabaseSettings
from .database_settings_name import DatabaseSettingsName from .database_settings_name import DatabaseSettingsName
from .dbmodel import DBModel

View File

@ -0,0 +1,3 @@
from sqlalchemy.ext.declarative import declarative_base
DBModel: declarative_base = declarative_base()

View File

@ -1,15 +1,21 @@
from abc import abstractmethod from abc import abstractmethod, ABC
from collections import Callable from collections import Callable
from typing import Type from typing import Type
from sh_edraft.database.context.base.database_context_base import DatabaseContextBase
from sh_edraft.service.base.service_base import ServiceBase from sh_edraft.service.base.service_base import ServiceBase
class ServiceProviderBase(ServiceBase): class ServiceProviderBase(ABC):
@abstractmethod @abstractmethod
def __init__(self): def __init__(self): pass
ServiceBase.__init__(self)
@abstractmethod
def add_db_context(self, db_context: Type[DatabaseContextBase]): pass
@abstractmethod
def get_db_context(self) -> Callable[DatabaseContextBase]: pass
@abstractmethod @abstractmethod
def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]): pass

View File

@ -1,8 +1,9 @@
from collections import Callable from collections import Callable
from inspect import signature, Parameter 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.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.hosting.base.application_runtime_base import ApplicationRuntimeBase
from sh_edraft.service.providing.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 from sh_edraft.service.base.service_base import ServiceBase
@ -13,6 +14,7 @@ class ServiceProvider(ServiceProviderBase):
def __init__(self, app_runtime: ApplicationRuntimeBase): def __init__(self, app_runtime: ApplicationRuntimeBase):
ServiceProviderBase.__init__(self) ServiceProviderBase.__init__(self)
self._app_runtime: ApplicationRuntimeBase = app_runtime self._app_runtime: ApplicationRuntimeBase = app_runtime
self._database_context: Optional[DatabaseContextBase] = None
self._transient_services: dict[Type[ServiceBase], Type[ServiceBase]] = {} self._transient_services: dict[Type[ServiceBase], Type[ServiceBase]] = {}
self._scoped_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): if issubclass(parameter.annotation, ApplicationRuntimeBase):
params.append(self._app_runtime) params.append(self._app_runtime)
elif issubclass(parameter.annotation, DatabaseContextBase):
params.append(self._database_context)
elif issubclass(parameter.annotation, ServiceBase): elif issubclass(parameter.annotation, ServiceBase):
params.append(self.get_service(parameter.annotation)) params.append(self.get_service(parameter.annotation))
@ -37,6 +42,12 @@ class ServiceProvider(ServiceProviderBase):
return service(*params) 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]): def add_transient(self, service_type: Type[ServiceBase], service: Type[ServiceBase]):
self._transient_services[service_type] = service self._transient_services[service_type] = service

View File

@ -21,6 +21,7 @@ from collections import namedtuple
# imports: # imports:
from .console import Console from .console import Console
from .credential_manager import CredentialManager
VersionInfo = namedtuple('VersionInfo', 'major minor micro') VersionInfo = namedtuple('VersionInfo', 'major minor micro')
version_info = VersionInfo(major=2020, minor=12, micro=5) version_info = VersionInfo(major=2020, minor=12, micro=5)

View File

14
src/tests_dev/db/city.py Normal file
View File

@ -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

18
src/tests_dev/db/user.py Normal file
View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -1,15 +1,17 @@
from typing import Optional from typing import Optional
from sh_edraft.configuration.base import ConfigurationBase from sh_edraft.configuration.base import ConfigurationBase
from sh_edraft.database.connection import DatabaseConnection from sh_edraft.database.context import DatabaseContext
from sh_edraft.database.connection.base import DatabaseConnectionBase
from sh_edraft.database.model import DatabaseSettings from sh_edraft.database.model import DatabaseSettings
from sh_edraft.hosting import ApplicationHost from sh_edraft.hosting import ApplicationHost
from sh_edraft.hosting.base import ApplicationBase from sh_edraft.hosting.base import ApplicationBase
from sh_edraft.logging import Logger from sh_edraft.logging import Logger
from sh_edraft.logging.base import LoggerBase from sh_edraft.logging.base import LoggerBase
from sh_edraft.service.providing.base import ServiceProviderBase 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): class Program(ApplicationBase):
@ -38,10 +40,12 @@ class Program(ApplicationBase):
def create_services(self): def create_services(self):
# Create and connect to database # Create and connect to database
db_settings: DatabaseSettings = self._configuration.get_configuration(DatabaseSettings) db_settings: DatabaseSettings = self._configuration.get_configuration(DatabaseSettings)
self._services.add_singleton(DatabaseConnectionBase, DatabaseConnection) self._services.add_db_context(DatabaseContext)
db: DatabaseConnectionBase = self._services.get_service(DatabaseConnectionBase) db: DatabaseContext = self._services.get_db_context()
db.connect(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials)) db.connect(CredentialManager.build_string(db_settings.connection_string, db_settings.credentials))
self._services.add_scoped(UserRepoBase, UserRepo)
# Add and create logger # Add and create logger
self._services.add_singleton(LoggerBase, Logger) self._services.add_singleton(LoggerBase, Logger)
self._logger = self._services.get_service(LoggerBase) 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'Host: {self._configuration.environment.host_name}')
self._logger.debug(__name__, f'Environment: {self._configuration.environment.environment_name}') self._logger.debug(__name__, f'Environment: {self._configuration.environment.environment_name}')
self._logger.debug(__name__, f'Customer: {self._configuration.environment.customer}') self._logger.debug(__name__, f'Customer: {self._configuration.environment.customer}')
self._services.get_service(UserRepoBase).add_test_user()