141 lines
5.7 KiB
C#
141 lines
5.7 KiB
C#
using Humanizer;
|
|
using MycroForge.CLI.Commands;
|
|
using MycroForge.CLI.Extensions;
|
|
using MycroForge.Core;
|
|
|
|
namespace MycroForge.CLI.CodeGen;
|
|
|
|
public class CrudRouterGenerator
|
|
{
|
|
#region Templates
|
|
|
|
private static readonly string[] Template =
|
|
[
|
|
"from typing import Annotated",
|
|
"from fastapi import APIRouter, Depends",
|
|
"from fastapi.responses import JSONResponse, Response",
|
|
"from fastapi.encoders import jsonable_encoder",
|
|
"from %service_import_path% import %service_class_name%",
|
|
"from %create_entity_request_import_path% import %create_entity_request_class_name%",
|
|
"from %update_entity_request_import_path% import %update_entity_request_class_name%",
|
|
"",
|
|
"router = APIRouter()",
|
|
"",
|
|
"@router.get(\"/\")",
|
|
"async def list(",
|
|
"\tservice: Annotated[%service_class_name%, Depends()]",
|
|
"):",
|
|
"\ttry:",
|
|
"\t\tresult = await service.list()",
|
|
"\t\treturn JSONResponse(status_code=200, content=jsonable_encoder(result))",
|
|
"\texcept Exception as ex:",
|
|
"\t\tprint(str(ex))",
|
|
"\t\treturn JSONResponse(status_code=500, content=str(ex))",
|
|
"",
|
|
"@router.get(\"/{id}\")",
|
|
"async def get_by_id(",
|
|
"\tid: int,",
|
|
"\tservice: Annotated[%service_class_name%, Depends()]",
|
|
"):",
|
|
"\ttry:",
|
|
"\t\tresult = await service.get_by_id(id)",
|
|
"\t\treturn JSONResponse(status_code=200 if result is not None else 404, content=jsonable_encoder(result))",
|
|
"\texcept Exception as ex:",
|
|
"\t\tprint(str(ex))",
|
|
"\t\treturn JSONResponse(status_code=500, content=str(ex))",
|
|
"",
|
|
"@router.post(\"/\")",
|
|
"async def create(",
|
|
"\trequest: Create%entity_class_name%Request,",
|
|
"\tservice: Annotated[%service_class_name%, Depends()]",
|
|
"):",
|
|
"\ttry:",
|
|
"\t\tawait service.create(request.model_dump())",
|
|
"\t\treturn JSONResponse(status_code=201, content=None)",
|
|
"\texcept Exception as ex:",
|
|
"\t\tprint(str(ex))",
|
|
"\t\treturn JSONResponse(status_code=500, content=str(ex))",
|
|
"",
|
|
"@router.patch(\"/{id}\")",
|
|
"async def update(",
|
|
"\tid: int,",
|
|
"\trequest: Update%entity_class_name%Request,",
|
|
"\tservice: Annotated[%service_class_name%, Depends()]",
|
|
"):",
|
|
"\ttry:",
|
|
"\t\tupdated = await service.update(id, request.model_dump(exclude_unset=True))",
|
|
"\t\treturn Response(status_code=204 if updated else 404)",
|
|
"\texcept Exception as ex:",
|
|
"\t\tprint(str(ex))",
|
|
"\t\treturn JSONResponse(status_code=500, content=str(ex))",
|
|
"",
|
|
"@router.delete(\"/{id}\")",
|
|
"async def delete(",
|
|
"\tid: int,",
|
|
"\tservice: Annotated[%service_class_name%, Depends()]",
|
|
"):",
|
|
"\ttry:",
|
|
"\t\tdeleted = await service.delete(id)",
|
|
"\t\treturn JSONResponse(status_code=204 if deleted else 404, content=None)",
|
|
"\texcept Exception as ex:",
|
|
"\t\tprint(str(ex))",
|
|
"\t\treturn JSONResponse(status_code=500, content=str(ex))",
|
|
];
|
|
|
|
#endregion
|
|
|
|
private readonly ProjectContext _context;
|
|
|
|
public CrudRouterGenerator(ProjectContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task Generate(FullyQualifiedName fqn)
|
|
{
|
|
var serviceClassName = $"{fqn.PascalizedName}Service";
|
|
var entityRoutePrefix = fqn.PascalizedName.Kebaberize().Pluralize().ToLower();
|
|
|
|
var serviceFilePath = Path.Join(
|
|
Features.Api.FeatureName, "services", fqn.Namespace, $"{fqn.SnakeCasedName}_service"
|
|
);
|
|
|
|
var serviceImportPath = serviceFilePath.SlashesToDots();
|
|
var routerFolderPath = Path.Join(Features.Api.FeatureName, "routers", fqn.Namespace);
|
|
var routerFilePath = Path.Join(routerFolderPath, $"{fqn.SnakeCasedName}");
|
|
var routerImportPath = routerFolderPath.SlashesToDots();
|
|
var requestsFolderPath = Path.Join(Features.Api.FeatureName, "requests", fqn.Namespace);
|
|
|
|
var createRequestImportPath = Path.Join(requestsFolderPath, $"Create{fqn.PascalizedName}Request")
|
|
.SlashesToDots()
|
|
.Underscore()
|
|
.ToLower();
|
|
var createRequestClassName = $"Create{fqn.PascalizedName}Request";
|
|
|
|
var updateRequestImportPath = Path.Join(requestsFolderPath, $"Update{fqn.PascalizedName}Request")
|
|
.SlashesToDots()
|
|
.Underscore()
|
|
.ToLower();
|
|
var updateRequestClassName = $"Update{fqn.PascalizedName}Request";
|
|
|
|
var router = string.Join("\n", Template)
|
|
.Replace("%service_import_path%", serviceImportPath)
|
|
.Replace("%entity_class_name%", fqn.PascalizedName)
|
|
.Replace("%service_class_name%", serviceClassName)
|
|
.Replace("%create_entity_request_import_path%", createRequestImportPath)
|
|
.Replace("%create_entity_request_class_name%", createRequestClassName)
|
|
.Replace("%update_entity_request_import_path%", updateRequestImportPath)
|
|
.Replace("%update_entity_request_class_name%", updateRequestClassName);
|
|
|
|
await _context.CreateFile($"{routerFilePath}.py", router);
|
|
|
|
var main = await _context.ReadFile("main.py");
|
|
|
|
main = new MainModifier(main).Initialize()
|
|
.Import(from: routerImportPath, import: fqn.SnakeCasedName)
|
|
.IncludeRouter(prefix: entityRoutePrefix, router: fqn.SnakeCasedName)
|
|
.Rewrite();
|
|
|
|
await _context.WriteFile("main.py", main);
|
|
}
|
|
} |