feat(infra): BATCH 4 - Permiso/RolPermiso repos Dapper + tests integracion [UDT-005]
This commit is contained in:
@@ -29,6 +29,8 @@ public static class DependencyInjection
|
||||
services.AddScoped<IUsuarioRepository, UsuarioRepository>();
|
||||
services.AddScoped<IRefreshTokenRepository, RefreshTokenRepository>();
|
||||
services.AddScoped<IRolRepository, RolRepository>();
|
||||
services.AddScoped<IPermisoRepository, PermisoRepository>();
|
||||
services.AddScoped<IRolPermisoRepository, RolPermisoRepository>();
|
||||
|
||||
// JWT Options — bound lazily via IOptions so tests can override via ConfigureWebHost
|
||||
services.Configure<JwtOptions>(configuration.GetSection("Jwt"));
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
using Dapper;
|
||||
using SIGCM2.Application.Abstractions.Persistence;
|
||||
using SIGCM2.Domain.Entities;
|
||||
|
||||
namespace SIGCM2.Infrastructure.Persistence;
|
||||
|
||||
public sealed class PermisoRepository : IPermisoRepository
|
||||
{
|
||||
private readonly SqlConnectionFactory _connectionFactory;
|
||||
|
||||
public PermisoRepository(SqlConnectionFactory connectionFactory)
|
||||
{
|
||||
_connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<Permiso>> ListAsync(CancellationToken ct = default)
|
||||
{
|
||||
const string sql = """
|
||||
SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
|
||||
FROM dbo.Permiso
|
||||
ORDER BY Id
|
||||
""";
|
||||
|
||||
await using var connection = _connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(ct);
|
||||
|
||||
var rows = await connection.QueryAsync<PermisoRow>(sql);
|
||||
return rows.Select(MapRow).ToList();
|
||||
}
|
||||
|
||||
public async Task<Permiso?> GetByCodigoAsync(string codigo, CancellationToken ct = default)
|
||||
{
|
||||
const string sql = """
|
||||
SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
|
||||
FROM dbo.Permiso
|
||||
WHERE Codigo = @Codigo
|
||||
""";
|
||||
|
||||
await using var connection = _connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(ct);
|
||||
|
||||
var row = await connection.QuerySingleOrDefaultAsync<PermisoRow>(sql, new { Codigo = codigo });
|
||||
return row is null ? null : MapRow(row);
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<Permiso>> GetByCodigosAsync(
|
||||
IEnumerable<string> codigos,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var codigosList = codigos.ToList();
|
||||
if (codigosList.Count == 0)
|
||||
return Array.Empty<Permiso>();
|
||||
|
||||
const string sql = """
|
||||
SELECT Id, Codigo, Nombre, Descripcion, Modulo, Activo, FechaCreacion
|
||||
FROM dbo.Permiso
|
||||
WHERE Codigo IN @Codigos
|
||||
""";
|
||||
|
||||
await using var connection = _connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(ct);
|
||||
|
||||
var rows = await connection.QueryAsync<PermisoRow>(sql, new { Codigos = codigosList });
|
||||
return rows.Select(MapRow).ToList();
|
||||
}
|
||||
|
||||
private static Permiso MapRow(PermisoRow row)
|
||||
=> Permiso.ForRead(
|
||||
id: row.Id,
|
||||
codigo: row.Codigo,
|
||||
nombre: row.Nombre,
|
||||
descripcion: row.Descripcion,
|
||||
modulo: row.Modulo,
|
||||
activo: row.Activo,
|
||||
fechaCreacion: row.FechaCreacion);
|
||||
|
||||
private sealed record PermisoRow(
|
||||
int Id,
|
||||
string Codigo,
|
||||
string Nombre,
|
||||
string? Descripcion,
|
||||
string Modulo,
|
||||
bool Activo,
|
||||
DateTime FechaCreacion);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using Dapper;
|
||||
using SIGCM2.Application.Abstractions.Persistence;
|
||||
using SIGCM2.Domain.Entities;
|
||||
|
||||
namespace SIGCM2.Infrastructure.Persistence;
|
||||
|
||||
public sealed class RolPermisoRepository : IRolPermisoRepository
|
||||
{
|
||||
private readonly SqlConnectionFactory _connectionFactory;
|
||||
|
||||
public RolPermisoRepository(SqlConnectionFactory connectionFactory)
|
||||
{
|
||||
_connectionFactory = connectionFactory;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<Permiso>> GetByRolCodigoAsync(
|
||||
string rolCodigo,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
const string sql = """
|
||||
SELECT p.Id, p.Codigo, p.Nombre, p.Descripcion, p.Modulo, p.Activo, p.FechaCreacion
|
||||
FROM dbo.RolPermiso rp
|
||||
JOIN dbo.Rol r ON r.Id = rp.RolId
|
||||
JOIN dbo.Permiso p ON p.Id = rp.PermisoId
|
||||
WHERE r.Codigo = @RolCodigo
|
||||
ORDER BY p.Id
|
||||
""";
|
||||
|
||||
await using var connection = _connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(ct);
|
||||
|
||||
var rows = await connection.QueryAsync<PermisoRow>(sql, new { RolCodigo = rolCodigo });
|
||||
return rows.Select(MapRow).ToList();
|
||||
}
|
||||
|
||||
public async Task ReplaceForRolAsync(
|
||||
int rolId,
|
||||
IEnumerable<int> permisoIds,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var ids = permisoIds.ToList();
|
||||
|
||||
await using var connection = _connectionFactory.CreateConnection();
|
||||
await connection.OpenAsync(ct);
|
||||
|
||||
await using var transaction = await connection.BeginTransactionAsync(ct);
|
||||
try
|
||||
{
|
||||
// Step 1: Delete all existing permisos for this rol
|
||||
await connection.ExecuteAsync(
|
||||
"DELETE FROM dbo.RolPermiso WHERE RolId = @RolId",
|
||||
new { RolId = rolId },
|
||||
transaction);
|
||||
|
||||
// Step 2: Insert the new set (bulk via multi-row VALUES)
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
foreach (var permisoId in ids)
|
||||
{
|
||||
await connection.ExecuteAsync(
|
||||
"""
|
||||
INSERT INTO dbo.RolPermiso (RolId, PermisoId)
|
||||
VALUES (@RolId, @PermisoId)
|
||||
""",
|
||||
new { RolId = rolId, PermisoId = permisoId },
|
||||
transaction);
|
||||
}
|
||||
}
|
||||
|
||||
await transaction.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static Permiso MapRow(PermisoRow row)
|
||||
=> Permiso.ForRead(
|
||||
id: row.Id,
|
||||
codigo: row.Codigo,
|
||||
nombre: row.Nombre,
|
||||
descripcion: row.Descripcion,
|
||||
modulo: row.Modulo,
|
||||
activo: row.Activo,
|
||||
fechaCreacion: row.FechaCreacion);
|
||||
|
||||
private sealed record PermisoRow(
|
||||
int Id,
|
||||
string Codigo,
|
||||
string Nombre,
|
||||
string? Descripcion,
|
||||
string Modulo,
|
||||
bool Activo,
|
||||
DateTime FechaCreacion);
|
||||
}
|
||||
Reference in New Issue
Block a user