A-0.3 - Basismodul #36
@ -3,8 +3,10 @@ from cpl_core.configuration import ConfigurationABC
|
||||
from cpl_core.console import Console
|
||||
from cpl_core.dependency_injection import ServiceProviderABC
|
||||
from cpl_core.logging import LoggerABC
|
||||
|
||||
from gismo_core.abc.bot_service_abc import BotServiceABC
|
||||
from gismo_core.service.bot_service import BotService
|
||||
from gismo_data.service.migration_service import MigrationService
|
||||
|
||||
|
||||
class Gismo(ApplicationABC):
|
||||
@ -14,12 +16,14 @@ class Gismo(ApplicationABC):
|
||||
|
||||
self._bot: BotService = services.get_service(BotServiceABC)
|
||||
self._logger: LoggerABC = services.get_service(LoggerABC)
|
||||
self._migrations: MigrationService = services.get_service(MigrationService)
|
||||
|
||||
async def configure(self):
|
||||
pass
|
||||
|
||||
async def main(self):
|
||||
try:
|
||||
self._migrations.migrate()
|
||||
self._logger.trace(__name__, f'Try to start {BotService}')
|
||||
await self._bot.start_async()
|
||||
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.message_service import MessageService
|
||||
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.user_repository_abc import UserRepositoryABC
|
||||
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 (
|
||||
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 \
|
||||
ServerRepositoryService
|
||||
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))
|
||||
|
||||
# modules
|
||||
services.add_singleton(ModuleServiceABC, ModuleService)
|
||||
services.add_singleton(BotServiceABC, BotService)
|
||||
services.add_transient(MessageServiceABC, MessageService)
|
||||
|
||||
# services
|
||||
services.add_transient(MigrationService)
|
||||
|
||||
# data services
|
||||
services.add_transient(ServerRepositoryABC, ServerRepositoryService)
|
||||
services.add_transient(UserRepositoryABC, UserRepositoryService)
|
||||
services.add_transient(ClientRepositoryABC, ClientRepositoryService)
|
||||
services.add_transient(KnownUserRepositoryABC, KnownUserRepositoryService)
|
||||
|
||||
|
||||
# modules
|
||||
services.add_transient(ModuleABC, Database)
|
||||
services.add_transient(ModuleABC, Base)
|
||||
services.add_transient(ModuleABC, BootLog)
|
||||
|
||||
# migrations
|
||||
services.add_transient(MigrationABC, InitialMigration)
|
||||
services.add_transient(MigrationABC, Migration_0_3)
|
||||
|
||||
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:
|
||||
self._logger.debug(__name__, "Connecting to database")
|
||||
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._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