feat: PRD-002 Product CRUD #40

Merged
dmolinari merged 14 commits from feature/PRD-002 into main 2026-04-19 16:49:58 +00:00
3 changed files with 9 additions and 46 deletions
Showing only changes of commit b4f17d6961 - Show all commits

View File

@@ -1,14 +0,0 @@
using SIGCM2.Application.Abstractions.Persistence;
namespace SIGCM2.Application.Products;
/// <summary>
/// STUB — PRD-002 replaces the DI binding with a real Dapper impl against dbo.Product.
/// Returns false for all queries so DeactivateProductTypeCommandHandler guard always passes.
/// This is intentional for PRD-001: the mechanism is installed; the data feed arrives in PRD-002.
/// </summary>
public sealed class NullProductQueryRepository : IProductQueryRepository
{
public Task<bool> ExistsActiveByProductTypeAsync(int productTypeId, CancellationToken ct = default)
=> Task.FromResult(false);
}

View File

@@ -19,16 +19,19 @@ public sealed class ProductQueryRepository : IProductQueryRepository
public async Task<bool> ExistsActiveByProductTypeAsync(int productTypeId, CancellationToken ct = default)
{
const string sql = """
SELECT COUNT(1)
FROM dbo.Product
WHERE ProductTypeId = @ProductTypeId
AND IsActive = 1
SELECT CASE
WHEN EXISTS (
SELECT 1 FROM dbo.Product
WHERE ProductTypeId = @ProductTypeId
AND IsActive = 1
) THEN 1 ELSE 0
END
""";
await using var connection = _factory.CreateConnection();
await connection.OpenAsync(ct);
var count = await connection.ExecuteScalarAsync<int>(sql, new { ProductTypeId = productTypeId });
return count > 0;
var result = await connection.ExecuteScalarAsync<int>(sql, new { ProductTypeId = productTypeId });
return result == 1;
}
}

View File

@@ -1,26 +0,0 @@
using FluentAssertions;
using SIGCM2.Application.Products;
namespace SIGCM2.Application.Tests.ProductTypes;
public class NullProductQueryRepositoryTests
{
private readonly NullProductQueryRepository _sut = new();
[Fact]
public async Task ExistsActiveByProductTypeAsync_AlwaysReturnsFalse()
{
var result = await _sut.ExistsActiveByProductTypeAsync(productTypeId: 1);
result.Should().BeFalse();
}
[Fact]
public async Task ExistsActiveByProductTypeAsync_WithCancellationToken_DoesNotThrow()
{
using var cts = new CancellationTokenSource();
var act = async () => await _sut.ExistsActiveByProductTypeAsync(productTypeId: 999, ct: cts.Token);
await act.Should().NotThrowAsync();
}
}