Skip to content

Commit d8942f1

Browse files
committed
feat: 강의가 하나 이상의 커버 이미지를 가질 수 있게 수정
1 parent 8396e29 commit d8942f1

File tree

13 files changed

+126
-47
lines changed

13 files changed

+126
-47
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package nextstep.courses.domain;
2+
3+
import nextstep.courses.exception.EmptyCoverImageException;
4+
5+
import java.util.List;
6+
7+
public class CoverImages {
8+
9+
private List<CoverImage> images;
10+
11+
public CoverImages(List<CoverImage> images) {
12+
validateIsNull(images);
13+
this.images = images;
14+
}
15+
16+
private void validateIsNull(List<CoverImage> images) {
17+
if (images == null || images.isEmpty()) {
18+
throw new EmptyCoverImageException();
19+
}
20+
}
21+
}

src/main/java/nextstep/courses/domain/Session.java

+13-17
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,39 @@ public class Session extends BaseEntity {
1313
private final Long id;
1414
private final Long courseId;
1515
private final SessionType type;
16-
private final CoverImage coverImage;
16+
private final CoverImages coverImages;
1717
private final Period period;
1818
private Status status;
1919
private final Students students;
2020
private final PaidCondition paidCondition;
2121

22-
public static Session ofFree(Long id, Long courseId, CoverImage coverImage, LocalDate startDate, LocalDate endDate) {
23-
return new Session(id, courseId, SessionType.FREE, coverImage, new Period(startDate, endDate), Status.NOT_OPEN, 0, 0L, LocalDateTime.now(), null);
22+
public static Session ofFree(Long id, Long courseId, CoverImages coverImages, LocalDate startDate, LocalDate endDate) {
23+
return new Session(id, courseId, SessionType.FREE, coverImages, new Period(startDate, endDate), Status.NOT_OPEN, 0, 0L, LocalDateTime.now(), null);
2424
}
2525

26-
public static Session ofPaid(Long id, Long courseId, CoverImage coverImage, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee) {
27-
return new Session(id, courseId, SessionType.PAID, coverImage, new Period(startDate, endDate), Status.NOT_OPEN, maxStudents, fee, LocalDateTime.now(), null);
26+
public static Session ofPaid(Long id, Long courseId, CoverImages coverImages, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee) {
27+
return new Session(id, courseId, SessionType.PAID, coverImages, new Period(startDate, endDate), Status.NOT_OPEN, maxStudents, fee, LocalDateTime.now(), null);
2828
}
2929

30-
public static Session of(Long id, Long courseId, SessionType type, CoverImage coverImage, Status status, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
31-
return new Session(id, courseId, type, coverImage, new Period(startDate, endDate), status, maxStudents, fee, createdAt, updatedAt);
30+
public static Session of(Long id, Long courseId, SessionType type, CoverImages coverImages, Status status, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
31+
return new Session(id, courseId, type, coverImages, new Period(startDate, endDate), status, maxStudents, fee, createdAt, updatedAt);
3232
}
3333

34-
private Session(Long id, Long courseId, SessionType type, CoverImage coverImage, Period period, Status status, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
34+
private Session(Long id, Long courseId, SessionType type, CoverImages coverImages, Period period, Status status, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
3535
super(createdAt, updatedAt);
36-
validateNotNull(id, coverImage, period);
36+
validateNotNull(id, coverImages, period);
3737
this.id = id;
3838
this.courseId = courseId;
3939
this.type = type;
40-
this.coverImage = coverImage;
40+
this.coverImages = coverImages;
4141
this.period = period;
4242
this.status = status;
4343
this.students = new Students();
4444
this.paidCondition = new PaidCondition(maxStudents, fee);
4545
}
4646

47-
private void validateNotNull(Long id, CoverImage coverImage, Period period) {
48-
if (id == null || coverImage == null || period == null) {
47+
private void validateNotNull(Long id, CoverImages coverImages, Period period) {
48+
if (id == null || coverImages == null || period == null) {
4949
throw new InvalidSessionException();
5050
}
5151
}
@@ -83,10 +83,6 @@ public Long courseId() {
8383
return courseId;
8484
}
8585

86-
public Long imageId() {
87-
return coverImage.getId();
88-
}
89-
9086
public String type() {
9187
return type.name();
9288
}
@@ -116,7 +112,7 @@ public String toString() {
116112
return "Session{" +
117113
"id=" + id +
118114
", type=" + type +
119-
", coverImage=" + coverImage +
115+
", coverImages=" + coverImages +
120116
", period=" + period +
121117
", status=" + status +
122118
", students=" + students +
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package nextstep.courses.exception;
2+
3+
public class EmptyCoverImageException extends RuntimeException {
4+
5+
public EmptyCoverImageException() {
6+
super("강의는 하나 이상의 커버 이미지를 가져야 합니다.");
7+
}
8+
}

src/main/java/nextstep/courses/infrastructure/JdbcCoverImageRepository.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.sql.Timestamp;
1010
import java.time.LocalDateTime;
11+
import java.util.List;
1112

1213
@Repository("coverImageRepository")
1314
public class JdbcCoverImageRepository implements CoverImageRepository {
@@ -27,6 +28,16 @@ public int save(CoverImage image) {
2728
@Override
2829
public CoverImage findById(Long id) {
2930
String sql = "select id, size, extension, width, height, created_at, updated_at from cover_image where id = ?";
31+
return jdbcTemplate.queryForObject(sql, rowMapper(), id);
32+
}
33+
34+
@Override
35+
public List<CoverImage> findAllBySessionId(Long id) {
36+
String sql = "select id, size, extension, width, height, created_at, updated_at from cover_image where session_id = ?";
37+
return jdbcTemplate.query(sql, rowMapper(), id);
38+
}
39+
40+
private RowMapper<CoverImage> rowMapper() {
3041
RowMapper<CoverImage> rowMapper = (rs, rowNum) -> new CoverImage(
3142
rs.getLong(1),
3243
rs.getLong(2),
@@ -35,7 +46,7 @@ public CoverImage findById(Long id) {
3546
rs.getInt(5),
3647
toLocalDateTime(rs.getTimestamp(6)),
3748
toLocalDateTime(rs.getTimestamp(7)));
38-
return jdbcTemplate.queryForObject(sql, rowMapper, id);
49+
return rowMapper;
3950
}
4051

4152
private LocalDateTime toLocalDateTime(Timestamp timestamp) {

src/main/java/nextstep/courses/infrastructure/JdbcSessionRepository.java

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package nextstep.courses.infrastructure;
22

3-
import nextstep.courses.domain.CoverImage;
3+
import nextstep.courses.domain.CoverImages;
44
import nextstep.courses.domain.Session;
55
import nextstep.courses.domain.SessionType;
66
import nextstep.courses.domain.Status;
@@ -29,25 +29,25 @@ public JdbcSessionRepository(JdbcOperations jdbcTemplate) {
2929

3030
@Override
3131
public int save(Session session) {
32-
String sql = "insert into session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
33-
return jdbcTemplate.update(sql, session.id(), session.courseId(), session.imageId(), session.type(), session.status(), session.startDate(), session.endDate(), session.maxStudents(), session.fee(), session.getCreatedAt());
32+
String sql = "insert into session2 (id, course_id, type, status, start_date, end_date, max_students, fee, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
33+
return jdbcTemplate.update(sql, session.id(), session.courseId(), session.type(), session.status(), session.startDate(), session.endDate(), session.maxStudents(), session.fee(), session.getCreatedAt());
3434
}
3535

3636
@Override
3737
public Session findById(Long id) {
38-
String sql = "select id, course_id, type, image_id, status, start_date, end_date, max_students, fee, created_at, updated_at from session where id = ?";
38+
String sql = "select id, course_id, type, status, start_date, end_date, max_students, fee, created_at, updated_at from session where id = ?";
3939
RowMapper<Session> rowMapper = (rs, rowNum) -> Session.of(
4040
rs.getLong(1),
4141
rs.getLong(2),
4242
SessionType.findByCode(rs.getString(3)),
43-
coverImage(rs.getLong(4)),
44-
Status.findByName(rs.getString(5)),
43+
coverImages(id),
44+
Status.findByName(rs.getString(4)),
45+
toLocalDate(rs.getDate(5)),
4546
toLocalDate(rs.getDate(6)),
46-
toLocalDate(rs.getDate(7)),
47-
rs.getInt(8),
48-
rs.getLong(9),
49-
toLocalDateTime(rs.getTimestamp(10)),
50-
toLocalDateTime(rs.getTimestamp(11)));
47+
rs.getInt(7),
48+
rs.getLong(8),
49+
toLocalDateTime(rs.getTimestamp(9)),
50+
toLocalDateTime(rs.getTimestamp(10)));
5151

5252
return jdbcTemplate.queryForObject(sql, rowMapper, id);
5353
}
@@ -66,7 +66,7 @@ private LocalDate toLocalDate(Date date) {
6666
return date.toLocalDate();
6767
}
6868

69-
private CoverImage coverImage(Long id) {
70-
return coverImageRepository.findById(id);
69+
private CoverImages coverImages(Long id) {
70+
return new CoverImages(coverImageRepository.findAllBySessionId(id));
7171
}
7272
}

src/main/java/nextstep/courses/repository/CoverImageRepository.java

+4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
import nextstep.courses.domain.CoverImage;
44

5+
import java.util.List;
6+
57
public interface CoverImageRepository {
68
int save(CoverImage coverImage);
79

810
CoverImage findById(Long id);
11+
12+
List<CoverImage> findAllBySessionId(Long id);
913
}

src/main/resources/data.sql

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ INSERT INTO question (id, writer_id, title, contents, created_at, deleted) VALUE
1212
INSERT INTO course (id, title, creator_id, created_at) VALUES (2, 'JPA 활용편1', 2, CURRENT_TIMESTAMP());
1313

1414
INSERT INTO cover_image (id, size, extension, width, height, created_at) VALUES (2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
15+
INSERT INTO cover_image (id, session_id, size, extension, width, height, created_at) VALUES (3, 2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
16+
INSERT INTO cover_image (id, session_id, size, extension, width, height, created_at) VALUES (4, 2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
1517

1618
INSERT INTO session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) VALUES (2, 2, 2, 'FREE', 'NOT_OPEN', '2023-12-01', '2023-12-31', 0, 0, CURRENT_TIMESTAMP());
1719
INSERT INTO session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) VALUES (3, 2, 2, 'PAID', 'NOT_OPEN', '2023-12-01', '2023-12-31', 30, 20000, CURRENT_TIMESTAMP());

src/main/resources/schema.sql

+15
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ create table delete_history (
5151

5252
create table cover_image (
5353
id bigint not null,
54+
session_id bigint,
5455
size double not null,
5556
extension varchar(10) not null,
5657
width int not null,
@@ -75,6 +76,20 @@ create table session (
7576
primary key (id)
7677
);
7778

79+
create table session2 (
80+
id bigint not null,
81+
course_id bigint not null,
82+
type varchar(10) not null,
83+
status varchar(10) not null,
84+
start_date timestamp not null,
85+
end_date timestamp not null,
86+
max_students int,
87+
fee int,
88+
created_at timestamp not null,
89+
updated_at timestamp,
90+
primary key (id)
91+
);
92+
7893
create table students (
7994
id bigint generated by default as identity,
8095
session_id bigint not null,

src/test/java/nextstep/courses/domain/CourseTest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.junit.jupiter.api.Test;
55

66
import java.time.LocalDate;
7+
import java.util.List;
78

89
import static org.assertj.core.api.Assertions.assertThat;
910

@@ -15,7 +16,7 @@ void add_session() {
1516
Course course = new Course(0L, "TDD, 클린 코드 with Java 17기", 1L);
1617
CoverImage coverImage = new CoverImage(1, "jpg", 300, 200);
1718
LocalDate now = LocalDate.now();
18-
Session session = Session.ofFree(0L, 1L, coverImage, now, now);
19+
Session session = Session.ofFree(0L, 1L, new CoverImages(List.of(coverImage)), now, now);
1920

2021
course.addSession(session);
2122

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package nextstep.courses.domain;
2+
3+
class CoverImagesTest {
4+
5+
}

src/test/java/nextstep/courses/domain/SessionTest.java

+16-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.junit.jupiter.api.Test;
88

99
import java.time.LocalDate;
10+
import java.util.List;
1011

1112
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1213

@@ -18,23 +19,23 @@ class SessionTest {
1819
@Test
1920
@DisplayName("무료 강의 수강 신청 시 강의 상태가 모집중이 아니면 예외를 던진다.")
2021
void register_status_check() {
21-
Session freeSession = Session.ofFree(1L, 2L, coverImage(), START_DATE, END_DATE);
22+
Session freeSession = Session.ofFree(1L, 2L, coverImages(), START_DATE, END_DATE);
2223
assertThatThrownBy(() -> freeSession.register(Payment.ofFree(1L, NsUserTest.JAVAJIGI)))
2324
.isInstanceOf(NotOpenSessionException.class);
2425
}
2526

2627
@Test
2728
@DisplayName("강의 상태를 모집중으로 변경 시 현재 날짜가 강의 기간에 속하지 않으면 예외를 던진다.")
2829
void register_open() {
29-
Session session = Session.ofFree(1L, 2L, coverImage(), START_DATE, LocalDate.of(2023, 12, 2));
30+
Session session = Session.ofFree(1L, 2L, coverImages(), START_DATE, LocalDate.of(2023, 12, 2));
3031
assertThatThrownBy(() -> session.openSession())
3132
.isInstanceOf(OutOfSessionException.class);
3233
}
3334

3435
@Test
3536
@DisplayName("유료 강의 수강 신청 시 최대 수강 인원을 초과하면 예외를 던진다.")
3637
void register_over_students() {
37-
Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 1, 10_000L);
38+
Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 1, 10_000L);
3839
paidSession.openSession();
3940

4041
paidSession.register(Payment.ofPaid(1L, 1L, NsUserTest.JAVAJIGI, 10_000L));
@@ -46,7 +47,7 @@ void register_over_students() {
4647
@Test
4748
@DisplayName("유료 강의 수강 신청 시 결제금액과 수강료가 일치하는지 확인하지 않으면 예외를 던진다.")
4849
void session_fee_test() {
49-
Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 1, 10_000L);
50+
Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 1, 10_000L);
5051
paidSession.openSession();
5152

5253
assertThatThrownBy(() -> paidSession.register(Payment.ofPaid(2L, 1L, NsUserTest.SANJIGI, 8_000L)))
@@ -56,14 +57,14 @@ void session_fee_test() {
5657
@Test
5758
@DisplayName("강의 생성 시 결제금액과 수강료가 음수면 예외를 던진다.")
5859
void session_paid_condition_null() {
59-
assertThatThrownBy(() -> Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, -1, -1L))
60+
assertThatThrownBy(() -> Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, -1, -1L))
6061
.isInstanceOf(NegativePaidConditionException.class);
6162
}
6263

6364
@Test
6465
@DisplayName("중복 수강 신청 시 예외를 던진다.")
6566
void duplicate_register() {
66-
Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 2, 10_000L);
67+
Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 2, 10_000L);
6768
paidSession.openSession();
6869

6970
paidSession.register(Payment.ofPaid(1L, 1L, NsUserTest.SANJIGI, 10_000L));
@@ -72,7 +73,14 @@ void duplicate_register() {
7273
.isInstanceOf(DuplicateStudentsException.class);
7374
}
7475

75-
private static CoverImage coverImage() {
76-
return new CoverImage(1, "gif", 300, 200);
76+
@Test
77+
@DisplayName("강의 생성 시 이미지가 없으면 예외를 던진다.")
78+
void empty_images() {
79+
assertThatThrownBy(() -> Session.ofPaid(1L, 2L, new CoverImages(null), START_DATE, END_DATE, 1, 10_000L))
80+
.isInstanceOf(EmptyCoverImageException.class);
81+
}
82+
83+
private static CoverImages coverImages() {
84+
return new CoverImages(List.of(new CoverImage(1, "gif", 300, 200)));
7785
}
7886
}

src/test/java/nextstep/courses/infrastructure/CoverImageRepositoryTest.java

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
1111
import org.springframework.jdbc.core.JdbcTemplate;
1212

13+
import java.util.List;
14+
1315
import static org.assertj.core.api.Assertions.assertThat;
1416

1517
@JdbcTest
@@ -41,4 +43,11 @@ void crud() {
4143
void find() {
4244
assertThat(coverImageRepository.findById(2L).getId()).isEqualTo(2L);
4345
}
46+
47+
@Test
48+
void findAllBySessionId() {
49+
List<CoverImage> images = coverImageRepository.findAllBySessionId(2L);
50+
assertThat(images.get(0).getId()).isEqualTo(3L);
51+
assertThat(images.get(1).getId()).isEqualTo(4L);
52+
}
4453
}

0 commit comments

Comments
 (0)