A-0.3 - Basismodul #36
@ -3,8 +3,10 @@ from cpl_core.configuration import ConfigurationABC
|
|||||||
from cpl_core.console import Console
|
from cpl_core.console import Console
|
||||||
from cpl_core.dependency_injection import ServiceProviderABC
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
from cpl_core.logging import LoggerABC
|
from cpl_core.logging import LoggerABC
|
||||||
|
|
||||||
from gismo_core.abc.bot_service_abc import BotServiceABC
|
from gismo_core.abc.bot_service_abc import BotServiceABC
|
||||||
from gismo_core.service.bot_service import BotService
|
from gismo_core.service.bot_service import BotService
|
||||||
|
from gismo_data.service.migration_service import MigrationService
|
||||||
|
|
||||||
|
|
||||||
class Gismo(ApplicationABC):
|
class Gismo(ApplicationABC):
|
||||||
@ -14,12 +16,14 @@ class Gismo(ApplicationABC):
|
|||||||
|
|
||||||
self._bot: BotService = services.get_service(BotServiceABC)
|
self._bot: BotService = services.get_service(BotServiceABC)
|
||||||
self._logger: LoggerABC = services.get_service(LoggerABC)
|
self._logger: LoggerABC = services.get_service(LoggerABC)
|
||||||
|
self._migrations: MigrationService = services.get_service(MigrationService)
|
||||||
|
|
||||||
async def configure(self):
|
async def configure(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def main(self):
|
async def main(self):
|
||||||
try:
|
try:
|
||||||
|
self._migrations.migrate()
|
||||||
self._logger.trace(__name__, f'Try to start {BotService}')
|
self._logger.trace(__name__, f'Try to start {BotService}')
|
||||||
await self._bot.start_async()
|
await self._bot.start_async()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -15,12 +15,17 @@ from gismo_core.abc.message_service_abc import MessageServiceABC
|
|||||||
from gismo_core.service.bot_service import BotService
|
from gismo_core.service.bot_service import BotService
|
||||||
from gismo_core.service.message_service import MessageService
|
from gismo_core.service.message_service import MessageService
|
||||||
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
from gismo_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||||
|
from gismo_data.abc.migration_abc import MigrationABC
|
||||||
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
|
from gismo_data.abc.server_repository_abc import ServerRepositoryABC
|
||||||
from gismo_data.abc.user_repository_abc import UserRepositoryABC
|
from gismo_data.abc.user_repository_abc import UserRepositoryABC
|
||||||
from gismo_data.db_context import DBContext
|
from gismo_data.db_context import DBContext
|
||||||
|
from gismo_data.migration.initial_migration import InitialMigration
|
||||||
|
from gismo_data.migration.migration_0_3 import Migration_0_3
|
||||||
from gismo_data.service.client_repository_service import (
|
from gismo_data.service.client_repository_service import (
|
||||||
ClientRepositoryABC, ClientRepositoryService)
|
ClientRepositoryABC, ClientRepositoryService)
|
||||||
from gismo_data.service.known_user_repository_service import KnownUserRepositoryService
|
from gismo_data.service.known_user_repository_service import \
|
||||||
|
KnownUserRepositoryService
|
||||||
|
from gismo_data.service.migration_service import MigrationService
|
||||||
from gismo_data.service.server_repository_service import \
|
from gismo_data.service.server_repository_service import \
|
||||||
ServerRepositoryService
|
ServerRepositoryService
|
||||||
from gismo_data.service.user_repository_service import UserRepositoryService
|
from gismo_data.service.user_repository_service import UserRepositoryService
|
||||||
@ -58,18 +63,28 @@ class Startup(StartupABC):
|
|||||||
|
|
||||||
services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings))
|
services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings))
|
||||||
|
|
||||||
|
# modules
|
||||||
services.add_singleton(ModuleServiceABC, ModuleService)
|
services.add_singleton(ModuleServiceABC, ModuleService)
|
||||||
services.add_singleton(BotServiceABC, BotService)
|
services.add_singleton(BotServiceABC, BotService)
|
||||||
services.add_transient(MessageServiceABC, MessageService)
|
services.add_transient(MessageServiceABC, MessageService)
|
||||||
|
|
||||||
|
# services
|
||||||
|
services.add_transient(MigrationService)
|
||||||
|
|
||||||
|
# data services
|
||||||
services.add_transient(ServerRepositoryABC, ServerRepositoryService)
|
services.add_transient(ServerRepositoryABC, ServerRepositoryService)
|
||||||
services.add_transient(UserRepositoryABC, UserRepositoryService)
|
services.add_transient(UserRepositoryABC, UserRepositoryService)
|
||||||
services.add_transient(ClientRepositoryABC, ClientRepositoryService)
|
services.add_transient(ClientRepositoryABC, ClientRepositoryService)
|
||||||
services.add_transient(KnownUserRepositoryABC, KnownUserRepositoryService)
|
services.add_transient(KnownUserRepositoryABC, KnownUserRepositoryService)
|
||||||
|
|
||||||
|
# modules
|
||||||
services.add_transient(ModuleABC, Database)
|
services.add_transient(ModuleABC, Database)
|
||||||
services.add_transient(ModuleABC, Base)
|
services.add_transient(ModuleABC, Base)
|
||||||
services.add_transient(ModuleABC, BootLog)
|
services.add_transient(ModuleABC, BootLog)
|
||||||
|
|
||||||
|
# migrations
|
||||||
|
services.add_transient(MigrationABC, InitialMigration)
|
||||||
|
services.add_transient(MigrationABC, Migration_0_3)
|
||||||
|
|
||||||
provider: ServiceProviderABC = services.build_service_provider()
|
provider: ServiceProviderABC = services.build_service_provider()
|
||||||
|
|
||||||
|
13
src/gismo_data/abc/migration_abc.py
Normal file
13
src/gismo_data/abc/migration_abc.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationABC(ABC):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def __init__(self): pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def upgrade(self): pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def downgrade(self): pass
|
@ -16,10 +16,6 @@ class DBContext(DatabaseContext):
|
|||||||
try:
|
try:
|
||||||
self._logger.debug(__name__, "Connecting to database")
|
self._logger.debug(__name__, "Connecting to database")
|
||||||
self._db.connect(database_settings)
|
self._db.connect(database_settings)
|
||||||
for table in self._tables:
|
|
||||||
self._logger.debug(__name__, f"Create table if not exists: {table}")
|
|
||||||
self._logger.trace(__name__, f'Send SQL command: {table.get_create_string()}')
|
|
||||||
self._db.cursor.execute(table.get_create_string())
|
|
||||||
|
|
||||||
self.save_changes()
|
self.save_changes()
|
||||||
self._logger.info(__name__, "Connected to database")
|
self._logger.info(__name__, "Connected to database")
|
||||||
|
1
src/gismo_data/migration/__init__.py
Normal file
1
src/gismo_data/migration/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# imports
|
57
src/gismo_data/migration/initial_migration.py
Normal file
57
src/gismo_data/migration/initial_migration.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
|
||||||
|
from gismo_data.abc.migration_abc import MigrationABC
|
||||||
|
from gismo_data.db_context import DBContext
|
||||||
|
|
||||||
|
|
||||||
|
class InitialMigration(MigrationABC):
|
||||||
|
|
||||||
|
def __init__(self, logger: LoggerABC, db: DBContext):
|
||||||
|
self._logger = logger
|
||||||
|
self._db = db
|
||||||
|
self._cursor = db.cursor
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
self._logger.debug(__name__, 'Running upgrade')
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `MigrationHistory` (
|
||||||
|
`MigrationId` VARCHAR(255),
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
PRIMARY KEY(`MigrationId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Servers` (
|
||||||
|
`ServerId` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`DiscordServerId` BIGINT NOT NULL,
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
PRIMARY KEY(`ServerId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Users` (
|
||||||
|
`UserId` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`DiscordId` BIGINT NOT NULL,
|
||||||
|
`XP` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`ServerId` BIGINT,
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
FOREIGN KEY (`ServerId`) REFERENCES Servers(`ServerId`),
|
||||||
|
PRIMARY KEY(`UserId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute('DROP TABLE `Servers`;')
|
||||||
|
self._cursor.execute('DROP TABLE `Users`;')
|
65
src/gismo_data/migration/migration_0_3.py
Normal file
65
src/gismo_data/migration/migration_0_3.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
|
||||||
|
from gismo_data.abc.migration_abc import MigrationABC
|
||||||
|
from gismo_data.db_context import DBContext
|
||||||
|
|
||||||
|
class Migration_0_3(MigrationABC):
|
||||||
|
|
||||||
|
def __init__(self, logger: LoggerABC, db: DBContext):
|
||||||
|
self._logger = logger
|
||||||
|
self._db = db
|
||||||
|
self._cursor = db.cursor
|
||||||
|
|
||||||
|
def upgrade(self):
|
||||||
|
self._logger.debug(__name__, 'Running upgrade')
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `Clients` (
|
||||||
|
`ClientId` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`DiscordClientId` BIGINT NOT NULL,
|
||||||
|
`SentMessageCount` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`ReceivedMessageCount` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`DeletedMessageCount` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`ReceivedCommandsCount` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`MovedUsersCount` BIGINT NOT NULL DEFAULT 0,
|
||||||
|
`ServerId` BIGINT,
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
FOREIGN KEY (`ServerId`) REFERENCES Servers(`ServerId`),
|
||||||
|
PRIMARY KEY(`ClientId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `KnownUsers` (
|
||||||
|
`KnownUserId` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`DiscordId` BIGINT NOT NULL,
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
PRIMARY KEY(`KnownUserId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cursor.execute(
|
||||||
|
str(f"""
|
||||||
|
CREATE TABLE IF NOT EXISTS `UserJoinedServers` (
|
||||||
|
`JoinId` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`UserId` BIGINT NOT NULL,
|
||||||
|
`JoinedOn` DATETIME(6) NOT NULL,
|
||||||
|
`LeavedOn` DATETIME(6),
|
||||||
|
`CreatedAt` DATETIME(6),
|
||||||
|
`LastModifiedAt` DATETIME(6),
|
||||||
|
FOREIGN KEY (`UserId`) REFERENCES Users(`UserId`),
|
||||||
|
PRIMARY KEY(`JoinId`)
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
|
def downgrade(self):
|
||||||
|
self._cursor.execute('DROP TABLE `Clients`;')
|
||||||
|
self._cursor.execute('DROP TABLE `KnownUsers`;')
|
||||||
|
self._cursor.execute('DROP TABLE `UserJoinedServers`;')
|
47
src/gismo_data/model/migration_history.py
Normal file
47
src/gismo_data/model/migration_history.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from cpl_core.database import TableABC
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationHistory(TableABC):
|
||||||
|
|
||||||
|
def __init__(self, id: str):
|
||||||
|
self._id = id
|
||||||
|
|
||||||
|
TableABC.__init__(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def migration_id(self) -> str:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_select_by_id_string(id: str) -> str:
|
||||||
|
return str(f"""
|
||||||
|
SELECT * FROM `MigrationHistory`
|
||||||
|
WHERE `MigrationId` = '{id}';
|
||||||
|
""")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def insert_string(self) -> str:
|
||||||
|
return str(f"""
|
||||||
|
INSERT INTO `MigrationHistory` (
|
||||||
|
`MigrationId`, `CreatedAt`, `LastModifiedAt`
|
||||||
|
) VALUES (
|
||||||
|
'{self._id}',
|
||||||
|
'{self._created_at}',
|
||||||
|
'{self._modified_at}'
|
||||||
|
);
|
||||||
|
""")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def udpate_string(self) -> str:
|
||||||
|
return str(f"""
|
||||||
|
UPDATE `MigrationHistory`
|
||||||
|
SET LastModifiedAt` = '{self._modified_at}'
|
||||||
|
WHERE `MigrationId` = '{self._id}';
|
||||||
|
""")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def delete_string(self) -> str:
|
||||||
|
return str(f"""
|
||||||
|
DELETE FROM `MigrationHistory`
|
||||||
|
WHERE `MigrationId` = '{self._id}';
|
||||||
|
""")
|
43
src/gismo_data/service/migration_service.py
Normal file
43
src/gismo_data/service/migration_service.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from cpl_core.database.context import DatabaseContextABC
|
||||||
|
from cpl_core.dependency_injection import ServiceProviderABC
|
||||||
|
from cpl_core.logging import LoggerABC
|
||||||
|
|
||||||
|
from gismo_data.abc.migration_abc import MigrationABC
|
||||||
|
from gismo_data.model.migration_history import MigrationHistory
|
||||||
|
|
||||||
|
|
||||||
|
class MigrationService:
|
||||||
|
|
||||||
|
def __init__(self, logger: LoggerABC, services: ServiceProviderABC, db: DatabaseContextABC):
|
||||||
|
self._logger = logger
|
||||||
|
self._services = services
|
||||||
|
|
||||||
|
self._db = db
|
||||||
|
self._cursor = db.cursor
|
||||||
|
|
||||||
|
self._migrations: list[MigrationABC] = MigrationABC.__subclasses__()
|
||||||
|
|
||||||
|
def migrate(self):
|
||||||
|
self._logger.info(__name__, f"Running Migrations")
|
||||||
|
for migration in self._migrations:
|
||||||
|
migration_id = migration.__name__
|
||||||
|
try:
|
||||||
|
# check if table exists
|
||||||
|
self._cursor.execute("SHOW TABLES LIKE 'MigrationHistory'")
|
||||||
|
result = self._cursor.fetchone()
|
||||||
|
if result:
|
||||||
|
# there is a table named "tableName"
|
||||||
|
self._logger.trace(__name__, f"Running SQL Command: {MigrationHistory.get_select_by_id_string(migration_id)}")
|
||||||
|
migration_from_db: MigrationHistory = self._db.select(MigrationHistory.get_select_by_id_string(migration_id))
|
||||||
|
self._logger.trace(__name__, migration_from_db)
|
||||||
|
if migration_from_db is not None and len(migration_from_db) > 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._logger.debug(__name__, f"Running Migration {migration}")
|
||||||
|
migration_as_service: MigrationABC = self._services.get_service(migration)
|
||||||
|
migration_as_service.upgrade()
|
||||||
|
self._cursor.execute(MigrationHistory(migration_id).insert_string)
|
||||||
|
self._db.save_changes()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.error(__name__, f'Cannot get migration with id {migration}', e)
|
Reference in New Issue
Block a user