package com.example.app.project; import com.example.app.project.ProjectDtos.CreateProjectRequest; import com.example.app.project.ProjectDtos.ProjectResponse; import com.example.app.time.TimeEntryRepository; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class ProjectService { private final ProjectRepository projectRepository; private final TimeEntryRepository timeEntryRepository; public ProjectService( ProjectRepository projectRepository, TimeEntryRepository timeEntryRepository) { this.projectRepository = projectRepository; this.timeEntryRepository = timeEntryRepository; } @Transactional(readOnly = true) public List findAll() { List projects = projectRepository.findAll(); // one aggregate query for totals across all entries Map totals = new HashMap<>(); for (Object[] row : timeEntryRepository.aggregateAllByProject()) { long projectId = ((Number) row[0]).longValue(); long minutes = ((Number) row[1]).longValue(); long cost = ((Number) row[2]).longValue(); totals.put(projectId, new long[] {minutes, cost}); } return projects.stream() .map( p -> { long[] t = totals.getOrDefault(p.getId(), new long[] {0, 0}); return ProjectResponse.from(p, t[0], t[1]); }) .toList(); } @Transactional public ProjectResponse create(CreateProjectRequest req) { Project p = new Project(); p.setName(req.name()); p.setTimeBudgetMinutes(req.timeBudgetMinutes()); p.setCostBudgetCents(req.costBudgetCents()); p.setHourlyRateCents(req.hourlyRateCents()); Project saved = projectRepository.save(p); return ProjectResponse.from(saved, 0, 0); } }