using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Stocks.GetLendingHistory; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { private const ushort MaxPerPage = 500; public async Task> Handle(Query request, CancellationToken ct) { var input = request.CodeOrIsin?.Trim(); if (string.IsNullOrEmpty(input)) { return Result.Failure(Error.Problem("Stock.CodeRequired", "종목 코드가 필요합니다.")); } // 단축코드(6자리)면 Stock 조인으로 ISIN 확보, 아니면 입력을 ISIN 으로 간주. var isin = await db.Stock.AsNoTracking().Where(c => c.Code == input && c.ISIN != null).Select(c => c.ISIN!).FirstOrDefaultAsync(ct) ?? input; var page = request.Page < 1 ? 1 : request.Page; var perPage = request.PerPage is 0 or > MaxPerPage ? (ushort)90 : request.PerPage; var query = db.SecuritiesLending.AsNoTracking().Where(c => c.Isin == isin); if (request.From.HasValue) { query = query.Where(c => c.StdDt >= request.From.Value); } if (request.To.HasValue) { query = query.Where(c => c.StdDt <= request.To.Value); } var total = await query.CountAsync(ct); var list = await query .OrderByDescending(c => c.StdDt) .Skip((page - 1) * perPage) .Take(perPage) .Select(c => new Response.Row { StdDt = c.StdDt, LendingBalanceQty = c.SlbTrRemQty, MatchedQty = c.MatcQty, RedeemedQty = c.RedQty, TradeQty = c.TrQty, ForeignLendRatio = c.FrinerLendRemRatio, NativeLendRatio = c.NativeLendRemRatio, ForeignBorrowRatio = c.FrinerBrwRemRatio, NativeBorrowRatio = c.NativeBrwRemRatio }) .ToListAsync(ct); return new Response { Isin = isin, Total = total, List = list }; } }