using MycroForge.CLI.CodeGen; namespace MycroForge.CLI.Features; public sealed class Db : IFeature { #region Defaults private static readonly string[] Settings = [ "class DbSettings:", "\tdef get_connectionstring() -> str:", "\t\tconnectionstring = \"mysql+asyncmy://root:password@localhost:%db_port%/%app_name%\"", "\t\treturn connectionstring", ]; private static readonly string[] AsyncSession = [ "from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine, AsyncSession", $"from {FeatureName}.settings import DbSettings", "", "async_engine: AsyncEngine = create_async_engine(DbSettings.get_connectionstring())", "", "def async_session() -> AsyncSession:", "\treturn AsyncSession(async_engine, expire_on_commit=False)" ]; private static readonly string[] EntityBase = [ "from sqlalchemy.orm import DeclarativeBase", "", "class EntityBase(DeclarativeBase):", "\tpass" ]; private static readonly string[] DockerCompose = [ "version: '3.8'", "# Access the database UI at http://localhost:${DB_PORT}.", "# Login: username = root & password = password", "", "services:", " %app_name%_mariadb:", " image: 'mariadb:10.4'", " container_name: '%app_name%_mariadb'", " networks:", " - default", " ports:", " - '${DB_PORT}:3306'", " environment:", " MYSQL_ROOT_PASSWORD: 'password'", " MYSQL_USER: 'root'", " MYSQL_PASSWORD: 'password'", " MYSQL_DATABASE: '%app_name%'", " volumes:", " - '%app_name%_mariadb:/var/lib/mysql'", "", " %app_name%_phpmyadmin:", " image: phpmyadmin/phpmyadmin", " container_name: %app_name%_phpmyadmin", " ports:", " - '${PMA_PORT}:80'", " networks:", " - default", " environment:", " PMA_HOST: %app_name%_mariadb", " PMA_PORT: 3306", " PMA_ARBITRARY: 1", " links:", " - %app_name%_mariadb", "", "volumes:", " %app_name%_mariadb:\n", ]; #endregion public const string FeatureName = "db"; public string Name => FeatureName; public async Task ExecuteAsync(ProjectContext context) { var config = await context.LoadConfig(); config.Db = new() { DbPort = 5050, PmaPort = 5051 }; await context.SaveConfig(config); var appName = context.AppName; await context.Bash( "source .venv/bin/activate", "python3 -m pip install asyncmy sqlalchemy alembic", "python3 -m pip freeze > requirements.txt", $"alembic init -t async {FeatureName}" ); var env = await context.ReadFile($"{FeatureName}/env.py"); env = new DbEnvInitializer(env).Rewrite(); await context.WriteFile($"{FeatureName}/env.py", env); var settings = string.Join('\n', Settings) .Replace("%app_name%", appName) .Replace("%db_port%", config.Db.DbPort.ToString()) ; await context.CreateFile($"{FeatureName}/settings.py", settings); await context.CreateFile($"{FeatureName}/engine/async_session.py", AsyncSession); await context.CreateFile($"{FeatureName}/entities/entity_base.py", EntityBase); var dockerCompose = string.Join('\n', DockerCompose).Replace("%app_name%", appName); await context.CreateFile($"{FeatureName}.docker-compose.yml", dockerCompose); } }