Added CRUD generation and a bunch of other stuff
This commit is contained in:
45
MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs
Normal file
45
MycroForge.CLI/Commands/MycroForge.Api.Generate.Crud.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.CommandLine;
|
||||
using MycroForge.CLI.CodeGen;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
public partial class Api
|
||||
{
|
||||
public partial class Generate
|
||||
{
|
||||
public class Crud : Command, ISubCommandOf<Generate>
|
||||
{
|
||||
private static readonly Argument<string> EntityArgument =
|
||||
new(name: "entity", description: "The entity to target");
|
||||
|
||||
private readonly ProjectContext _context;
|
||||
|
||||
public Crud(ProjectContext context)
|
||||
: base("crud", "Generated CRUD functionality for an entity")
|
||||
{
|
||||
_context = context;
|
||||
AddArgument(EntityArgument);
|
||||
this.SetHandler(ExecuteAsync, EntityArgument);
|
||||
}
|
||||
|
||||
private async Task ExecuteAsync(string entity)
|
||||
{
|
||||
var path = string.Empty;
|
||||
if (entity.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName)
|
||||
{
|
||||
path = fullName[0];
|
||||
entity = fullName[1];
|
||||
}
|
||||
|
||||
await new CrudServiceGenerator(_context).Generate(path, entity);
|
||||
await new RequestClassGenerator(_context).Generate(path, entity, RequestClassGenerator.Type.Create);
|
||||
await new RequestClassGenerator(_context).Generate(path, entity, RequestClassGenerator.Type.Update);
|
||||
await new CrudRouterGenerator(_context).Generate(path, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.CommandLine;
|
||||
using Humanizer;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
using MycroForge.CLI.Extensions;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
@@ -40,16 +41,30 @@ public partial class MycroForge
|
||||
|
||||
private async Task ExecuteAsync(string name)
|
||||
{
|
||||
_context.AssertDirectoryExists($"{Features.Api.FeatureName}/routers");
|
||||
var folderPath = $"{Features.Api.FeatureName}/routers";
|
||||
|
||||
var moduleName = name.Underscore();
|
||||
await _context.CreateFile($"{Features.Api.FeatureName}/routers/{moduleName}.py", Template);
|
||||
_context.AssertDirectoryExists(folderPath);
|
||||
|
||||
if (name.FullyQualifiedName() is { Length: 2 } fullName)
|
||||
{
|
||||
folderPath = Path.Join(folderPath, fullName[0]);
|
||||
name = fullName[1];
|
||||
}
|
||||
|
||||
var moduleImportPath = folderPath.Replace('\\', '.').Replace('/', '.');
|
||||
var moduleName = name.Underscore().ToLower();
|
||||
var fileName = $"{moduleName}.py";
|
||||
var filePath = Path.Join(folderPath, fileName);
|
||||
|
||||
await _context.CreateFile(filePath, Template);
|
||||
|
||||
var main = await _context.ReadFile("main.py");
|
||||
|
||||
main += string.Join('\n',
|
||||
$"\n\nfrom {Features.Api.FeatureName}.routers import {moduleName}",
|
||||
$"\n\nfrom {moduleImportPath} import {moduleName}",
|
||||
$"app.include_router(prefix=\"/{name.Kebaberize()}\", router={moduleName}.router)"
|
||||
);
|
||||
|
||||
await _context.WriteFile("main.py", main);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.CommandLine;
|
||||
using Humanizer;
|
||||
using MycroForge.CLI.CodeGen;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
using MycroForge.CLI.Extensions;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
@@ -19,7 +20,7 @@ public partial class MycroForge
|
||||
[
|
||||
"from sqlalchemy import %type_imports%",
|
||||
"from sqlalchemy.orm import Mapped, mapped_column",
|
||||
"from db.entities.entity_base import EntityBase",
|
||||
$"from {Features.Db.FeatureName}.entities.entity_base import EntityBase",
|
||||
"",
|
||||
"class %class_name%(EntityBase):",
|
||||
"\t__tablename__ = \"%table_name%\"",
|
||||
@@ -67,12 +68,13 @@ public partial class MycroForge
|
||||
|
||||
private async Task ExecuteAsync(string name, IEnumerable<string> columns)
|
||||
{
|
||||
_context.AssertDirectoryExists(Features.Db.FeatureName);
|
||||
var folderPath = $"{Features.Db.FeatureName}/entities";
|
||||
|
||||
var path = string.Empty;
|
||||
if (name.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName)
|
||||
_context.AssertDirectoryExists(Features.Db.FeatureName);
|
||||
|
||||
if (name.FullyQualifiedName() is { Length: 2 } fullName)
|
||||
{
|
||||
path = fullName[0];
|
||||
folderPath = Path.Join(folderPath, fullName[0]);
|
||||
name = fullName[1];
|
||||
}
|
||||
|
||||
@@ -87,12 +89,12 @@ public partial class MycroForge
|
||||
code = code.Replace("%table_name%", name.Underscore().ToLower().Pluralize());
|
||||
code = code.Replace("%column_definitions%", columnDefinitions);
|
||||
|
||||
var folderPath = Path.Join($"{Features.Db.FeatureName}/entities", path);
|
||||
var fileName = $"{name.ToLower()}.py";
|
||||
// var folderPath = Path.Join(, path);
|
||||
var fileName = $"{name.Underscore().ToLower()}.py";
|
||||
var filePath = Path.Join(folderPath, fileName);
|
||||
await _context.CreateFile(filePath, code);
|
||||
|
||||
var importPathParts = new[] { path, fileName.Replace(".py", "") }
|
||||
var importPathParts = new[] { folderPath, fileName.Replace(".py", "") }
|
||||
.Where(s => !string.IsNullOrEmpty(s));
|
||||
|
||||
var importPath = string.Join('.', importPathParts)
|
||||
|
||||
@@ -32,7 +32,6 @@ public partial class MycroForge
|
||||
this.SetHandler(ExecuteAsync, LeftArgument, ToOneOption, ToManyOption);
|
||||
}
|
||||
|
||||
|
||||
private async Task ExecuteAsync(string left, string? toOneOption, string? toManyOption)
|
||||
{
|
||||
if (toOneOption is not null && toManyOption is not null)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.CommandLine;
|
||||
using Humanizer;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
using MycroForge.CLI.Extensions;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
@@ -13,36 +14,33 @@ public partial class MycroForge
|
||||
private static readonly Argument<string> NameArgument =
|
||||
new(name: "name", description: "The name of the service");
|
||||
|
||||
private static readonly Option<string> PathOption =
|
||||
new(name: "--path", description: "The folder path of the service") { IsRequired = true };
|
||||
|
||||
private static readonly Option<bool> WithSessionOption =
|
||||
new(name: "--with-session", description: "Create a service that uses database sessions");
|
||||
|
||||
|
||||
private static readonly string[] DefaultTemplate =
|
||||
[
|
||||
"class %class_name%:",
|
||||
"",
|
||||
"\tdef do_stuff(self, stuff: str) -> str:",
|
||||
"\t\treturn f\"Hey, I'm doing stuff!\""
|
||||
"\tdef hello(self, name: str) -> str:",
|
||||
"\t\treturn f\"Hello, {str}!\""
|
||||
];
|
||||
|
||||
private static readonly string[] WithSessionTemplate =
|
||||
[
|
||||
"from db.engine.async_session import async_session",
|
||||
"from typing import List",
|
||||
"from sqlalchemy import select",
|
||||
"# from db.entities.some_entity import SomeEntity",
|
||||
$"from {Features.Db.FeatureName}.engine.async_session import async_session",
|
||||
$"# from {Features.Db.FeatureName}.entities.entity import Entity",
|
||||
"",
|
||||
"class %class_name%Service:",
|
||||
"class %class_name%:",
|
||||
"",
|
||||
"\tasync def do_stuff(self, stuff: str) -> str:",
|
||||
"\tasync def list(self, value: str) -> List[Entity]:",
|
||||
"\t\tasync with async_session() as session:",
|
||||
"\t\t\t# stmt = select(User).where(SomeEntity.value == \"some_value\")",
|
||||
"\t\t\t# stmt = select(User).where(Entity.value == value)",
|
||||
"\t\t\t# results = (await session.scalars(stmt)).all()",
|
||||
"\t\t\t# print(len(results))",
|
||||
"\t\t\t# return results",
|
||||
"\t\t\tpass",
|
||||
"\t\treturn f\"Hey, I'm doing stuff!\""
|
||||
"\t\treturn []"
|
||||
];
|
||||
|
||||
private readonly ProjectContext _context;
|
||||
@@ -52,26 +50,25 @@ public partial class MycroForge
|
||||
_context = context;
|
||||
AddAlias("s");
|
||||
AddArgument(NameArgument);
|
||||
AddOption(PathOption);
|
||||
AddOption(WithSessionOption);
|
||||
this.SetHandler(ExecuteAsync, NameArgument, PathOption, WithSessionOption);
|
||||
this.SetHandler(ExecuteAsync, NameArgument, WithSessionOption);
|
||||
}
|
||||
|
||||
private async Task ExecuteAsync(string name, string? path, bool withSession)
|
||||
private async Task ExecuteAsync(string name, bool withSession)
|
||||
{
|
||||
var folderPath = "services";
|
||||
|
||||
if (!string.IsNullOrEmpty(path) && !path.Equals("."))
|
||||
var folderPath = string.Empty;
|
||||
|
||||
if (name.FullyQualifiedName() is { Length: 2} fullName)
|
||||
{
|
||||
folderPath = Path.Join(_context.RootDirectory, path);
|
||||
Directory.CreateDirectory(folderPath);
|
||||
folderPath = Path.Join(folderPath, fullName[0]);
|
||||
name = fullName[1];
|
||||
}
|
||||
|
||||
var filePath = Path.Join(folderPath, $"{name.Underscore().ToLower()}.py");
|
||||
var className = Path.GetFileName(name).Pascalize();
|
||||
var code = string.Join('\n', withSession ? WithSessionTemplate : DefaultTemplate)
|
||||
.Replace("%class_name%", className);
|
||||
|
||||
var filePath = Path.Join(folderPath, $"{name.Underscore().ToLower()}_service.py");
|
||||
await _context.CreateFile(filePath, code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.CommandLine;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Scripting.Utils;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
32
MycroForge.CLI/Commands/MycroForge.Script.List.cs
Normal file
32
MycroForge.CLI/Commands/MycroForge.Script.List.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.CommandLine;
|
||||
using MycroForge.CLI.Commands.Interfaces;
|
||||
|
||||
namespace MycroForge.CLI.Commands;
|
||||
|
||||
public partial class MycroForge
|
||||
{
|
||||
public partial class Script
|
||||
{
|
||||
public class List : Command, ISubCommandOf<Script>
|
||||
{
|
||||
public List() : base("list", "Show available scripts")
|
||||
{
|
||||
this.SetHandler(Execute);
|
||||
}
|
||||
|
||||
private void Execute()
|
||||
{
|
||||
var folder = Path.Join(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".m4g"
|
||||
);
|
||||
|
||||
var files = Directory.GetFiles(folder)
|
||||
.Select(Path.GetFileName)
|
||||
.Select(p => p.Replace(".py", ""));
|
||||
|
||||
foreach (var file in files)
|
||||
Console.WriteLine(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,12 @@ public partial class MycroForge
|
||||
{
|
||||
public partial class Script : Command, ISubCommandOf<MycroForge>
|
||||
{
|
||||
public Script(IEnumerable<ISubCommandOf<Script>> subCommands) :
|
||||
public Script(IEnumerable<ISubCommandOf<Script>> commands) :
|
||||
base("script", "Script related commands")
|
||||
{
|
||||
AddAlias("s");
|
||||
foreach (var subCommandOf in subCommands.Cast<Command>())
|
||||
AddCommand(subCommandOf);
|
||||
foreach (var command in commands.Cast<Command>())
|
||||
AddCommand(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user