modules/backend/Write-Persistence-Shared.ps1

param(
    [string]$ProjectName,
    [string]$OrmMode,
    [string]$DbProvider,
    [string]$OutputPath,
    [string[]]$Entities
)

. (Join-Path (Split-Path $MyInvocation.MyCommand.Path) "..\core\Utils.ps1")

$base = Join-Path $OutputPath "src\$ProjectName.Persistence"
function Write-File($rel, $con) { Write-CoreFile (Join-Path $base $rel) $con }
function T($template, $e = "") { 
    $res = $template.Replace("{P}", $ProjectName)
    if ($e) { $res = $res.Replace("{E}", $e) }
    return $res
}

# =====================================================================
# AppDbContext (EFCore ve Hybrid modlarda)
# =====================================================================
if ($OrmMode -eq "EFCore" -or $OrmMode -eq "Hybrid") {
    $dbSets = ""
    $fluent = ""
    foreach ($e in $Entities) {
        $pE = Get-Plural $e
        $dbSets += " public DbSet<$e> $pE => Set<$e>();`n"
        if ($e -eq "User") {
            # BCrypt hash of "Admin123!" with work factor 11
            $bcryptHash = '$2a$11$K5L4eU5vU9.KUjFp3q/WyOFq1JBk5NbMgFV2aSvZCjfTKzf6zSmKS'
            $fluent += " modelBuilder.Entity<User>(e => {
            e.HasKey(u => u.Id);
            e.Property(u => u.Username).HasMaxLength(100).IsRequired();
            e.Property(u => u.Email)
             .HasConversion(
                 email => email.Value,
                 value => new Email(value))
             .HasMaxLength(255)
             .IsRequired();
            e.HasQueryFilter(u => !u.IsDeleted);
            e.HasData(new { Id = 1, Username = `"admin`", Email = new Email(`"admin@example.com`"), PasswordHash = `"$bcryptHash`", Role = `"Admin`", IsActive = true, CreatedAt = new DateTime(2024,1,1,0,0,0,DateTimeKind.Utc), UpdatedAt = new DateTime(2024,1,1,0,0,0,DateTimeKind.Utc), IsDeleted = false });
        });`n"

        } else {
            $fluent += " modelBuilder.Entity<$e>(e => { e.HasKey(x => x.Id); e.HasQueryFilter(x => !x.IsDeleted); });`n"
        }
    }

    Write-File "Context\AppDbContext.cs" (T @"
using Microsoft.EntityFrameworkCore;
using {P}.Domain.Entities;
using {P}.Domain.ValueObjects;
 
namespace {P}.Persistence.Context;
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
$dbSets
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
$fluent
    }
}
"@
)
}

# =====================================================================
# ServiceRegistration
# =====================================================================
$registrations = ""
foreach ($e in $Entities) {
    $registrations += " services.AddScoped<I$e`Repository, $e`Repository>();`n"
}
$uowRegistration = if ($OrmMode -match "EFCore|Hybrid") { " services.AddScoped<IUnitOfWork, {P}.Persistence.UnitOfWork.UnitOfWork>();`n" } else { "" }

$efUsing = if ($OrmMode -ne "Dapper") { "`nusing Microsoft.EntityFrameworkCore;" } else { "" }
$usings = switch ($DbProvider) {
    "Postgres" { "using Npgsql;$efUsing" }
    default    { "using Microsoft.Data.SqlClient;$efUsing" }
}

$connRegistration = switch ($DbProvider) {
    "Postgres" { 
        $r = if ($OrmMode -ne "Dapper") { " services.AddDbContext<AppDbContext>(opt => opt.UseNpgsql(connStr));`n" } else { "" }
        $r += if ($OrmMode -ne "EFCore") { " services.AddScoped<IDbConnection>(_ => new NpgsqlConnection(connStr));" } else { "" }
        $r
    }
    default {
        $r = if ($OrmMode -ne "Dapper") { " services.AddDbContext<AppDbContext>(opt => opt.UseSqlServer(connStr));`n" } else { "" }
        $r += if ($OrmMode -ne "EFCore") { " services.AddScoped<IDbConnection>(_ => new SqlConnection(connStr));" } else { "" }
        $r
    }
}

$dapperTypeHandlerReg = ""
$dapperTypeHandlerDef = ""
if ($OrmMode -ne "EFCore") {
    $dapperTypeHandlerReg = " Dapper.SqlMapper.AddTypeHandler(new EmailTypeHandler());`n"
    $dapperTypeHandlerDef = T @"
 
public class EmailTypeHandler : Dapper.SqlMapper.TypeHandler<{P}.Domain.ValueObjects.Email>
{
    public override void SetValue(System.Data.IDbDataParameter parameter, {P}.Domain.ValueObjects.Email? value)
    {
        parameter.Value = value?.Value ?? (object)System.DBNull.Value;
    }
 
    public override {P}.Domain.ValueObjects.Email Parse(object value)
    {
        return new {P}.Domain.ValueObjects.Email(value.ToString() ?? string.Empty);
    }
}
"@

}

Write-File "ServiceRegistration\PersistenceServiceRegistration.cs" (T @"
using System.Data;
$usings
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using {P}.Domain.Interfaces;
using {P}.Persistence.Repositories;
$(if ($OrmMode -ne "Dapper") { "using {P}.Persistence.Context;" })
 
namespace {P}.Persistence.ServiceRegistration;
public static class PersistenceServiceRegistration {
    public static IServiceCollection AddPersistenceServices(this IServiceCollection services, IConfiguration configuration) {
$dapperTypeHandlerReg var connStr = configuration.GetConnectionString("DefaultConnection");
$connRegistration
$uowRegistration
$registrations return services;
    }
}
$dapperTypeHandlerDef
"@
)