diff --git a/src/main/java/nextstep/courses/domain/image/SessionCoverImage.java b/src/main/java/nextstep/courses/domain/image/SessionCoverImage.java index 814e160962..9c8504e88d 100644 --- a/src/main/java/nextstep/courses/domain/image/SessionCoverImage.java +++ b/src/main/java/nextstep/courses/domain/image/SessionCoverImage.java @@ -1,17 +1,41 @@ package nextstep.courses.domain.image; public class SessionCoverImage { + private final Long id; + private final Long sessionId; private final SessionImageDimension dimension; private final SessionImageExtension extension; private final SessionImageCapacity capacity; - public SessionCoverImage(int width, int height, String extension, long bytes) { - this(new SessionImageDimension(width, height), SessionImageExtension.from(extension), new SessionImageCapacity(bytes)); + public SessionCoverImage(Long sessionId, int width, int height, String extension, long bytes) { + this(null, sessionId, new SessionImageDimension(width, height), SessionImageExtension.from(extension), new SessionImageCapacity(bytes)); } - public SessionCoverImage(SessionImageDimension dimension, SessionImageExtension extension, SessionImageCapacity capacity) { + public SessionCoverImage(Long id, Long sessionId, SessionImageDimension dimension, SessionImageExtension extension, SessionImageCapacity capacity) { + this.id = id; + this.sessionId = sessionId; this.dimension = dimension; this.extension = extension; this.capacity = capacity; } + + public Long getId() { + return id; + } + + public Long getSessionId() { + return sessionId; + } + + public SessionImageDimension getDimension() { + return dimension; + } + + public SessionImageExtension getExtension() { + return extension; + } + + public SessionImageCapacity getCapacity() { + return capacity; + } } diff --git a/src/main/java/nextstep/courses/domain/image/SessionImageCapacity.java b/src/main/java/nextstep/courses/domain/image/SessionImageCapacity.java index d9477c35fc..2be95674ca 100644 --- a/src/main/java/nextstep/courses/domain/image/SessionImageCapacity.java +++ b/src/main/java/nextstep/courses/domain/image/SessionImageCapacity.java @@ -26,4 +26,7 @@ private void validate(long bytes) { } } + public long bytes() { + return bytes; + } } diff --git a/src/main/java/nextstep/courses/domain/image/SessionImageDimension.java b/src/main/java/nextstep/courses/domain/image/SessionImageDimension.java index f033bb6351..029bc31da0 100644 --- a/src/main/java/nextstep/courses/domain/image/SessionImageDimension.java +++ b/src/main/java/nextstep/courses/domain/image/SessionImageDimension.java @@ -15,6 +15,7 @@ public SessionImageDimension(int width, int height) { this.width = width; this.height = height; } + private void validateMinLength(int width, int height){ if(!(width >= MIN_WIDTH && height >= MIN_HEIGHT)) { throw new IllegalArgumentException("이미지는 가로 300이상, 세로 200 이상이어야 합니다."); @@ -34,5 +35,11 @@ private int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } + public int width() { + return width; + } + public int height() { + return height; + } } diff --git a/src/main/java/nextstep/courses/domain/image/SessionImageRepository.java b/src/main/java/nextstep/courses/domain/image/SessionImageRepository.java new file mode 100644 index 0000000000..690f73aef6 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/image/SessionImageRepository.java @@ -0,0 +1,9 @@ +package nextstep.courses.domain.image; + +public interface SessionImageRepository { + int save(SessionCoverImage image); + + SessionCoverImage findById(Long id); + + SessionCoverImage findBySessionId(Long sessionId); +} diff --git a/src/main/java/nextstep/courses/domain/registration/Registration.java b/src/main/java/nextstep/courses/domain/registration/Registration.java index b9e25cda08..8de5695db3 100644 --- a/src/main/java/nextstep/courses/domain/registration/Registration.java +++ b/src/main/java/nextstep/courses/domain/registration/Registration.java @@ -1,23 +1,42 @@ package nextstep.courses.domain.registration; import java.time.LocalDateTime; +import java.util.Objects; public class Registration { + private final Long id; private final Long sessionId; private final Long studentId; private final LocalDateTime enrolledAt; public Registration(Long sessionId, Long studentId) { - this(sessionId, studentId, LocalDateTime.now()); + this(null, sessionId, studentId, LocalDateTime.now()); } - public Registration(Long sessionId, Long studentId, LocalDateTime enrolledAt) { + public Registration(Long id, Long sessionId, Long studentId, LocalDateTime enrolledAt) { + this.id = id; this.sessionId = sessionId; this.studentId = studentId; this.enrolledAt = enrolledAt; } + public boolean contains(Long studentId) { - return this.studentId == studentId; + return Objects.equals(this.studentId, studentId); + } + + public Long getId() { + return id; + } + + public Long getSessionId() { + return sessionId; + } + + public Long getStudentId() { + return studentId; } + public LocalDateTime getEnrolledAt() { + return enrolledAt; + } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/registration/RegistrationRepository.java b/src/main/java/nextstep/courses/domain/registration/RegistrationRepository.java new file mode 100644 index 0000000000..6140af2387 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/registration/RegistrationRepository.java @@ -0,0 +1,13 @@ +package nextstep.courses.domain.registration; + +import java.util.List; + +public interface RegistrationRepository { + int save(Registration registration); + + Registration findById(Long id); + + List findBySessionId(Long sessionId); + + int countBySessionId(Long sessionId); +} diff --git a/src/main/java/nextstep/courses/domain/registration/Registrations.java b/src/main/java/nextstep/courses/domain/registration/Registrations.java index d85102f1ab..9413270d13 100644 --- a/src/main/java/nextstep/courses/domain/registration/Registrations.java +++ b/src/main/java/nextstep/courses/domain/registration/Registrations.java @@ -1,33 +1,44 @@ package nextstep.courses.domain.registration; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public class Registrations { - private final List registrations; - - public Registrations() { - this(new ArrayList<>()); - } - - public Registrations(List registrations) { - this.registrations = registrations; - } - - public Registrations add(Registration registration) { - List newList = new ArrayList<>(registrations); - newList.add(registration); - return new Registrations(newList); - } - - public int count() { - return registrations.size(); - } - - public boolean contains(Long studentId) { - return registrations.stream() - .anyMatch(r -> r.contains(studentId)); - } - + private final List registrations; + + public Registrations() { + this(new ArrayList<>()); + } + + public Registrations(List registrations) { + this.registrations = new ArrayList<>(registrations); + } + + public Registrations add(Registration registration) { + validateDuplicateRegistration(registration); + List newList = new ArrayList<>(registrations); + newList.add(registration); + return new Registrations(newList); + } + + private void validateDuplicateRegistration(Registration registration) { + if (isAlreadyRegistered(registration.getStudentId())) { + throw new IllegalArgumentException("이미 수강신청한 학생입니다."); + } + } + + public boolean isAlreadyRegistered(long studentId) { + return registrations.stream() + .anyMatch(registration -> registration.getStudentId().equals(studentId)); + } + + public void validateCapacity(int maxCapacity) { + if (count() > maxCapacity) { + throw new IllegalStateException("최대 수강 인원을 초과할 수 없습니다."); + } + } + + public int count() { + return registrations.size(); + } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/Enrollment.java b/src/main/java/nextstep/courses/domain/session/Enrollment.java index 8349d21eea..65adea88d8 100644 --- a/src/main/java/nextstep/courses/domain/session/Enrollment.java +++ b/src/main/java/nextstep/courses/domain/session/Enrollment.java @@ -1,39 +1,33 @@ package nextstep.courses.domain.session; -import nextstep.courses.domain.session.type.FreeType; -import nextstep.courses.domain.session.type.SessionType; +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.Registrations; public class Enrollment { - private SessionState state; - private SessionType type; - - public Enrollment() { - this(SessionState.PREPARING, new FreeType()); - } - - public Enrollment(SessionType type) { - this(SessionState.PREPARING, type); - } - - public Enrollment(SessionState state, SessionType type) { + private final Session session; + private final SessionState state; + private final SessionPolicy policy; + private final Registrations registrations; + + public Enrollment(Session session, SessionState state, SessionPolicy policy, Registrations registrations) { + validateState(state); + this.session = session; this.state = state; - this.type = type; + this.policy = policy; + this.registrations = registrations; } - public void enroll(long payAmount) { - validateState(); - this.type = type.enroll(payAmount); - } + public Registration enroll(long payAmount, long userId) { + if (registrations.isAlreadyRegistered(userId)) { + throw new IllegalArgumentException("이미 수강신청한 학생입니다."); + } - public void open() { - this.state = state.open(); - } + policy.validate(payAmount, registrations); - public void close() { - this.state = state.close(); + return new Registration(session.getId(), userId); } - private void validateState() { + private void validateState(SessionState state) { if (!state.canEnroll()) { throw new IllegalStateException("모집중인 강의만 수강신청이 가능합니다."); } diff --git a/src/main/java/nextstep/courses/domain/session/Session.java b/src/main/java/nextstep/courses/domain/session/Session.java index a506fbbe29..be99c04c5f 100644 --- a/src/main/java/nextstep/courses/domain/session/Session.java +++ b/src/main/java/nextstep/courses/domain/session/Session.java @@ -1,38 +1,74 @@ package nextstep.courses.domain.session; +import java.util.List; import nextstep.courses.domain.BaseEntity; -import nextstep.courses.domain.course.Course; import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.Registrations; public class Session extends BaseEntity { - private final Course course; - private final Term term; - private final SessionCoverImage cover; - private final SessionPeriod period; - private final Enrollment enrollment; - - public Session(Course course, int term, SessionCoverImage cover, String startDay, String endDay) { - this(null, course, new Term(term), cover, new SessionPeriod(startDay, endDay), new Enrollment()); - } - - public Session(Long id, Course course, Term term, SessionCoverImage cover, SessionPeriod period, Enrollment enrollment) { - super(id); - this.course = course; - this.term = term; - this.cover = cover; - this.period = period; - this.enrollment = enrollment; - } - - public void enroll(long payAmount) { - enrollment.enroll(payAmount); - } - - public void open() { - enrollment.open(); - } - - public void close() { - enrollment.close(); - } + private final Long courseId; + private final Term term; + private final SessionPeriod period; + private final SessionCoverImage coverImage; + private final SessionPolicy sessionPolicy; + private SessionState state; + + public Session(Long courseId, int term, String startDay, String endDay, SessionCoverImage coverImage) { + this(null, courseId, new Term(term), new SessionPeriod(startDay, endDay), SessionState.PREPARING, new SessionPolicy(), coverImage); + } + + public Session(Long courseId, int term, String startDay, String endDay, SessionPolicy sessionPolicy, SessionCoverImage coverImage) { + this(null, courseId, new Term(term), new SessionPeriod(startDay, endDay), SessionState.PREPARING, sessionPolicy, coverImage); + } + + public Session(Long id, Long courseId, Term term, SessionPeriod period, SessionState state, SessionPolicy sessionPolicy, SessionCoverImage coverImage) { + super(id); + this.courseId = courseId; + this.term = term; + this.period = period; + this.state = state; + this.sessionPolicy = sessionPolicy; + this.coverImage = coverImage; + } + + public Enrollment enrollment(Registrations registrations) { + return new Enrollment(this, state, sessionPolicy, registrations); + } + + public Enrollment enrollment(List registrations) { + return new Enrollment(this, state, sessionPolicy, new Registrations(registrations)); + } + + public void open() { + this.state = state.open(); + } + + public void close() { + this.state = state.close(); + } + + public Long getCourseId() { + return courseId; + } + + public Term getTerm() { + return term; + } + + public SessionPeriod getPeriod() { + return period; + } + + public SessionState getState() { + return state; + } + + public SessionPolicy getSessionPolicy() { + return sessionPolicy; + } + + public SessionCoverImage getCoverImage() { + return coverImage; + } } diff --git a/src/main/java/nextstep/courses/domain/session/SessionPeriod.java b/src/main/java/nextstep/courses/domain/session/SessionPeriod.java index af5089b4c3..2cbb6aa3a4 100644 --- a/src/main/java/nextstep/courses/domain/session/SessionPeriod.java +++ b/src/main/java/nextstep/courses/domain/session/SessionPeriod.java @@ -21,4 +21,12 @@ private void validate(LocalDate startDay, LocalDate endDay) { throw new IllegalArgumentException("시작일은 종료일보다 이전이어야 합니다."); } } + + public LocalDate startDay() { + return startDay; + } + + public LocalDate endDay() { + return endDay; + } } diff --git a/src/main/java/nextstep/courses/domain/session/SessionPolicy.java b/src/main/java/nextstep/courses/domain/session/SessionPolicy.java new file mode 100644 index 0000000000..691625e9b9 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/SessionPolicy.java @@ -0,0 +1,57 @@ +package nextstep.courses.domain.session; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.registration.Registrations; +import nextstep.courses.domain.session.policy.capacity.CapacityPolicy; +import nextstep.courses.domain.session.policy.capacity.LimitedCapacity; +import nextstep.courses.domain.session.policy.capacity.UnlimitedCapacity; +import nextstep.courses.domain.session.policy.tuition.FreeTuition; +import nextstep.courses.domain.session.policy.tuition.PaidTuition; +import nextstep.courses.domain.session.policy.tuition.TuitionPolicy; + +public class SessionPolicy { + private final TuitionPolicy tuitionPolicy; + private final CapacityPolicy capacityPolicy; + + public SessionPolicy() { + this(new FreeTuition(), new UnlimitedCapacity()); + } + + public SessionPolicy(long tuitionFee, int maxCapacity) { + this(new PaidTuition(tuitionFee), new LimitedCapacity(maxCapacity)); + } + + public SessionPolicy(TuitionPolicy tuitionPolicy, CapacityPolicy capacityPolicy) { + this.tuitionPolicy = tuitionPolicy; + this.capacityPolicy = capacityPolicy; + } + + public Session createSession(Long courseId, int term, String startDay, String endDay, SessionCoverImage coverImage) { + return new Session(courseId, term, startDay, endDay, this, coverImage); + } + + public Session createSession(Long id, Long courseId, Term term, SessionPeriod period, SessionState state, SessionCoverImage coverImage) { + return new Session(id, courseId, term, period, state, this, coverImage); + } + + public static SessionPolicy free() { + return new SessionPolicy(); + } + + public static SessionPolicy paid(long tuitionFee, int maxCapacity) { + return new SessionPolicy(tuitionFee, maxCapacity); + } + + public void validate(long payAmount, Registrations registrations) { + tuitionPolicy.validate(payAmount); + capacityPolicy.validate(registrations); + } + + public TuitionPolicy getTuitionPolicy() { + return tuitionPolicy; + } + + public CapacityPolicy getCapacityPolicy() { + return capacityPolicy; + } +} diff --git a/src/main/java/nextstep/courses/domain/session/SessionRepository.java b/src/main/java/nextstep/courses/domain/session/SessionRepository.java new file mode 100644 index 0000000000..ec68209ead --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/SessionRepository.java @@ -0,0 +1,10 @@ +package nextstep.courses.domain.session; + +public interface SessionRepository { + + int save(Session session); + + Session findById(Long id); + + int updateState(Long id, SessionState state); +} diff --git a/src/main/java/nextstep/courses/domain/session/policy/capacity/CapacityPolicy.java b/src/main/java/nextstep/courses/domain/session/policy/capacity/CapacityPolicy.java new file mode 100644 index 0000000000..28d04fc4fd --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/capacity/CapacityPolicy.java @@ -0,0 +1,7 @@ +package nextstep.courses.domain.session.policy.capacity; + +import nextstep.courses.domain.registration.Registrations; + +public interface CapacityPolicy { + void validate(Registrations registrations); +} diff --git a/src/main/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacity.java b/src/main/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacity.java new file mode 100644 index 0000000000..4c24396aee --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacity.java @@ -0,0 +1,21 @@ +package nextstep.courses.domain.session.policy.capacity; + +import nextstep.courses.domain.registration.Registrations; + +public class LimitedCapacity implements CapacityPolicy { + private final int maxCapacity; + + public LimitedCapacity(int maxCapacity) { + this.maxCapacity = maxCapacity; + } + + @Override + public void validate(Registrations registrations) { + registrations.validateCapacity(maxCapacity); + } + + public int getMaxCapacity() { + return maxCapacity; + } +} + diff --git a/src/main/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacity.java b/src/main/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacity.java new file mode 100644 index 0000000000..704f6afe49 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacity.java @@ -0,0 +1,10 @@ +package nextstep.courses.domain.session.policy.capacity; + +import nextstep.courses.domain.registration.Registrations; + +public class UnlimitedCapacity implements CapacityPolicy { + + @Override + public void validate(Registrations registrations) { + } +} diff --git a/src/main/java/nextstep/courses/domain/session/policy/tuition/FreeTuition.java b/src/main/java/nextstep/courses/domain/session/policy/tuition/FreeTuition.java new file mode 100644 index 0000000000..2d5b1f2556 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/tuition/FreeTuition.java @@ -0,0 +1,11 @@ +package nextstep.courses.domain.session.policy.tuition; + + +public class FreeTuition implements TuitionPolicy { + + @Override + public void validate(long payAmount) { + // 무료 강의는 수강료 검증 없음, 정원 제한 없음 + } + +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/policy/tuition/PaidTuition.java b/src/main/java/nextstep/courses/domain/session/policy/tuition/PaidTuition.java new file mode 100644 index 0000000000..66c4f65a5a --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/tuition/PaidTuition.java @@ -0,0 +1,20 @@ +package nextstep.courses.domain.session.policy.tuition; + +public class PaidTuition implements TuitionPolicy { + private final long tuitionFee; + + public PaidTuition(long tuitionFee) { + this.tuitionFee = tuitionFee; + } + + @Override + public void validate(long payAmount) { + if (payAmount != tuitionFee) { + throw new IllegalArgumentException("수강료와 지불한 금액이 정확히 일치해야 합니다."); + } + } + + public long getTuitionFee() { + return tuitionFee; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/policy/tuition/TuitionPolicy.java b/src/main/java/nextstep/courses/domain/session/policy/tuition/TuitionPolicy.java new file mode 100644 index 0000000000..57f416186c --- /dev/null +++ b/src/main/java/nextstep/courses/domain/session/policy/tuition/TuitionPolicy.java @@ -0,0 +1,5 @@ +package nextstep.courses.domain.session.policy.tuition; + +public interface TuitionPolicy { + void validate(long payAmount); +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/type/FreeType.java b/src/main/java/nextstep/courses/domain/session/type/FreeType.java deleted file mode 100644 index b6b425d1af..0000000000 --- a/src/main/java/nextstep/courses/domain/session/type/FreeType.java +++ /dev/null @@ -1,9 +0,0 @@ -package nextstep.courses.domain.session.type; - -public class FreeType implements SessionType { - - @Override - public SessionType enroll(long payAmount) { - return this; - } -} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/type/PaidType.java b/src/main/java/nextstep/courses/domain/session/type/PaidType.java deleted file mode 100644 index dc680bca29..0000000000 --- a/src/main/java/nextstep/courses/domain/session/type/PaidType.java +++ /dev/null @@ -1,55 +0,0 @@ -package nextstep.courses.domain.session.type; - -import java.util.Objects; - -public class PaidType implements SessionType { - private final int maxCapacity; - private final long tuitionFee; - private final int studentCount; - - public PaidType(int maxCapacity, long tuitionFee) { - this(maxCapacity, tuitionFee, 0); - } - - public PaidType(int maxCapacity, long tuitionFee, int studentCount) { - validateCapacity(maxCapacity, studentCount); - this.maxCapacity = maxCapacity; - this.tuitionFee = tuitionFee; - this.studentCount = studentCount; - } - - @Override - public SessionType enroll(long payAmount) { - int newCount = studentCount + 1; - validateCapacity(maxCapacity, newCount); - validateTuitionFee(payAmount); - return new PaidType(maxCapacity, tuitionFee, newCount); - } - - private void validateCapacity(int maxCapacity, int studentCount) { - if (maxCapacity < studentCount) { - throw new IllegalArgumentException("최대 수강 인원을 초과할 수 없습니다."); - } - } - - private void validateTuitionFee(long payAmount) { - if (payAmount != tuitionFee) { - throw new IllegalArgumentException("수강료와 지불한 금액이 정확히 일치해야 합니다."); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - PaidType that = (PaidType) o; - return maxCapacity == that.maxCapacity - && tuitionFee == that.tuitionFee - && studentCount == that.studentCount; - } - - @Override - public int hashCode() { - return Objects.hash(maxCapacity, tuitionFee, studentCount); - } -} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/session/type/SessionType.java b/src/main/java/nextstep/courses/domain/session/type/SessionType.java deleted file mode 100644 index 3998c88427..0000000000 --- a/src/main/java/nextstep/courses/domain/session/type/SessionType.java +++ /dev/null @@ -1,5 +0,0 @@ -package nextstep.courses.domain.session.type; - -public interface SessionType { - SessionType enroll(long payAmount); -} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/CourseRepositoryImpl.java b/src/main/java/nextstep/courses/infrastructure/CourseRepositoryImpl.java new file mode 100644 index 0000000000..c3754181bf --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/CourseRepositoryImpl.java @@ -0,0 +1,29 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.course.Course; +import nextstep.courses.domain.course.CourseRepository; +import nextstep.courses.infrastructure.entity.CourseEntity; +import nextstep.courses.infrastructure.jdbc.CourseJdbcDao; +import nextstep.courses.infrastructure.mapper.CourseMapper; +import org.springframework.stereotype.Repository; + +@Repository("courseRepository") +public class CourseRepositoryImpl implements CourseRepository { + private final CourseJdbcDao courseJdbcDao; + + public CourseRepositoryImpl(CourseJdbcDao courseJdbcDao) { + this.courseJdbcDao = courseJdbcDao; + } + + @Override + public int save(Course course) { + CourseEntity entity = CourseMapper.toEntity(course); + return courseJdbcDao.save(entity); + } + + @Override + public Course findById(Long id) { + CourseEntity entity = courseJdbcDao.findById(id); + return CourseMapper.toDomain(entity); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java b/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java deleted file mode 100644 index 7489afc31d..0000000000 --- a/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java +++ /dev/null @@ -1,44 +0,0 @@ -package nextstep.courses.infrastructure; - -import nextstep.courses.domain.course.Course; -import nextstep.courses.domain.course.CourseRepository; -import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Repository; - -import java.sql.Timestamp; -import java.time.LocalDateTime; - -@Repository("courseRepository") -public class JdbcCourseRepository implements CourseRepository { - private JdbcOperations jdbcTemplate; - - public JdbcCourseRepository(JdbcOperations jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - @Override - public int save(Course course) { - String sql = "insert into course (title, creator_id, created_at) values(?, ?, ?)"; - return jdbcTemplate.update(sql, course.getTitle(), course.getCreatorId(), course.getCreatedAt()); - } - - @Override - public Course findById(Long id) { - String sql = "select id, title, creator_id, created_at, updated_at from course where id = ?"; - RowMapper rowMapper = (rs, rowNum) -> new Course( - rs.getLong(1), - rs.getString(2), - rs.getLong(3), - toLocalDateTime(rs.getTimestamp(4)), - toLocalDateTime(rs.getTimestamp(5))); - return jdbcTemplate.queryForObject(sql, rowMapper, id); - } - - private LocalDateTime toLocalDateTime(Timestamp timestamp) { - if (timestamp == null) { - return null; - } - return timestamp.toLocalDateTime(); - } -} diff --git a/src/main/java/nextstep/courses/infrastructure/RegistrationRepositoryImpl.java b/src/main/java/nextstep/courses/infrastructure/RegistrationRepositoryImpl.java new file mode 100644 index 0000000000..d3fa91bd78 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/RegistrationRepositoryImpl.java @@ -0,0 +1,44 @@ +package nextstep.courses.infrastructure; + +import java.util.List; +import java.util.stream.Collectors; +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.RegistrationRepository; +import nextstep.courses.infrastructure.entity.RegistrationEntity; +import nextstep.courses.infrastructure.jdbc.RegistrationJdbcDao; +import nextstep.courses.infrastructure.mapper.RegistrationMapper; +import org.springframework.stereotype.Repository; + +@Repository("registrationRepository") +public class RegistrationRepositoryImpl implements RegistrationRepository { + private final RegistrationJdbcDao registrationJdbcDao; + + public RegistrationRepositoryImpl(RegistrationJdbcDao registrationJdbcDao) { + this.registrationJdbcDao = registrationJdbcDao; + } + + @Override + public int save(Registration registration) { + RegistrationEntity entity = RegistrationMapper.toEntity(registration); + return registrationJdbcDao.save(entity); + } + + @Override + public Registration findById(Long id) { + RegistrationEntity entity = registrationJdbcDao.findById(id); + return RegistrationMapper.toDomain(entity); + } + + @Override + public List findBySessionId(Long sessionId) { + List entities = registrationJdbcDao.findBySessionId(sessionId); + return entities.stream() + .map(RegistrationMapper::toDomain) + .collect(Collectors.toList()); + } + + @Override + public int countBySessionId(Long sessionId) { + return registrationJdbcDao.countBySessionId(sessionId); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/SessionImageRepositoryImpl.java b/src/main/java/nextstep/courses/infrastructure/SessionImageRepositoryImpl.java new file mode 100644 index 0000000000..715ff6bd2a --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/SessionImageRepositoryImpl.java @@ -0,0 +1,35 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.image.SessionImageRepository; +import nextstep.courses.infrastructure.entity.SessionCoverImageEntity; +import nextstep.courses.infrastructure.jdbc.SessionImageJdbcDao; +import nextstep.courses.infrastructure.mapper.SessionCoverImageMapper; +import org.springframework.stereotype.Repository; + +@Repository("sessionImageRepository") +public class SessionImageRepositoryImpl implements SessionImageRepository { + private final SessionImageJdbcDao sessionImageJdbcDao; + + public SessionImageRepositoryImpl(SessionImageJdbcDao sessionImageJdbcDao) { + this.sessionImageJdbcDao = sessionImageJdbcDao; + } + + @Override + public int save(SessionCoverImage image) { + SessionCoverImageEntity entity = SessionCoverImageMapper.toEntity(image); + return sessionImageJdbcDao.save(entity); + } + + @Override + public SessionCoverImage findById(Long id) { + SessionCoverImageEntity entity = sessionImageJdbcDao.findById(id); + return SessionCoverImageMapper.toDomain(entity); + } + + @Override + public SessionCoverImage findBySessionId(Long sessionId) { + SessionCoverImageEntity entity = sessionImageJdbcDao.findBySessionId(sessionId); + return SessionCoverImageMapper.toDomain(entity); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/SessionRepositoryImpl.java b/src/main/java/nextstep/courses/infrastructure/SessionRepositoryImpl.java new file mode 100644 index 0000000000..f0cda8b5c4 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/SessionRepositoryImpl.java @@ -0,0 +1,47 @@ +package nextstep.courses.infrastructure; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionRepository; +import nextstep.courses.domain.session.SessionState; +import nextstep.courses.infrastructure.entity.SessionCoverImageEntity; +import nextstep.courses.infrastructure.entity.SessionEntity; +import nextstep.courses.infrastructure.jdbc.SessionJdbcDao; +import nextstep.courses.infrastructure.mapper.SessionCoverImageMapper; +import nextstep.courses.infrastructure.mapper.SessionMapper; +import org.springframework.stereotype.Repository; + +@Repository("sessionRepository") +public class SessionRepositoryImpl implements SessionRepository { + private final SessionJdbcDao sessionJdbcDao; + + public SessionRepositoryImpl(SessionJdbcDao sessionJdbcDao) { + this.sessionJdbcDao = sessionJdbcDao; + } + + @Override + public int save(Session session) { + SessionEntity entity = SessionMapper.toEntity(session); + return sessionJdbcDao.save(entity); + } + + @Override + public Session findById(Long id) { + SessionEntity entity = sessionJdbcDao.findById(id); + SessionCoverImage coverImage = findCoverImageBySessionId(id); + return SessionMapper.toDomain(entity, coverImage); + } + + private SessionCoverImage findCoverImageBySessionId(Long sessionId) { + SessionCoverImageEntity entity = sessionJdbcDao.findCoverImageBySessionId(sessionId); + if (entity == null) { + return null; + } + return SessionCoverImageMapper.toDomain(entity); + } + + @Override + public int updateState(Long id, SessionState state) { + return sessionJdbcDao.updateState(id, state); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/entity/CourseEntity.java b/src/main/java/nextstep/courses/infrastructure/entity/CourseEntity.java new file mode 100644 index 0000000000..ef47e4582d --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/entity/CourseEntity.java @@ -0,0 +1,39 @@ +package nextstep.courses.infrastructure.entity; + +import java.time.LocalDateTime; + +public class CourseEntity { + private final Long id; + private final String title; + private final Long creatorId; + private final LocalDateTime createdAt; + private final LocalDateTime updatedAt; + + public CourseEntity(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { + this.id = id; + this.title = title; + this.creatorId = creatorId; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + public Long getId() { + return id; + } + + public String getTitle() { + return title; + } + + public Long getCreatorId() { + return creatorId; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/entity/RegistrationEntity.java b/src/main/java/nextstep/courses/infrastructure/entity/RegistrationEntity.java new file mode 100644 index 0000000000..418eac3ad5 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/entity/RegistrationEntity.java @@ -0,0 +1,33 @@ +package nextstep.courses.infrastructure.entity; + +import java.time.LocalDateTime; + +public class RegistrationEntity { + private final Long id; + private final Long sessionId; + private final Long studentId; + private final LocalDateTime enrolledAt; + + public RegistrationEntity(Long id, Long sessionId, Long studentId, LocalDateTime enrolledAt) { + this.id = id; + this.sessionId = sessionId; + this.studentId = studentId; + this.enrolledAt = enrolledAt; + } + + public Long getId() { + return id; + } + + public Long getSessionId() { + return sessionId; + } + + public Long getStudentId() { + return studentId; + } + + public LocalDateTime getEnrolledAt() { + return enrolledAt; + } +} diff --git a/src/main/java/nextstep/courses/infrastructure/entity/SessionCoverImageEntity.java b/src/main/java/nextstep/courses/infrastructure/entity/SessionCoverImageEntity.java new file mode 100644 index 0000000000..5dba4f9985 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/entity/SessionCoverImageEntity.java @@ -0,0 +1,43 @@ +package nextstep.courses.infrastructure.entity; + +public class SessionCoverImageEntity { + private final Long id; + private final Long sessionId; + private final int width; + private final int height; + private final String extension; + private final long capacity; + + public SessionCoverImageEntity(Long id, Long sessionId, int width, int height, String extension, long capacity) { + this.id = id; + this.sessionId = sessionId; + this.width = width; + this.height = height; + this.extension = extension; + this.capacity = capacity; + } + + public Long getId() { + return id; + } + + public Long getSessionId() { + return sessionId; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public String getExtension() { + return extension; + } + + public long getCapacity() { + return capacity; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/entity/SessionEntity.java b/src/main/java/nextstep/courses/infrastructure/entity/SessionEntity.java new file mode 100644 index 0000000000..f64ae044b0 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/entity/SessionEntity.java @@ -0,0 +1,72 @@ +package nextstep.courses.infrastructure.entity; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class SessionEntity { + private final Long id; + private final Long courseId; + private final int term; + private final LocalDate startDay; + private final LocalDate endDay; + private final String state; + private final String type; + private final Integer maxCapacity; + private final Long tuitionFee; + private final LocalDateTime createdAt; + + public SessionEntity(Long id, Long courseId, int term, LocalDate startDay, LocalDate endDay, + String state, String type, Integer maxCapacity, Long tuitionFee, + LocalDateTime createdAt) { + this.id = id; + this.courseId = courseId; + this.term = term; + this.startDay = startDay; + this.endDay = endDay; + this.state = state; + this.type = type; + this.maxCapacity = maxCapacity; + this.tuitionFee = tuitionFee; + this.createdAt = createdAt; + } + + public Long getId() { + return id; + } + + public Long getCourseId() { + return courseId; + } + + public int getTerm() { + return term; + } + + public LocalDate getStartDay() { + return startDay; + } + + public LocalDate getEndDay() { + return endDay; + } + + public String getState() { + return state; + } + + public String getType() { + return type; + } + + public Integer getMaxCapacity() { + return maxCapacity; + } + + public Long getTuitionFee() { + return tuitionFee; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/jdbc/CourseJdbcDao.java b/src/main/java/nextstep/courses/infrastructure/jdbc/CourseJdbcDao.java new file mode 100644 index 0000000000..1955e03da9 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/jdbc/CourseJdbcDao.java @@ -0,0 +1,44 @@ +package nextstep.courses.infrastructure.jdbc; + +import java.sql.Timestamp; +import java.time.LocalDateTime; +import nextstep.courses.infrastructure.entity.CourseEntity; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class CourseJdbcDao { + private final JdbcOperations jdbcTemplate; + + public CourseJdbcDao(JdbcOperations jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public int save(CourseEntity entity) { + String sql = "insert into course (title, creator_id, created_at) values(?, ?, ?)"; + return jdbcTemplate.update(sql, entity.getTitle(), entity.getCreatorId(), entity.getCreatedAt()); + } + + public CourseEntity findById(Long id) { + String sql = "select id, title, creator_id, created_at, updated_at from course where id = ?"; + return jdbcTemplate.queryForObject(sql, rowMapper(), id); + } + + private RowMapper rowMapper() { + return (rs, rowNum) -> new CourseEntity( + rs.getLong("id"), + rs.getString("title"), + rs.getLong("creator_id"), + toLocalDateTime(rs.getTimestamp("created_at")), + toLocalDateTime(rs.getTimestamp("updated_at")) + ); + } + + private LocalDateTime toLocalDateTime(Timestamp timestamp) { + if (timestamp == null) { + return null; + } + return timestamp.toLocalDateTime(); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/jdbc/RegistrationJdbcDao.java b/src/main/java/nextstep/courses/infrastructure/jdbc/RegistrationJdbcDao.java new file mode 100644 index 0000000000..8112b75060 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/jdbc/RegistrationJdbcDao.java @@ -0,0 +1,51 @@ +package nextstep.courses.infrastructure.jdbc; + +import java.sql.Timestamp; +import java.util.List; +import nextstep.courses.infrastructure.entity.RegistrationEntity; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class RegistrationJdbcDao { + private final JdbcOperations jdbcTemplate; + + public RegistrationJdbcDao(JdbcOperations jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public int save(RegistrationEntity entity) { + String sql = "insert into registration (session_id, student_id, enrolled_at) values(?, ?, ?)"; + + return jdbcTemplate.update(sql, + entity.getSessionId(), + entity.getStudentId(), + Timestamp.valueOf(entity.getEnrolledAt()) + ); + } + + public RegistrationEntity findById(Long id) { + String sql = "select id, session_id, student_id, enrolled_at from registration where id = ?"; + return jdbcTemplate.queryForObject(sql, rowMapper(), id); + } + + public List findBySessionId(Long sessionId) { + String sql = "select id, session_id, student_id, enrolled_at from registration where session_id = ?"; + return jdbcTemplate.query(sql, rowMapper(), sessionId); + } + + public int countBySessionId(Long sessionId) { + String sql = "select count(*) from registration where session_id = ?"; + return jdbcTemplate.queryForObject(sql, Integer.class, sessionId); + } + + private RowMapper rowMapper() { + return (rs, rowNum) -> new RegistrationEntity( + rs.getLong("id"), + rs.getLong("session_id"), + rs.getLong("student_id"), + rs.getTimestamp("enrolled_at").toLocalDateTime() + ); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/jdbc/SessionImageJdbcDao.java b/src/main/java/nextstep/courses/infrastructure/jdbc/SessionImageJdbcDao.java new file mode 100644 index 0000000000..195f27c611 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/jdbc/SessionImageJdbcDao.java @@ -0,0 +1,48 @@ +package nextstep.courses.infrastructure.jdbc; + +import nextstep.courses.infrastructure.entity.SessionCoverImageEntity; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class SessionImageJdbcDao { + private final JdbcOperations jdbcTemplate; + + public SessionImageJdbcDao(JdbcOperations jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public int save(SessionCoverImageEntity entity) { + String sql = "insert into session_cover_image (session_id, width, height, extension, capacity) values(?, ?, ?, ?, ?)"; + + return jdbcTemplate.update(sql, + entity.getSessionId(), + entity.getWidth(), + entity.getHeight(), + entity.getExtension(), + entity.getCapacity() + ); + } + + public SessionCoverImageEntity findById(Long id) { + String sql = "select id, session_id, width, height, extension, capacity from session_cover_image where id = ?"; + return jdbcTemplate.queryForObject(sql, rowMapper(), id); + } + + public SessionCoverImageEntity findBySessionId(Long sessionId) { + String sql = "select id, session_id, width, height, extension, capacity from session_cover_image where session_id = ?"; + return jdbcTemplate.queryForObject(sql, rowMapper(), sessionId); + } + + private RowMapper rowMapper() { + return (rs, rowNum) -> new SessionCoverImageEntity( + rs.getLong("id"), + rs.getLong("session_id"), + rs.getInt("width"), + rs.getInt("height"), + rs.getString("extension"), + rs.getLong("capacity") + ); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/jdbc/SessionJdbcDao.java b/src/main/java/nextstep/courses/infrastructure/jdbc/SessionJdbcDao.java new file mode 100644 index 0000000000..6cc9987a21 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/jdbc/SessionJdbcDao.java @@ -0,0 +1,115 @@ +package nextstep.courses.infrastructure.jdbc; + +import java.sql.Date; +import java.time.LocalDate; +import java.util.List; +import nextstep.courses.domain.session.SessionState; +import nextstep.courses.infrastructure.entity.RegistrationEntity; +import nextstep.courses.infrastructure.entity.SessionCoverImageEntity; +import nextstep.courses.infrastructure.entity.SessionEntity; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcOperations; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +@Component +public class SessionJdbcDao { + private final JdbcOperations jdbcTemplate; + + public SessionJdbcDao(JdbcOperations jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public int save(SessionEntity entity) { + String sql = "insert into session (course_id, term, start_day, end_day, state, type, max_capacity, tuition_fee, created_at) values(?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + return jdbcTemplate.update(sql, + entity.getCourseId(), + entity.getTerm(), + Date.valueOf(entity.getStartDay()), + Date.valueOf(entity.getEndDay()), + entity.getState(), + entity.getType(), + entity.getMaxCapacity(), + entity.getTuitionFee(), + entity.getCreatedAt() + ); + } + + public int saveCoverImage(SessionCoverImageEntity image) { + String sql = "insert into session_cover_image (session_id, width, height, extension, capacity) values(?, ?, ?, ?, ?)"; + return jdbcTemplate.update(sql, + image.getSessionId(), + image.getWidth(), + image.getHeight(), + image.getExtension(), + image.getCapacity() + ); + } + + public SessionEntity findById(Long id) { + String sql = "select id, course_id, term, start_day, end_day, state, type, max_capacity, tuition_fee, created_at from session where id = ?"; + return jdbcTemplate.queryForObject(sql, sessionRowMapper(), id); + } + + public SessionCoverImageEntity findCoverImageBySessionId(Long sessionId) { + String sql = "select id, session_id, width, height, extension, capacity from session_cover_image where session_id = ?"; + try { + return jdbcTemplate.queryForObject(sql, coverImageRowMapper(), sessionId); + } catch (EmptyResultDataAccessException e) { + return null; + } + } + + public List findRegistrationsBySessionId(Long sessionId) { + String sql = "select id, session_id, student_id, enrolled_at from registration where session_id = ?"; + return jdbcTemplate.query(sql, registrationRowMapper(), sessionId); + } + + public int updateState(Long id, SessionState state) { + String sql = "update session set state = ? where id = ?"; + return jdbcTemplate.update(sql, state.name(), id); + } + + private RowMapper sessionRowMapper() { + return (rs, rowNum) -> new SessionEntity( + rs.getLong("id"), + rs.getLong("course_id"), + rs.getInt("term"), + toLocalDate(rs.getDate("start_day")), + toLocalDate(rs.getDate("end_day")), + rs.getString("state"), + rs.getString("type"), + rs.getObject("max_capacity", Integer.class), + rs.getObject("tuition_fee", Long.class), + rs.getTimestamp("created_at") != null ? rs.getTimestamp("created_at").toLocalDateTime() : null + ); + } + + private RowMapper coverImageRowMapper() { + return (rs, rowNum) -> new SessionCoverImageEntity( + rs.getLong("id"), + rs.getLong("session_id"), + rs.getInt("width"), + rs.getInt("height"), + rs.getString("extension"), + rs.getLong("capacity") + ); + } + + private RowMapper registrationRowMapper() { + return (rs, rowNum) -> new RegistrationEntity( + rs.getLong("id"), + rs.getLong("session_id"), + rs.getLong("student_id"), + rs.getTimestamp("enrolled_at").toLocalDateTime() + ); + } + + private LocalDate toLocalDate(Date date) { + if (date == null) { + return null; + } + return date.toLocalDate(); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/mapper/CourseMapper.java b/src/main/java/nextstep/courses/infrastructure/mapper/CourseMapper.java new file mode 100644 index 0000000000..bbbb938b83 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/mapper/CourseMapper.java @@ -0,0 +1,30 @@ +package nextstep.courses.infrastructure.mapper; + +import nextstep.courses.domain.course.Course; +import nextstep.courses.infrastructure.entity.CourseEntity; + +public class CourseMapper { + + private CourseMapper() { + } + + public static CourseEntity toEntity(Course course) { + return new CourseEntity( + course.getId(), + course.getTitle(), + course.getCreatorId(), + course.getCreatedAt(), + course.getUpdatedAt() + ); + } + + public static Course toDomain(CourseEntity entity) { + return new Course( + entity.getId(), + entity.getTitle(), + entity.getCreatorId(), + entity.getCreatedAt(), + entity.getUpdatedAt() + ); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/infrastructure/mapper/RegistrationMapper.java b/src/main/java/nextstep/courses/infrastructure/mapper/RegistrationMapper.java new file mode 100644 index 0000000000..e2780568a8 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/mapper/RegistrationMapper.java @@ -0,0 +1,32 @@ +package nextstep.courses.infrastructure.mapper; + +import java.util.List; +import java.util.stream.Collectors; +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.Registrations; +import nextstep.courses.infrastructure.entity.RegistrationEntity; + +public class RegistrationMapper { + + private RegistrationMapper() { + } + + public static RegistrationEntity toEntity(Registration registration) { + return new RegistrationEntity( + registration.getId(), + registration.getSessionId(), + registration.getStudentId(), + registration.getEnrolledAt() + ); + } + + public static Registration toDomain(RegistrationEntity entity) { + return new Registration( + entity.getId(), + entity.getSessionId(), + entity.getStudentId(), + entity.getEnrolledAt() + ); + } + +} diff --git a/src/main/java/nextstep/courses/infrastructure/mapper/SessionCoverImageMapper.java b/src/main/java/nextstep/courses/infrastructure/mapper/SessionCoverImageMapper.java new file mode 100644 index 0000000000..58348743ac --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/mapper/SessionCoverImageMapper.java @@ -0,0 +1,34 @@ +package nextstep.courses.infrastructure.mapper; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.image.SessionImageCapacity; +import nextstep.courses.domain.image.SessionImageDimension; +import nextstep.courses.domain.image.SessionImageExtension; +import nextstep.courses.infrastructure.entity.SessionCoverImageEntity; + +public class SessionCoverImageMapper { + + private SessionCoverImageMapper() { + } + + public static SessionCoverImageEntity toEntity(SessionCoverImage image) { + return new SessionCoverImageEntity( + image.getId(), + image.getSessionId(), + image.getDimension().width(), + image.getDimension().height(), + image.getExtension().name(), + image.getCapacity().bytes() + ); + } + + public static SessionCoverImage toDomain(SessionCoverImageEntity entity) { + return new SessionCoverImage( + entity.getId(), + entity.getSessionId(), + new SessionImageDimension(entity.getWidth(), entity.getHeight()), + SessionImageExtension.valueOf(entity.getExtension()), + new SessionImageCapacity(entity.getCapacity()) + ); + } +} diff --git a/src/main/java/nextstep/courses/infrastructure/mapper/SessionMapper.java b/src/main/java/nextstep/courses/infrastructure/mapper/SessionMapper.java new file mode 100644 index 0000000000..de1e935ba2 --- /dev/null +++ b/src/main/java/nextstep/courses/infrastructure/mapper/SessionMapper.java @@ -0,0 +1,90 @@ +package nextstep.courses.infrastructure.mapper; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionPeriod; +import nextstep.courses.domain.session.SessionPolicy; +import nextstep.courses.domain.session.SessionState; +import nextstep.courses.domain.session.Term; +import nextstep.courses.domain.session.policy.capacity.CapacityPolicy; +import nextstep.courses.domain.session.policy.capacity.LimitedCapacity; +import nextstep.courses.domain.session.policy.capacity.UnlimitedCapacity; +import nextstep.courses.domain.session.policy.tuition.FreeTuition; +import nextstep.courses.domain.session.policy.tuition.PaidTuition; +import nextstep.courses.domain.session.policy.tuition.TuitionPolicy; +import nextstep.courses.infrastructure.entity.SessionEntity; + +public class SessionMapper { + + private SessionMapper() { + } + + public static SessionEntity toEntity(Session session) { + SessionPolicy sessionPolicy = session.getSessionPolicy(); + TuitionPolicy tuitionPolicy = sessionPolicy.getTuitionPolicy(); + CapacityPolicy capacityPolicy = sessionPolicy.getCapacityPolicy(); + + Integer maxCapacity = null; + Long tuitionFee = null; + String typeName = "FREE"; + + if (tuitionPolicy instanceof PaidTuition) { + PaidTuition paidTuition = (PaidTuition) tuitionPolicy; + tuitionFee = paidTuition.getTuitionFee(); + typeName = "PAID"; + } + + if (capacityPolicy instanceof LimitedCapacity) { + LimitedCapacity limitedCapacity = (LimitedCapacity) capacityPolicy; + maxCapacity = limitedCapacity.getMaxCapacity(); + } + + return new SessionEntity( + session.getId(), + session.getCourseId(), + session.getTerm().getValue(), + session.getPeriod().startDay(), + session.getPeriod().endDay(), + session.getState().name(), + typeName, + maxCapacity, + tuitionFee, + session.getCreatedAt() + ); + } + + public static Session toDomain(SessionEntity entity, SessionCoverImage coverImage) { + SessionPeriod period = new SessionPeriod(entity.getStartDay(), entity.getEndDay()); + SessionState state = SessionState.valueOf(entity.getState()); + SessionPolicy sessionPolicy = createSessionPolicy(entity); + + return sessionPolicy.createSession( + entity.getId(), + entity.getCourseId(), + new Term(entity.getTerm()), + period, + state, + coverImage + ); + } + + private static SessionPolicy createSessionPolicy(SessionEntity entity) { + TuitionPolicy tuitionPolicy = createTuitionPolicy(entity); + CapacityPolicy capacityPolicy = createCapacityPolicy(entity); + return new SessionPolicy(tuitionPolicy, capacityPolicy); + } + + private static TuitionPolicy createTuitionPolicy(SessionEntity entity) { + if ("PAID".equals(entity.getType())) { + return new PaidTuition(entity.getTuitionFee()); + } + return new FreeTuition(); + } + + private static CapacityPolicy createCapacityPolicy(SessionEntity entity) { + if (entity.getMaxCapacity() != null) { + return new LimitedCapacity(entity.getMaxCapacity()); + } + return new UnlimitedCapacity(); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/service/CourseManageService.java b/src/main/java/nextstep/courses/service/CourseManageService.java new file mode 100644 index 0000000000..6a3196416c --- /dev/null +++ b/src/main/java/nextstep/courses/service/CourseManageService.java @@ -0,0 +1,24 @@ +package nextstep.courses.service; + +import nextstep.courses.domain.course.Course; +import nextstep.courses.domain.course.CourseRepository; +import org.springframework.stereotype.Service; + +@Service +public class CourseManageService { + + private final CourseRepository courseRepository; + + public CourseManageService(CourseRepository courseRepository) { + this.courseRepository = courseRepository; + } + + public void createCourse(String title, Long creatorId) { + Course course = new Course(title, creatorId); + courseRepository.save(course); + } + + public Course findById(Long id) { + return courseRepository.findById(id); + } +} diff --git a/src/main/java/nextstep/courses/service/RegistrationService.java b/src/main/java/nextstep/courses/service/RegistrationService.java new file mode 100644 index 0000000000..3698239750 --- /dev/null +++ b/src/main/java/nextstep/courses/service/RegistrationService.java @@ -0,0 +1,34 @@ +package nextstep.courses.service; + +import java.util.List; +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.RegistrationRepository; +import nextstep.courses.domain.registration.Registrations; +import nextstep.courses.domain.session.Enrollment; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionRepository; +import nextstep.payments.domain.Payment; +import org.springframework.stereotype.Service; + +@Service +public class RegistrationService { + + private final SessionRepository sessionRepository; + private final RegistrationRepository registrationRepository; + + public RegistrationService(SessionRepository sessionRepository, + RegistrationRepository registrationRepository) { + this.sessionRepository = sessionRepository; + this.registrationRepository = registrationRepository; + } + + public void register(Payment payment) { + Session session = sessionRepository.findById(payment.getSessionId()); + List registered = registrationRepository.findBySessionId(session.getId()); + + Enrollment enrollment = session.enrollment(registered); + Registration registration = enrollment.enroll(payment.getAmount(), payment.getNsUserId()); + + registrationRepository.save(registration); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/service/SessionEnrollService.java b/src/main/java/nextstep/courses/service/SessionEnrollService.java deleted file mode 100644 index 5b12a385a7..0000000000 --- a/src/main/java/nextstep/courses/service/SessionEnrollService.java +++ /dev/null @@ -1,16 +0,0 @@ -package nextstep.courses.service; - -import nextstep.courses.domain.course.CourseRepository; -import nextstep.courses.domain.session.Session; -import nextstep.payments.domain.Payment; -import org.springframework.stereotype.Service; - -@Service -public class SessionEnrollService { - private CourseRepository courseRepository; - - public void enroll(Session session, Payment payment){ - session.enroll(payment.getAmount()); - } - -} diff --git a/src/main/java/nextstep/courses/service/SessionManageService.java b/src/main/java/nextstep/courses/service/SessionManageService.java new file mode 100644 index 0000000000..096faf9241 --- /dev/null +++ b/src/main/java/nextstep/courses/service/SessionManageService.java @@ -0,0 +1,50 @@ +package nextstep.courses.service; + +import nextstep.courses.domain.image.SessionCoverImage; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionPolicy; +import nextstep.courses.domain.session.SessionRepository; +import org.springframework.stereotype.Service; + +@Service +public class SessionManageService { + + private final SessionRepository sessionRepository; + + public SessionManageService(SessionRepository sessionRepository) { + this.sessionRepository = sessionRepository; + } + + public void createFreeSession(Long courseId, int term, String startDay, String endDay, + int imageWidth, int imageHeight, String imageExtension, long imageBytes) { + SessionCoverImage coverImage = new SessionCoverImage(null, imageWidth, imageHeight, imageExtension, imageBytes); + SessionPolicy sessionPolicy = SessionPolicy.free(); + Session session = sessionPolicy.createSession(courseId, term, startDay, endDay, coverImage); + sessionRepository.save(session); + } + + public void createPaidSession(Long courseId, int term, String startDay, String endDay, + int maxCapacity, long tuitionFee, + int imageWidth, int imageHeight, String imageExtension, long imageBytes) { + SessionCoverImage coverImage = new SessionCoverImage(null, imageWidth, imageHeight, imageExtension, imageBytes); + SessionPolicy sessionPolicy = SessionPolicy.paid(tuitionFee, maxCapacity); + Session session = sessionPolicy.createSession(courseId, term, startDay, endDay, coverImage); + sessionRepository.save(session); + } + + public void openSession(Long sessionId) { + Session session = sessionRepository.findById(sessionId); + session.open(); + sessionRepository.updateState(sessionId, session.getState()); + } + + public void closeSession(Long sessionId) { + Session session = sessionRepository.findById(sessionId); + session.close(); + sessionRepository.updateState(sessionId, session.getState()); + } + + public Session findById(Long sessionId) { + return sessionRepository.findById(sessionId); + } +} \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 8d5a988c8b..42c3963afb 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -48,3 +48,36 @@ create table delete_history ( deleted_by_id bigint, primary key (id) ); + +create table session ( + id bigint generated by default as identity, + course_id bigint not null, + term int not null, + start_day date not null, + end_day date not null, + state varchar(20) not null, + type varchar(10) not null, + max_capacity int, + tuition_fee bigint, + created_at timestamp not null, + updated_at timestamp, + primary key (id) +); + +create table session_cover_image ( + id bigint generated by default as identity, + session_id bigint not null, + width int not null, + height int not null, + extension varchar(10) not null, + capacity bigint not null, + primary key (id) +); + +create table registration ( + id bigint generated by default as identity, + session_id bigint not null, + student_id bigint not null, + enrolled_at timestamp not null, + primary key (id) +); diff --git a/src/test/java/nextstep/courses/domain/image/SessionCoverImageTest.java b/src/test/java/nextstep/courses/domain/image/SessionCoverImageTest.java index 795afcfeee..b5e5f57d4e 100644 --- a/src/test/java/nextstep/courses/domain/image/SessionCoverImageTest.java +++ b/src/test/java/nextstep/courses/domain/image/SessionCoverImageTest.java @@ -7,22 +7,21 @@ import org.junit.jupiter.params.provider.CsvSource; class SessionCoverImageTest { + private static final Long SESSION_ID = 1L; private static final int WIDTH = 300, HEIGHT = 200; private static final long VALID_BYTES = 1024 * 500; // 500KB @ParameterizedTest @CsvSource({"gif","jpg","jpeg", "png", "svg"}) void 허용된_확장자(String extension){ - assertDoesNotThrow(() -> new SessionCoverImage(WIDTH, HEIGHT, extension, VALID_BYTES)); + assertDoesNotThrow(() -> new SessionCoverImage(SESSION_ID, WIDTH, HEIGHT, extension, VALID_BYTES)); } @ParameterizedTest @CsvSource({"webp"}) void 허용하지않은_확장자는_예외(String extension){ - assertThatThrownBy(() -> new SessionCoverImage(WIDTH, HEIGHT, extension, VALID_BYTES)) + assertThatThrownBy(() -> new SessionCoverImage(SESSION_ID, WIDTH, HEIGHT, extension, VALID_BYTES)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("지원하지 않는 이미지 확장자입니다: " + extension); } - - } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/registration/RegistrationsTest.java b/src/test/java/nextstep/courses/domain/registration/RegistrationsTest.java new file mode 100644 index 0000000000..e094c5d87e --- /dev/null +++ b/src/test/java/nextstep/courses/domain/registration/RegistrationsTest.java @@ -0,0 +1,40 @@ +package nextstep.courses.domain.registration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +class RegistrationsTest { + + @Test + void 중복_등록하면_예외() { + Registrations registrations = new Registrations(); + registrations = registrations.add(new Registration(1L, 1L)); + + Registrations finalRegistrations = registrations; + assertThatThrownBy(() -> finalRegistrations.add(new Registration(1L, 1L))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("이미 수강신청한 학생입니다."); + } + + @Test + void 새로운_학생_등록_가능() { + Registrations registrations = new Registrations(); + + Registrations updated = registrations.add(new Registration(1L, 1L)); + + assertThat(updated.count()).isEqualTo(1); + } + + @Test + void 여러_학생_등록_가능() { + Registrations registrations = new Registrations(); + + for (long i = 0; i < 1000; i++) { + registrations = registrations.add(new Registration(1L, i)); + } + + assertThat(registrations.count()).isEqualTo(1000); + } +} diff --git a/src/test/java/nextstep/courses/domain/session/SessionBuilder.java b/src/test/java/nextstep/courses/domain/session/SessionBuilder.java index 76061345e8..593953ca13 100644 --- a/src/test/java/nextstep/courses/domain/session/SessionBuilder.java +++ b/src/test/java/nextstep/courses/domain/session/SessionBuilder.java @@ -1,18 +1,15 @@ package nextstep.courses.domain.session; -import nextstep.courses.domain.course.Course; import nextstep.courses.domain.image.SessionCoverImage; -import nextstep.courses.domain.session.type.FreeType; -import nextstep.courses.domain.session.type.SessionType; public class SessionBuilder { private Long id = null; - private Course course = new Course("TDD", 1L); + private Long courseId = 1L; private Term term = new Term(1); - private SessionCoverImage cover = new SessionCoverImage(300, 200, "png", 1024 * 500); private SessionPeriod period = new SessionPeriod("2025-01-01", "2025-01-31"); private SessionState state = SessionState.PREPARING; - private SessionType type = new FreeType(); + private SessionPolicy sessionPolicy = new SessionPolicy(); + private SessionCoverImage coverImage = null; public static SessionBuilder aSession() { return new SessionBuilder(); @@ -23,8 +20,8 @@ public SessionBuilder withId(Long id) { return this; } - public SessionBuilder withCourse(Course course) { - this.course = course; + public SessionBuilder withCourseId(Long courseId) { + this.courseId = courseId; return this; } @@ -33,11 +30,6 @@ public SessionBuilder withTerm(int term) { return this; } - public SessionBuilder withCover(SessionCoverImage cover) { - this.cover = cover; - return this; - } - public SessionBuilder withPeriod(String startDay, String endDay) { this.period = new SessionPeriod(startDay, endDay); return this; @@ -48,8 +40,13 @@ public SessionBuilder withState(SessionState state) { return this; } - public SessionBuilder withType(SessionType type) { - this.type = type; + public SessionBuilder withSessionPolicy(SessionPolicy sessionPolicy) { + this.sessionPolicy = sessionPolicy; + return this; + } + + public SessionBuilder withCoverImage(SessionCoverImage coverImage) { + this.coverImage = coverImage; return this; } @@ -58,8 +55,17 @@ public SessionBuilder recruiting() { return this; } + public SessionBuilder paid(long tuitionFee, int maxCapacity) { + this.sessionPolicy = SessionPolicy.paid(tuitionFee, maxCapacity); + return this; + } + + public SessionBuilder free() { + this.sessionPolicy = SessionPolicy.free(); + return this; + } + public Session build() { - Enrollment enrollment = new Enrollment(state, type); - return new Session(id, course, term, cover, period, enrollment); + return sessionPolicy.createSession(id, courseId, term, period, state, coverImage); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/SessionTest.java b/src/test/java/nextstep/courses/domain/session/SessionTest.java index 21513ea3c1..6d0e8b05ad 100644 --- a/src/test/java/nextstep/courses/domain/session/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/session/SessionTest.java @@ -4,41 +4,59 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import nextstep.courses.domain.registration.Registrations; import org.junit.jupiter.api.Test; class SessionTest { - @Test - void 모집중일때_수강신청_가능() { - Session session = aSession().recruiting().build(); - - assertDoesNotThrow(() -> session.enroll(0)); - } - - @Test - void 모집중이_아닐때_수강신청하면_예외() { - Session session = aSession().build(); - - assertThatThrownBy(() -> session.enroll(0)) - .isInstanceOf(IllegalStateException.class) - .hasMessage("모집중인 강의만 수강신청이 가능합니다."); - } - - @Test - void 준비중이_아닐때_모집시작하면_예외() { - Session session = aSession().recruiting().build(); - - assertThatThrownBy(() -> session.open()) - .isInstanceOf(IllegalStateException.class) - .hasMessage("준비중인 강의만 모집을 시작할 수 있습니다."); - } - - @Test - void 모집중이_아닐때_종료하면_예외() { - Session session = aSession().build(); - - assertThatThrownBy(() -> session.close()) - .isInstanceOf(IllegalStateException.class) - .hasMessage("모집중인 강의만 종료할 수 있습니다."); - } -} \ No newline at end of file + @Test + void 모집중일때_수강신청_가능() { + Session session = aSession().recruiting().build(); + Registrations registrations = new Registrations(); + Enrollment enrollment = session.enrollment(registrations); + + assertDoesNotThrow(() -> enrollment.enroll(0, 1L)); + } + + @Test + void 모집중이_아닐때_수강신청하면_예외() { + Session session = aSession().build(); + Registrations registrations = new Registrations(); + + assertThatThrownBy(() -> session.enrollment(registrations)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("모집중인 강의만 수강신청이 가능합니다."); + } + + @Test + void 준비중이_아닐때_모집시작하면_예외() { + Session session = aSession().recruiting().build(); + + assertThatThrownBy(() -> session.open()) + .isInstanceOf(IllegalStateException.class) + .hasMessage("준비중인 강의만 모집을 시작할 수 있습니다."); + } + + @Test + void 모집중이_아닐때_종료하면_예외() { + Session session = aSession().build(); + + assertThatThrownBy(() -> session.close()) + .isInstanceOf(IllegalStateException.class) + .hasMessage("모집중인 강의만 종료할 수 있습니다."); + } + + @Test + void 유료강의_수강료_불일치시_예외() { + Session session = aSession() + .recruiting() + .paid(10000L, 10) + .build(); + Registrations registrations = new Registrations(); + Enrollment enrollment = session.enrollment(registrations); + + assertThatThrownBy(() -> enrollment.enroll(5000L, 1L)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("수강료와 지불한 금액이 정확히 일치해야 합니다."); + } +} diff --git a/src/test/java/nextstep/courses/domain/session/policy/FreeTuitionTest.java b/src/test/java/nextstep/courses/domain/session/policy/FreeTuitionTest.java new file mode 100644 index 0000000000..004eabb447 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/session/policy/FreeTuitionTest.java @@ -0,0 +1,22 @@ +package nextstep.courses.domain.session.policy; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import nextstep.courses.domain.session.policy.tuition.FreeTuition; +import nextstep.courses.domain.session.policy.tuition.TuitionPolicy; +import org.junit.jupiter.api.Test; + +class FreeTuitionTest { + + @Test + void 금액_상관없이_수강가능() { + TuitionPolicy type = new FreeTuition(); + + assertThatCode(() -> type.validate(0)) + .doesNotThrowAnyException(); + assertThatCode(() -> type.validate(100)) + .doesNotThrowAnyException(); + assertThatCode(() -> type.validate(999999)) + .doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/policy/PaidTuitionTest.java b/src/test/java/nextstep/courses/domain/session/policy/PaidTuitionTest.java new file mode 100644 index 0000000000..d6bbaa5d17 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/session/policy/PaidTuitionTest.java @@ -0,0 +1,27 @@ +package nextstep.courses.domain.session.policy; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.domain.session.policy.tuition.PaidTuition; +import org.junit.jupiter.api.Test; + +class PaidTuitionTest { + + @Test + void 결제금액과_수강료가_동일하지_않으면_예외() { + PaidTuition type = new PaidTuition(1000); + + assertThatThrownBy(() -> type.validate(999)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("수강료와 지불한 금액이 정확히 일치해야 합니다."); + } + + @Test + void 결제금액과_수강료가_동일하면_성공() { + PaidTuition type = new PaidTuition(1000); + + assertThatCode(() -> type.validate(1000)) + .doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacityTest.java b/src/test/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacityTest.java new file mode 100644 index 0000000000..8e02419ca5 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/session/policy/capacity/LimitedCapacityTest.java @@ -0,0 +1,45 @@ +package nextstep.courses.domain.session.policy.capacity; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.Registrations; +import org.junit.jupiter.api.Test; + +class LimitedCapacityTest { + + @Test + void 현재인원이_최대수강인원을_초과하면_예외() { + LimitedCapacity capacity = new LimitedCapacity(2); + Registrations registrations = new Registrations() + .add(new Registration(1L, 1L)) + .add(new Registration(1L, 2L)) + .add(new Registration(1L, 3L)); + + assertThatThrownBy(() -> capacity.validate(registrations)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("최대 수강 인원을 초과할 수 없습니다."); + } + + @Test + void 현재인원이_최대수강인원과_같으면_검증_통과() { + LimitedCapacity capacity = new LimitedCapacity(2); + Registrations registrations = new Registrations() + .add(new Registration(1L, 1L)) + .add(new Registration(1L, 2L)); + + assertThatCode(() -> capacity.validate(registrations)) + .doesNotThrowAnyException(); + } + + @Test + void 현재인원이_최대수강인원_미만이면_검증_통과() { + LimitedCapacity capacity = new LimitedCapacity(3); + Registrations registrations = new Registrations() + .add(new Registration(1L, 1L)); + + assertThatCode(() -> capacity.validate(registrations)) + .doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacityTest.java b/src/test/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacityTest.java new file mode 100644 index 0000000000..532678374b --- /dev/null +++ b/src/test/java/nextstep/courses/domain/session/policy/capacity/UnlimitedCapacityTest.java @@ -0,0 +1,25 @@ +package nextstep.courses.domain.session.policy.capacity; + +import static org.assertj.core.api.Assertions.assertThatCode; + +import nextstep.courses.domain.registration.Registration; +import nextstep.courses.domain.registration.Registrations; +import org.junit.jupiter.api.Test; + +class UnlimitedCapacityTest { + + @Test + void 무제한이면_수강인원_제한없음() { + UnlimitedCapacity capacity = new UnlimitedCapacity(); + Registrations registrations = new Registrations(); + + for (long i = 0; i < 1000; i++) { + registrations = registrations.add(new Registration(1L, i)); + capacity.validate(registrations); + } + + Registrations finalRegistrations = registrations; + assertThatCode(() -> capacity.validate(finalRegistrations)) + .doesNotThrowAnyException(); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/type/FreeTypeTest.java b/src/test/java/nextstep/courses/domain/session/type/FreeTypeTest.java deleted file mode 100644 index bc01653de8..0000000000 --- a/src/test/java/nextstep/courses/domain/session/type/FreeTypeTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package nextstep.courses.domain.session.type; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -import nextstep.courses.domain.session.type.FreeType; -import nextstep.courses.domain.session.type.SessionType; -import org.junit.jupiter.api.Test; - -class FreeTypeTest { - - @Test - void 수강인원_제한없음() { - SessionType type = new FreeType(); - - for (int i = 0; i < 1000; i++) { - type = type.enroll(0); - } - - assertThat(type).isInstanceOf(FreeType.class); - } - - @Test - void 금액_상관없이_수강가능() { - SessionType type = new FreeType(); - - assertThatCode(() -> type.enroll(0)) - .doesNotThrowAnyException(); - assertThatCode(() -> type.enroll(100)) - .doesNotThrowAnyException(); - assertThatCode(() -> type.enroll(999999)) - .doesNotThrowAnyException(); - } -} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/session/type/PaidTypeTest.java b/src/test/java/nextstep/courses/domain/session/type/PaidTypeTest.java deleted file mode 100644 index da71011700..0000000000 --- a/src/test/java/nextstep/courses/domain/session/type/PaidTypeTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package nextstep.courses.domain.session.type; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import nextstep.courses.domain.session.type.PaidType; -import org.junit.jupiter.api.Test; - -class PaidTypeTest { - - @Test - void 최대수강인원_초과하면_예외() { - PaidType type = new PaidType(300, 1000, 300); - - assertThatThrownBy(() -> type.enroll(1000)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("최대 수강 인원을 초과할 수 없습니다."); - } - - @Test - void 결제금액과_수강료가_동일하지_않으면_예외() { - PaidType type = new PaidType(300, 1000); - - assertThatThrownBy(() -> type.enroll(999)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("수강료와 지불한 금액이 정확히 일치해야 합니다."); - } - - @Test - void 최대수강인원이하_결제금액과수강료동일하면_성공() { - PaidType type = new PaidType(300, 1000); - - assertThatCode(() -> type.enroll(1000)) - .doesNotThrowAnyException(); - } -} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java b/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java index 530375d3e1..6791a0195f 100644 --- a/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java +++ b/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java @@ -2,6 +2,7 @@ import nextstep.courses.domain.course.Course; import nextstep.courses.domain.course.CourseRepository; +import nextstep.courses.infrastructure.jdbc.CourseJdbcDao; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -23,7 +24,8 @@ public class CourseRepositoryTest { @BeforeEach void setUp() { - courseRepository = new JdbcCourseRepository(jdbcTemplate); + CourseJdbcDao courseJdbcDao = new CourseJdbcDao(jdbcTemplate); + courseRepository = new CourseRepositoryImpl(courseJdbcDao); } @Test