using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.Stocks.GetList; internal sealed class Handler(IAppDbContext db) : IQueryHandler { private const ushort MaxPerPage = 100; public async Task Handle(Query request, CancellationToken ct) { var page = request.Page < 1 ? 1 : request.Page; var perPage = request.PerPage is 0 or > MaxPerPage ? (ushort)20 : request.PerPage; var query = db.Stock.AsNoTracking().Where(c => c.IsActive); if (request.Market.HasValue) { query = query.Where(c => c.Market == request.Market.Value); } var q = request.Q?.Trim(); if (!string.IsNullOrEmpty(q)) { query = query.Where(c => c.Name.Contains(q) || c.Code.StartsWith(q)); } var total = await query.CountAsync(ct); var list = await query .OrderBy(c => c.Name).ThenBy(c => c.Code) .Skip((page - 1) * perPage) .Take(perPage) .Select(c => new { c.Code, c.Name, c.Market, c.TradingStatus, c.LastTradingDate, c.LastClosePrice, c.LastChangeRate, c.MarketCap, // 전일 거래량 — Stock denorm 에 없어 최근 거래일(LastTradingDate)의 StockDailyPrice 를 상관 서브쿼리로 조회 Volume = db.StockDailyPrice.Where(p => p.StockID == c.ID && p.TradingDate == c.LastTradingDate).Select(p => (long?)p.Volume).FirstOrDefault() }) .ToListAsync(ct); return new Response { Total = total, List = [..list.Select(c => new Response.Row { Code = c.Code, Name = c.Name, Market = c.Market.ToString(), TradingStatus = c.TradingStatus.ToString(), LastTradingDate = c.LastTradingDate, ClosePrice = c.LastClosePrice, ChangeRate = c.LastChangeRate, MarketCap = c.MarketCap, Volume = c.Volume })] }; } }