modules/backend/Write-Persistence-Hybrid.ps1

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

if ($OrmMode -ne "Hybrid") { return }

. (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
}

function Get-PagedSql {
    param($table, $cols)
    switch ($DbProvider) {
        "Postgres" { "SELECT $cols FROM $table WHERE IsDeleted=@IsDeleted ORDER BY Id LIMIT @Size OFFSET @Offset" }
        default    { "SELECT $cols FROM $table WHERE IsDeleted=@IsDeleted ORDER BY Id OFFSET @Offset ROWS FETCH NEXT @Size ROWS ONLY" }
    }
}

foreach ($e in $Entities) {
    $pE = Get-Plural $e
    if ($e -eq "User") {
        # UserRepository in Hybrid Mode: Write -> EF Core, Read -> Dapper
        Write-File "Repositories\UserRepository.cs" (T @"
using System.Data;
using Dapper;
using {P}.Domain.Entities;
using {P}.Domain.Interfaces;
using {P}.Persistence.Context;
 
namespace {P}.Persistence.Repositories;
 
public class UserRepository : IUserRepository
{
    private readonly AppDbContext _ctx;
    private readonly IDbConnection _conn;
 
    public UserRepository(AppDbContext ctx, IDbConnection conn)
    {
        _ctx = ctx;
        _conn = conn;
    }
 
    public async Task<User?> GetByUsernameAsync(string u) =>
        await _conn.QueryFirstOrDefaultAsync<User>(
            "SELECT Id, Username, PasswordHash, Email, IsActive, Role, CreatedAt, UpdatedAt, IsDeleted, DeletedAt FROM Users WHERE Username=@u",
            new { u });
 
    public async Task<int> AddAsync(User u)
    {
        await _ctx.Users.AddAsync(u);
        await _ctx.SaveChangesAsync();
        return u.Id;
    }
}
"@
)
    } else {
        # Generic Repository in Hybrid Mode: Write -> EF Core, Read -> Dapper (High Performance CQRS)
        $p = if ($e -eq "Product") { ", Price" } else { "" }
        $cols = "Id, Name$p, CreatedAt, UpdatedAt, IsDeleted, DeletedAt"
        $pagedSql = Get-PagedSql $pE $cols

        Write-File "Repositories\$e`Repository.cs" (T @'
using System.Data;
using Dapper;
using {P}.Domain.Common;
using {P}.Domain.Entities;
using {P}.Domain.Interfaces;
using {P}.Persistence.Context;
 
namespace {P}.Persistence.Repositories;
 
public class {E}Repository : I{E}Repository
{
    private readonly AppDbContext _ctx;
    private readonly IDbConnection _conn;
 
    public {E}Repository(AppDbContext ctx, IDbConnection conn)
    {
        _ctx = ctx;
        _conn = conn;
    }
 
    public async Task<{E}?> GetByIdAsync(int id) =>
        await _conn.QueryFirstOrDefaultAsync<{E}>(
            "SELECT {Cols} FROM {PE} WHERE Id=@id AND IsDeleted=@IsDeleted",
            new { id, IsDeleted = false });
 
    public async Task<IEnumerable<{E}>> GetAllAsync() =>
        await _conn.QueryAsync<{E}>(
            "SELECT {Cols} FROM {PE} WHERE IsDeleted=@IsDeleted",
            new { IsDeleted = false });
 
    public async Task<PagedResult<{E}>> GetPagedAsync(PagedQuery query)
    {
        var total = await _conn.ExecuteScalarAsync<int>(
            "SELECT COUNT(*) FROM {PE} WHERE IsDeleted=@IsDeleted",
            new { IsDeleted = false });
 
        var items = await _conn.QueryAsync<{E}>(
            BTICK{PagedSql}BTICK,
            new { Offset = query.Skip, query.Size, IsDeleted = false });
 
        return new PagedResult<{E}> { Items = items, TotalCount = total, Page = query.Page, Size = query.Size };
    }
 
    public async Task<int> AddAsync({E} e)
    {
        await _ctx.{PE}.AddAsync(e);
        await _ctx.SaveChangesAsync();
        return e.Id;
    }
 
    public async Task UpdateAsync({E} e)
    {
        _ctx.{PE}.Update(e);
        await _ctx.SaveChangesAsync();
    }
 
    public async Task DeleteAsync(int id)
    {
        var entity = await _ctx.{PE}.FindAsync(id);
        if (entity != null)
        {
            entity.Delete();
            await _ctx.SaveChangesAsync();
        }
    }
}
'@
 $e | % {
    $_.Replace("{PE}", $pE).Replace("{P}", $ProjectName).Replace("BTICK", "`"").Replace("{Cols}", $cols).Replace("{PagedSql}", $pagedSql)
})
    }
}