using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Stocks.GetCbExercises; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { private const ushort MaxPerPage = 200; 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)30 : request.PerPage; // 행사주식(기본) 또는 채권 기준 조회 var query = request.ByBond ? db.ConvertibleExercise.AsNoTracking().Where(c => c.BondIsin == isin) : db.ConvertibleExercise.AsNoTracking().Where(c => c.XrcStkIsin == isin); var total = await query.CountAsync(ct); var list = await query .OrderByDescending(c => c.RgtStdDt) .ThenBy(c => c.BondIsin) .Skip((page - 1) * perPage) .Take(perPage) .Select(c => new Response.Row { BondIsin = c.BondIsin, BondName = c.BondKorSecnNm, BondKind = c.BondKindNm, ExerciseStockIsin = c.XrcStkIsin, ExerciseStockName = c.StkKorSecnNm, RgtStdDt = c.RgtStdDt, ExercisePrice = c.XrcPrice, ExerciseQty = c.XrcQty, ExerciseAmt = c.XrcAmt, ListDt = c.ListDt }) .ToListAsync(ct); return new Response { Isin = isin, Total = total, List = list }; } }