| [09e02d7] | 1 | package mk.finki.roomreservation.service;
|
|---|
| 2 |
|
|---|
| 3 | import mk.finki.roomreservation.model.RoomOption;
|
|---|
| 4 | import mk.finki.roomreservation.model.SearchRoomsRequest;
|
|---|
| 5 | import org.springframework.jdbc.core.JdbcTemplate;
|
|---|
| 6 | import org.springframework.stereotype.Service;
|
|---|
| 7 |
|
|---|
| 8 | import java.sql.Date;
|
|---|
| 9 | import java.sql.Time;
|
|---|
| 10 | import java.time.LocalDate;
|
|---|
| 11 | import java.time.LocalTime;
|
|---|
| 12 | import java.util.List;
|
|---|
| 13 |
|
|---|
| 14 | @Service
|
|---|
| 15 | public class RoomService {
|
|---|
| 16 |
|
|---|
| 17 | private final JdbcTemplate jdbcTemplate;
|
|---|
| 18 |
|
|---|
| 19 | public RoomService(JdbcTemplate jdbcTemplate) {
|
|---|
| 20 | this.jdbcTemplate = jdbcTemplate;
|
|---|
| 21 | }
|
|---|
| 22 |
|
|---|
| 23 | public List<RoomOption> findAllRooms() {
|
|---|
| 24 | String sql = """
|
|---|
| 25 | SELECT
|
|---|
| 26 | r.room_id,
|
|---|
| 27 | r.room_code,
|
|---|
| 28 | r.capacity,
|
|---|
| 29 | r.type,
|
|---|
| 30 | b.name AS building_name,
|
|---|
| 31 | b.address
|
|---|
| 32 | FROM project.rooms r
|
|---|
| 33 | JOIN project.buildings b
|
|---|
| 34 | ON r.building_id = b.building_id
|
|---|
| 35 | ORDER BY b.name, r.room_code
|
|---|
| 36 | """;
|
|---|
| 37 |
|
|---|
| 38 | return jdbcTemplate.query(sql, (rs, rowNum) ->
|
|---|
| 39 | new RoomOption(
|
|---|
| 40 | rs.getInt("room_id"),
|
|---|
| 41 | rs.getString("room_code"),
|
|---|
| 42 | rs.getInt("capacity"),
|
|---|
| 43 | rs.getString("type"),
|
|---|
| 44 | rs.getString("building_name"),
|
|---|
| 45 | rs.getString("address")
|
|---|
| 46 | )
|
|---|
| 47 | );
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | public List<RoomOption> searchAvailableRooms(SearchRoomsRequest request) {
|
|---|
| 51 | validateSearchRequest(request);
|
|---|
| 52 |
|
|---|
| 53 | LocalDate date = LocalDate.parse(request.reservationDate());
|
|---|
| 54 | LocalTime start = LocalTime.parse(request.startTime());
|
|---|
| 55 | LocalTime end = LocalTime.parse(request.endTime());
|
|---|
| 56 |
|
|---|
| 57 | int minimumCapacity = request.minimumCapacity() == null ? 1 : request.minimumCapacity();
|
|---|
| 58 | String roomType = normalizeBlank(request.roomType());
|
|---|
| 59 | String equipmentName = normalizeBlank(request.requiredEquipmentName());
|
|---|
| 60 |
|
|---|
| 61 | String sql = """
|
|---|
| 62 | SELECT
|
|---|
| 63 | r.room_id,
|
|---|
| 64 | r.room_code,
|
|---|
| 65 | r.capacity,
|
|---|
| 66 | r.type,
|
|---|
| 67 | b.name AS building_name,
|
|---|
| 68 | b.address
|
|---|
| 69 | FROM project.rooms r
|
|---|
| 70 | JOIN project.buildings b
|
|---|
| 71 | ON r.building_id = b.building_id
|
|---|
| 72 | WHERE r.capacity >= ?
|
|---|
| 73 | AND (? = '' OR r.type = ?)
|
|---|
| 74 | AND (
|
|---|
| 75 | ? = ''
|
|---|
| 76 | OR EXISTS (
|
|---|
| 77 | SELECT 1
|
|---|
| 78 | FROM project.room_equipment re
|
|---|
| 79 | JOIN project.equipment e
|
|---|
| 80 | ON re.equipment_id = e.equipment_id
|
|---|
| 81 | WHERE re.room_id = r.room_id
|
|---|
| 82 | AND LOWER(e.name) LIKE LOWER('%' || ? || '%')
|
|---|
| 83 | )
|
|---|
| 84 | )
|
|---|
| 85 | AND NOT EXISTS (
|
|---|
| 86 | SELECT 1
|
|---|
| 87 | FROM project.reservations res
|
|---|
| 88 | WHERE res.room_id = r.room_id
|
|---|
| 89 | AND res.reservation_date = ?
|
|---|
| 90 | AND res.status IN ('pending', 'approved')
|
|---|
| 91 | AND ? < res.end_time
|
|---|
| 92 | AND ? > res.start_time
|
|---|
| 93 | )
|
|---|
| 94 | ORDER BY r.capacity, r.room_code
|
|---|
| 95 | """;
|
|---|
| 96 |
|
|---|
| 97 | return jdbcTemplate.query(
|
|---|
| 98 | sql,
|
|---|
| 99 | (rs, rowNum) -> new RoomOption(
|
|---|
| 100 | rs.getInt("room_id"),
|
|---|
| 101 | rs.getString("room_code"),
|
|---|
| 102 | rs.getInt("capacity"),
|
|---|
| 103 | rs.getString("type"),
|
|---|
| 104 | rs.getString("building_name"),
|
|---|
| 105 | rs.getString("address")
|
|---|
| 106 | ),
|
|---|
| 107 | minimumCapacity,
|
|---|
| 108 | roomType,
|
|---|
| 109 | roomType,
|
|---|
| 110 | equipmentName,
|
|---|
| 111 | equipmentName,
|
|---|
| 112 | Date.valueOf(date),
|
|---|
| 113 | Time.valueOf(start),
|
|---|
| 114 | Time.valueOf(end)
|
|---|
| 115 | );
|
|---|
| 116 | }
|
|---|
| 117 |
|
|---|
| 118 | private void validateSearchRequest(SearchRoomsRequest request) {
|
|---|
| 119 | if (request.reservationDate() == null || request.reservationDate().isBlank()) {
|
|---|
| 120 | throw new IllegalArgumentException("Reservation date is required.");
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | if (request.startTime() == null || request.startTime().isBlank()) {
|
|---|
| 124 | throw new IllegalArgumentException("Start time is required.");
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | if (request.endTime() == null || request.endTime().isBlank()) {
|
|---|
| 128 | throw new IllegalArgumentException("End time is required.");
|
|---|
| 129 | }
|
|---|
| 130 |
|
|---|
| 131 | LocalTime start = LocalTime.parse(request.startTime());
|
|---|
| 132 | LocalTime end = LocalTime.parse(request.endTime());
|
|---|
| 133 |
|
|---|
| 134 | if (!end.isAfter(start)) {
|
|---|
| 135 | throw new IllegalArgumentException("End time must be after start time.");
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | if (request.minimumCapacity() != null && request.minimumCapacity() < 1) {
|
|---|
| 139 | throw new IllegalArgumentException("Minimum capacity must be greater than 0.");
|
|---|
| 140 | }
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | private String normalizeBlank(String value) {
|
|---|
| 144 | if (value == null || value.trim().isEmpty()) {
|
|---|
| 145 | return "";
|
|---|
| 146 | }
|
|---|
| 147 |
|
|---|
| 148 | return value.trim();
|
|---|
| 149 | }
|
|---|
| 150 | } |
|---|