Implemented many to many relations

This commit is contained in:
mdnapo 2024-05-18 15:57:15 +02:00
parent d59dedc106
commit 3418f15103
2 changed files with 76 additions and 47 deletions

View File

@ -4,6 +4,23 @@ namespace MycroForge.CLI.CodeGen;
public partial class EntityLinker public partial class EntityLinker
{ {
#region AssociationTable
private static readonly string[] AssociationTable =
[
"from sqlalchemy import Column, ForeignKey, Table",
"from db.entities.entity_base import EntityBase",
"",
"%left_entity%_%right_entity%_mapping = Table(",
"\t\"%left_entity%_%right_entity%_mapping\",",
"\tEntityBase.metadata,",
"\tColumn(\"%left_entity%_id\", ForeignKey(\"%left_table%.id\"), primary_key=True),",
"\tColumn(\"%right_entity%_id\", ForeignKey(\"%right_table%.id\"), primary_key=True),",
")"
];
#endregion
private readonly ProjectContext _context; private readonly ProjectContext _context;
private readonly string _left; private readonly string _left;
private readonly string _right; private readonly string _right;
@ -21,12 +38,12 @@ public partial class EntityLinker
var right = await LoadEntity(_right); var right = await LoadEntity(_right);
left.AppendColumn( left.AppendColumn(
$"\t{right.FieldName}: Mapped[\"{right.ClassName}\"] = relationship(back_populates=\"{left.FieldName}\")" $"\t{right.FieldName}: Mapped[\"{right.ClassName.Pascalize()}\"] = relationship(back_populates=\"{left.FieldName}\")"
); );
right.AppendColumns([ right.AppendColumns([
$"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))", $"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))",
$"\t{left.FieldName}: Mapped[\"{left.ClassName}\"] = relationship(back_populates=\"{right.FieldName}\")" $"\t{left.FieldName}: Mapped[\"{left.ClassName.Pascalize()}\"] = relationship(back_populates=\"{right.FieldName}\")"
]); ]);
await _context.WriteFile(left.Path, left.Rewrite()); await _context.WriteFile(left.Path, left.Rewrite());
@ -39,11 +56,12 @@ public partial class EntityLinker
var right = await LoadEntity(_right); var right = await LoadEntity(_right);
left.Import(from: "typing", import: "List"); left.Import(from: "typing", import: "List");
left.AppendColumn($"\t{right.FieldName.Pluralize()}: Mapped[List[\"{right.ClassName}\"]] = relationship()"); left.AppendColumn(
$"\t{right.FieldName.Pluralize()}: Mapped[List[\"{right.ClassName.Pascalize()}\"]] = relationship()");
right.AppendColumns([ right.AppendColumns([
$"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))", $"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))",
$"\t{left.FieldName}: Mapped[\"{left.ClassName}\"] = relationship(back_populates=\"{right.FieldName}\")" $"\t{left.FieldName}: Mapped[\"{left.ClassName.Pascalize()}\"] = relationship(back_populates=\"{right.FieldName}\")"
]); ]);
await _context.WriteFile(left.Path, left.Rewrite()); await _context.WriteFile(left.Path, left.Rewrite());
@ -58,13 +76,13 @@ public partial class EntityLinker
left.Import(from: "typing", import: "Optional"); left.Import(from: "typing", import: "Optional");
left.AppendColumns([ left.AppendColumns([
$"\t{right.FieldName}_id: Mapped[Optional[int]] = mapped_column(ForeignKey(\"{right.TableName}.id\"))", $"\t{right.FieldName}_id: Mapped[Optional[int]] = mapped_column(ForeignKey(\"{right.TableName}.id\"))",
$"\t{right.FieldName}: Mapped[\"{right.ClassName}\"] = relationship(back_populates=\"{left.FieldName.Pluralize()}\")" $"\t{right.FieldName}: Mapped[\"{right.ClassName.Pascalize()}\"] = relationship(back_populates=\"{left.FieldName.Pluralize()}\")"
]); ]);
left.Import(from: "typing", import: "List"); left.Import(from: "typing", import: "List");
right.AppendColumns([ right.AppendColumns([
$"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))", $"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))",
$"\t{left.FieldName.Pluralize()}: Mapped[List[\"{left.ClassName}\"]] = relationship(back_populates=\"{right.FieldName}\")" $"\t{left.FieldName.Pluralize()}: Mapped[List[\"{left.ClassName.Pascalize()}\"]] = relationship(back_populates=\"{right.FieldName}\")"
]); ]);
await _context.WriteFile(left.Path, left.Rewrite()); await _context.WriteFile(left.Path, left.Rewrite());
@ -73,50 +91,60 @@ public partial class EntityLinker
public async Task ManyToMany() public async Task ManyToMany()
{ {
// var left = await LoadEntity(_left); var left = await LoadEntity(_left);
// var right = await LoadEntity(_right); var right = await LoadEntity(_right);
//
// left.AppendImportIfNotExists( var associationTable = string.Join('\n', AssociationTable);
// $"db.entities.{right.FieldName}", associationTable = associationTable
// $"{right.ClassName}", .Replace("%left_entity%", left.ClassName.Underscore().ToLower())
// $"from db.entities.{right.FieldName} import {right.ClassName}" .Replace("%right_entity%", right.ClassName.Underscore().ToLower())
// ); .Replace("%left_table%", left.TableName)
// left.AppendImportIfNotExists( .Replace("%right_table%", right.TableName);
// "typing", var associationTablePath =
// "Optional", $"{Features.Db.FeatureName}/entities/associations/{left.TableName.Singularize()}_{right.TableName.Singularize()}_mapping.py";
// "from typing import Optional"
// ); await _context.CreateFile(associationTablePath, associationTable);
// left.AppendColumn([
// $"\t{right.FieldName}_id: Mapped[Optional[int]] = mapped_column(ForeignKey(\"{right.TableName}.id\"))", var associationTableImport = associationTablePath
// $"\t{right.FieldName}: Mapped[\"{right.ClassName}\"] = relationship(back_populates=\"{left.FieldName.Pluralize()}\")\n" .Replace(".py", "")
// ]); .Replace('/', '.')
// .Replace('\\', '.')
// right.AppendImportIfNotExists( .Split('.')
// $"db.entities.{left.FieldName}", ;
// $"{left.ClassName}",
// $"from db.entities.{left.FieldName} import {left.ClassName}" var associationTableImportPath = string.Join('.', associationTableImport[..^1]);
// ); var associationTableImportName = associationTableImport[^1];
// left.AppendImportIfNotExists(
// "typing", left.Import(from: string.Join('.', associationTableImportPath), import: associationTableImportName);
// "List", left.Import(from: "typing", import: "List");
// "from typing import List" right.Import(from: string.Join('.', associationTableImportPath), import: associationTableImportName);
// ); right.Import(from: "typing", import: "List");
// right.AppendColumn([
// $"\t{left.FieldName}_id: Mapped[int] = mapped_column(ForeignKey(\"{left.TableName}.id\"))", left.AppendColumns([
// $"\t{left.FieldName.Pluralize()}: Mapped[List[\"{left.ClassName}\"]] = relationship(back_populates=\"{right.FieldName}\")\n" $"\t{right.FieldName.Pluralize()}: Mapped[List[\"{right.ClassName.Pascalize()}\"]] = relationship(back_populates=\"{left.FieldName.Pluralize()}\", secondary={associationTableImportName})"
// ]); ]);
//
// await _context.WriteFile(left.Path, left.Rewrite()); right.AppendColumns([
// await _context.WriteFile(right.Path, right.Rewrite()); $"\t{left.FieldName.Pluralize()}: Mapped[List[\"{left.ClassName.Pascalize()}\"]] = relationship(back_populates=\"{right.FieldName.Pluralize()}\", secondary={associationTableImportName})"
]);
await _context.WriteFile(left.Path, left.Rewrite());
await _context.WriteFile(right.Path, right.Rewrite());
} }
private async Task<EntityModel> LoadEntity(string name) private async Task<EntityModel> LoadEntity(string name)
{ {
var path = GetEntityPath(name); var path = $"{Features.Db.FeatureName}/entities";
if (name.Split(':').Select(s => s.Trim()).ToArray() is { Length: 2 } fullName)
{
path = Path.Join(path, fullName[0]);
name = fullName[1];
}
path = Path.Join(path, $"{name.Underscore().ToLower()}.py");
var entity = new EntityModel(name, path, await _context.ReadFile(path)); var entity = new EntityModel(name, path, await _context.ReadFile(path));
entity.Initialize(); entity.Initialize();
return entity; return entity;
} }
private string GetEntityPath(string name) => $"{Features.Db.FeatureName}/entities/{name.Underscore().ToLower()}.py";
} }

View File

@ -8,11 +8,12 @@ public sealed class Db : IFeature
private static readonly string[] Settings = private static readonly string[] Settings =
[ [
"connectionstring = \"mysql+asyncmy://root:root@localhost:3306/example\"",
"",
"class DbSettings:", "class DbSettings:",
"\tdef get_connectionstring() -> str:", "\tdef get_connectionstring() -> str:",
"\t\treturn connectionstring" "\t\t# Example",
"\t\t# connectionstring = \"mysql+asyncmy://root:root@localhost:3306/your_database\"",
"\t\t# return connectionstring",
"\t\traise Exception(\"DbSettings.get_connectionstring was not implemented.\")",
]; ];
private static readonly string[] AsyncSession = private static readonly string[] AsyncSession =