feat: Worker Service - API endpoints

Implement and configure Worker Service to orchestrate data fetchers - Implement API endpoints for stock market data
This commit is contained in:
2025-07-01 12:19:00 -03:00
parent 2fdf80f5b4
commit 10f19af9f8
15 changed files with 680 additions and 44 deletions

View File

@@ -0,0 +1,54 @@
using Dapper;
using Mercados.Core.Entities;
using System.Data;
namespace Mercados.Infrastructure.Persistence.Repositories
{
public class CotizacionBolsaRepository : ICotizacionBolsaRepository
{
private readonly IDbConnectionFactory _connectionFactory;
public CotizacionBolsaRepository(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task GuardarMuchosAsync(IEnumerable<CotizacionBolsa> cotizaciones)
{
using IDbConnection connection = _connectionFactory.CreateConnection();
const string sql = @"
INSERT INTO CotizacionesBolsa (Ticker, Mercado, PrecioActual, Apertura, CierreAnterior, PorcentajeCambio, FechaRegistro)
VALUES (@Ticker, @Mercado, @PrecioActual, @Apertura, @CierreAnterior, @PorcentajeCambio, @FechaRegistro);";
await connection.ExecuteAsync(sql, cotizaciones);
}
public async Task<IEnumerable<CotizacionBolsa>> ObtenerUltimasPorMercadoAsync(string mercado)
{
using IDbConnection connection = _connectionFactory.CreateConnection();
// Esta consulta SQL es un poco más avanzada. Usa una "Common Table Expression" (CTE)
// y la función ROW_NUMBER() para obtener el registro más reciente para cada Ticker
// dentro del mercado especificado. Es extremadamente eficiente.
const string sql = @"
WITH RankedCotizaciones AS (
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY Ticker ORDER BY FechaRegistro DESC) as rn
FROM
CotizacionesBolsa
WHERE
Mercado = @Mercado
)
SELECT
Id, Ticker, Mercado, PrecioActual, Apertura, CierreAnterior, PorcentajeCambio, FechaRegistro
FROM
RankedCotizaciones
WHERE
rn = 1;";
return await connection.QueryAsync<CotizacionBolsa>(sql, new { Mercado = mercado });
}
}
}

View File

@@ -0,0 +1,27 @@
using Dapper;
using Mercados.Core.Entities;
using System.Data;
namespace Mercados.Infrastructure.Persistence.Repositories
{
public class CotizacionGranoRepository : ICotizacionGranoRepository
{
private readonly IDbConnectionFactory _connectionFactory;
public CotizacionGranoRepository(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task GuardarMuchosAsync(IEnumerable<CotizacionGrano> cotizaciones)
{
using IDbConnection connection = _connectionFactory.CreateConnection();
const string sql = @"
INSERT INTO CotizacionesGranos (Nombre, Precio, VariacionPrecio, FechaOperacion, FechaRegistro)
VALUES (@Nombre, @Precio, @VariacionPrecio, @FechaOperacion, @FechaRegistro);";
await connection.ExecuteAsync(sql, cotizaciones);
}
}
}

View File

@@ -0,0 +1,10 @@
using Mercados.Core.Entities;
namespace Mercados.Infrastructure.Persistence.Repositories
{
public interface ICotizacionBolsaRepository : IBaseRepository
{
Task GuardarMuchosAsync(IEnumerable<CotizacionBolsa> cotizaciones);
Task<IEnumerable<CotizacionBolsa>> ObtenerUltimasPorMercadoAsync(string mercado);
}
}

View File

@@ -0,0 +1,9 @@
using Mercados.Core.Entities;
namespace Mercados.Infrastructure.Persistence.Repositories
{
public interface ICotizacionGranoRepository : IBaseRepository
{
Task GuardarMuchosAsync(IEnumerable<CotizacionGrano> cotizaciones);
}
}