Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-validation'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import roomescape.domain.reservation.dto.response.ReservationResponseDto;
import roomescape.domain.reservation.dto.response.ReservationTimeStartAtResponseDto;
import roomescape.domain.reservation.service.ReservationService;

@RestController
Expand All @@ -28,6 +29,13 @@ public ResponseEntity<List<ReservationResponseDto>> getReservations() {
return ResponseEntity.ok(reservationService.getReservations());
}

@GetMapping("/{id}/time-start-at")
public ResponseEntity<ReservationTimeStartAtResponseDto> getReservationTimeStartAt(
@PathVariable @Positive(message = "id์˜ ๊ฐ’์€ ์–‘์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.") Long id
) {
return ResponseEntity.ok(reservationService.getReservationTimeStartAtForSqlObservation(id));
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteReservation(@PathVariable @Positive(message = "id์˜ ๊ฐ’์€ ์–‘์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.") Long id) {
reservationService.deleteReservationById(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package roomescape.domain.reservation.controller;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import roomescape.domain.reservation.dto.response.ReservationResponseDto;
import roomescape.domain.reservation.service.ReservationService;

@RestController
@Validated
public class MineReservationController {

private final ReservationService reservationService;

public MineReservationController(ReservationService reservationService) {
this.reservationService = reservationService;
}

@GetMapping("/reservations-mine")
public ResponseEntity<List<ReservationResponseDto>> getMineReservations(
@RequestParam
@NotBlank(message = "์˜ˆ์•ฝ์ž๋ช…์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.")
@Size(max = 20, message = "์˜ˆ์•ฝ์ž๋ช…์˜ ๊ธธ์ด๋Š” 1์ด์ƒ 20์ดํ•˜ ์ž…๋‹ˆ๋‹ค.")
String name
) {
return ResponseEntity.ok(reservationService.getMineReservations(name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import roomescape.domain.reservation.dto.response.ReservationResponseDto;
import roomescape.domain.reservation.mapper.ReservationMapper;
import roomescape.domain.reservation.service.ReservationService;
import roomescape.domain.reservation.vo.ReserverName;

@RestController
@RequestMapping("/api/reservations")
Expand Down Expand Up @@ -64,7 +63,7 @@ public ResponseEntity<ReservationCreateResponseDto> updateReservation(
String name,
@Valid @RequestBody ReservationUpdateRequestDto requestDto) {
return ResponseEntity.ok(
reservationService.updateReservation(id, new ReserverName(name),
reservationService.updateReservation(id, name,
reservationMapper.toUpdateCommand(requestDto)));
}

Expand All @@ -76,7 +75,7 @@ public ResponseEntity<ReservationCancelResponseDto> cancelReservation(
@Size(max = 20, message = "์˜ˆ์•ฝ์ž๋ช…์˜ ๊ธธ์ด๋Š” 1์ด์ƒ 20์ดํ•˜ ์ž…๋‹ˆ๋‹ค.")
String name
) {
return ResponseEntity.ok(reservationService.cancelReservation(id, new ReserverName(name)));
return ResponseEntity.ok(reservationService.cancelReservation(id, name));
}

@PostMapping("/waitings")
Expand All @@ -94,6 +93,6 @@ public ResponseEntity<ReservationCancelResponseDto> cancelWaitingReservation(
@Size(max = 20, message = "์˜ˆ์•ฝ์ž๋ช…์˜ ๊ธธ์ด๋Š” 1์ด์ƒ 20์ดํ•˜ ์ž…๋‹ˆ๋‹ค.")
String name
) {
return ResponseEntity.ok(reservationService.cancelWaitingReservation(id, new ReserverName(name)));
return ResponseEntity.ok(reservationService.cancelWaitingReservation(id, name));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package roomescape.domain.reservation.dto.command;

import java.time.LocalDate;
import roomescape.domain.reservation.vo.ReserverName;

public record ReservationCreateCommand(
ReserverName name,
String name,
LocalDate date,
Long timeId,
Long themeId
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape.domain.reservation.dto.response;

import java.time.LocalTime;

public record ReservationTimeStartAtResponseDto(Long reservationId, LocalTime startAt) {

}
148 changes: 128 additions & 20 deletions src/main/java/roomescape/domain/reservation/entity/Reservation.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,116 @@
package roomescape.domain.reservation.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Objects;
import roomescape.domain.reservation.vo.ReservationSchedule;
import roomescape.domain.reservation.vo.ReserverName;
import roomescape.domain.theme.entity.Theme;
import roomescape.domain.time.entity.Time;

@Entity
@Table(
name = "reservation",
indexes = {
@Index(
name = "uq_waiting_reservation",
columnList = "active_waiting, name, date, time_id, theme_id",
unique = true
),
@Index(
name = "uq_active_reservation",
columnList = "active_date, active_time_id, active_theme_id",
unique = true
)
}
)
public class Reservation {

private final Long id;
private final ReserverName name;
private final LocalDate date;
private final Time time;
private final Theme theme;
private final ReservationStatus status;
private final Long version;

private Reservation(Long id, ReserverName name, LocalDate date, Time time, Theme theme, ReservationStatus status,
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotBlank
@Column(name = "name", nullable = false)
private String name;

@NotNull
@Column(name = "date", nullable = false, columnDefinition = "DATE")
private LocalDate date;

@Enumerated(EnumType.STRING)
@Column(
name = "status",
columnDefinition = "ENUM('ACTIVE', 'CANCELED', 'WAITING') DEFAULT 'ACTIVE'"
)
private ReservationStatus status;

@NotNull
@Version
@Column(name = "version", nullable = false, columnDefinition = "BIGINT DEFAULT 0")
private Long version;

@Column(name = "deleted_at", columnDefinition = "DATETIME DEFAULT NULL")
private LocalDateTime deletedAt;

@Column(
name = "active_date",
insertable = false,
updatable = false,
columnDefinition = "DATE GENERATED ALWAYS AS "
+ "(CASE WHEN status = 'ACTIVE' AND deleted_at IS NULL THEN date ELSE NULL END)"
)
private LocalDate activeDate;

@Column(
name = "active_time_id",
insertable = false,
updatable = false,
columnDefinition = "BIGINT GENERATED ALWAYS AS "
+ "(CASE WHEN status = 'ACTIVE' AND deleted_at IS NULL THEN time_id ELSE NULL END)"
)
private Long activeTimeId;

@Column(
name = "active_theme_id",
insertable = false,
updatable = false,
columnDefinition = "BIGINT GENERATED ALWAYS AS "
+ "(CASE WHEN status = 'ACTIVE' AND deleted_at IS NULL THEN theme_id ELSE NULL END)"
)
private Long activeThemeId;

@Column(
name = "active_waiting",
insertable = false,
updatable = false,
columnDefinition = "BOOLEAN GENERATED ALWAYS AS "
+ "(CASE WHEN status = 'WAITING' AND deleted_at IS NULL THEN true ELSE NULL END)"
)
private Boolean activeWaiting;

@ManyToOne
@JoinColumn(name = "time_id", nullable = false)
private Time time;

@ManyToOne
@JoinColumn(name = "theme_id", nullable = false)
private Theme theme;

private Reservation(Long id, String name, LocalDate date, Time time, Theme theme, ReservationStatus status,
Long version) {
this.id = id;
this.name = name;
Expand All @@ -28,32 +121,43 @@ private Reservation(Long id, ReserverName name, LocalDate date, Time time, Theme
this.version = version;
}

public static Reservation create(ReserverName name, LocalDate date, Time time, Theme theme) {
public Reservation() {

}

public static Reservation create(String name, LocalDate date, Time time, Theme theme) {
return new Reservation(null, name, date, time, theme, ReservationStatus.ACTIVE, 0L);
}

public static Reservation reconstruct(
Long id, ReserverName name, LocalDate date, Time time, Theme theme, ReservationStatus status, Long version) {
Long id, String name, LocalDate date, Time time, Theme theme, ReservationStatus status, Long version) {
return new Reservation(id, name, date, time, theme, status, version);
}

public static Reservation reconstruct(
Long id, ReserverName name, LocalDate date, Time time, Theme theme, ReservationStatus status) {
Long id, String name, LocalDate date, Time time, Theme theme, ReservationStatus status) {
return reconstruct(id, name, date, time, theme, status, 0L);
}

public Reservation cancel() {
return new Reservation(this.id, this.name, this.date, this.time, this.theme, ReservationStatus.CANCELED,
version);
this.status = ReservationStatus.CANCELED;
return this;
}

public Reservation toWaiting() {
return new Reservation(this.id, this.name, this.date, this.time, this.theme, ReservationStatus.WAITING,
version);
this.status = ReservationStatus.WAITING;
return this;
}

public Reservation toActive() {
return new Reservation(this.id, this.name, this.date, this.time, this.theme, ReservationStatus.ACTIVE, version);
this.status = ReservationStatus.ACTIVE;
return this;
}

public void update(LocalDate date, Time time, Theme theme) {
this.date = date;
this.time = time;
this.theme = theme;
}

public ReservationEditableStatus getEditableStatus(LocalDateTime now) {
Expand Down Expand Up @@ -84,7 +188,7 @@ public ReservationSchedule getSchedule() {
return new ReservationSchedule(date, theme.getId(), time.getId());
}

public boolean isReservedBy(ReserverName name) {
public boolean isReservedBy(String name) {
return this.name.equals(name);
}

Expand All @@ -100,6 +204,10 @@ public boolean isScheduleChanged(Reservation reservation) {
return !getSchedule().equals(reservation.getSchedule());
}

public boolean hasVersion(Long version) {
return Objects.equals(this.version, version);
}

public boolean isPast(LocalDateTime now) {
return LocalDateTime.of(date, time.getStartAt()).isBefore(now);
}
Expand All @@ -108,7 +216,7 @@ public Long getId() {
return id;
}

public ReserverName getName() {
public String getName() {
return name;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import roomescape.domain.reservation.dto.response.ReservationResponseDto;
import roomescape.domain.reservation.entity.Reservation;
import roomescape.domain.reservation.entity.ReservationEditableStatus;
import roomescape.domain.reservation.vo.ReserverName;
import roomescape.domain.theme.mapper.ThemeMapper;
import roomescape.domain.time.mapper.TimeMapper;

Expand All @@ -26,7 +25,7 @@ public ReservationMapper(TimeMapper timeMapper, ThemeMapper themeMapper) {
}

public ReservationCreateCommand toCreateCommand(ReservationCreateRequestDto requestDto) {
return new ReservationCreateCommand(new ReserverName(requestDto.name()), requestDto.date(), requestDto.timeId(),
return new ReservationCreateCommand(requestDto.name(), requestDto.date(), requestDto.timeId(),
requestDto.themeId());
}

Expand All @@ -40,19 +39,19 @@ public ReservationResponseDto toResponseDto(
ReservationEditableStatus status,
Integer waitingNumber
) {
return new ReservationResponseDto(reservation.getId(), reservation.getName().value(), reservation.getDate(),
return new ReservationResponseDto(reservation.getId(), reservation.getName(), reservation.getDate(),
timeMapper.toReservationResponseDto(reservation.getTime()),
themeMapper.toReservationResponseDto(reservation.getTheme()), status, status.getMessage(), waitingNumber,
reservation.getVersion());
}

public ReservationCreateResponseDto toCreateResponseDto(Reservation reservation) {
return new ReservationCreateResponseDto(reservation.getId(), reservation.getName().value(),
return new ReservationCreateResponseDto(reservation.getId(), reservation.getName(),
reservation.getDate(), reservation.getTime().getId(), reservation.getTheme().getId());
}

public ReservationCancelResponseDto toCancelResponseDto(Reservation reservation) {
return new ReservationCancelResponseDto(reservation.getId(), reservation.getName().value(),
return new ReservationCancelResponseDto(reservation.getId(), reservation.getName(),
reservation.getDate(), reservation.getTime().getId(), reservation.getTheme().getId());
}
}
Loading