Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Study V2 도메인 구현 #853

Merged
merged 12 commits into from
Jan 28, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.gdschongik.gdsc.domain.common.vo;

import com.gdschongik.gdsc.domain.common.model.SemesterType;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Embeddable
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Semester {

private Integer academicYear;

@Enumerated(EnumType.STRING)
private SemesterType semesterType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ private void validateDateTimeWithinTwoWeeks(LocalDateTime dateTime, LocalDateTim

private void validatePeriodOverlap(
List<RecruitmentRound> recruitmentRounds, LocalDateTime startDate, LocalDateTime endDate) {
// TODO: recruitmentRound.getPeriod().validatePeriodOverlap(startDate, endDate)로 변경
recruitmentRounds.forEach(recruitmentRound -> recruitmentRound.validatePeriodOverlap(startDate, endDate));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.gdschongik.gdsc.domain.studyv2.domain;

import com.gdschongik.gdsc.domain.common.model.BaseEntity;
import com.gdschongik.gdsc.domain.common.vo.Period;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.hibernate.annotations.Comment;

@Getter
@Entity
@Table(name = "study_session_v2")
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class StudySessionV2 extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "study_session_v2_id")
private Long id;

@Comment("회차 제목")
private String title;

@Comment("회차 설명")
private String description;

// 수업 관련 필드

@Comment("수업 출석 번호")
private Integer lessonAttendanceNumber;

@Embedded
@AttributeOverride(name = "startDate", column = @Column(name = "lesson_start_at"))
@AttributeOverride(name = "endDate", column = @Column(name = "lesson_end_at"))
private Period lessonPeriod;

// 과제 관련 필드

@Comment("과제 명세 링크")
private String assignmentDescriptionLink;
Comment on lines +44 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

임베디드랑 일반 필드 순서 맞추는 거 새로운 엔티티에서는 미리 맞춰둬도 좋을 거 같아요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그그그그 이거 하면서 좀 생각을 해봤는데, 일반 필드 -> VO는 꼭 맞춰야 하나? 싶더라고요.
요 케이스처럼 필드 성격에 따라 묶이는 게 적절할 것 같은 케이스도 있고...

물론 ID -> 상태 / 타입 -> 일반 / VO 필드 -> 참조 필드 순서는 지키되 일반/VO는 굳이 안지켜도 될 것 같은데 어떻게 생각하시나용

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 저도 성격에 따라 묶는 게 더 좋은 것 같아요 그럼 이대로 가죠 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿입니다 그 필드 순서 이슈 작업 건에서도 참고해주세용


@Embedded
@AttributeOverride(name = "startDate", column = @Column(name = "assignment_start_at"))
@AttributeOverride(name = "endDate", column = @Column(name = "assignment_end_at"))
private Period assignmentPeriod;

// 참조 필드

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "study_v2_id")
private StudyV2 studyV2;

/**
* 모든 스터디회차는 인자로 전달되는 스터디 애그리거트 루트 엔티티에 종속됩니다.
* 따라서 스터디회차 생성 팩토리 메서드 생성 시 자기 자신을 반환하지 않고,
* 스터디 애그리거트 루트 엔티티의 스터디회차 컬렉션에 자기 자신을 추가하는 식으로 생성합니다.
* 부모 클래스에서 위 로직을 수행하기 때문에, 생성 팩토리 메서드는 void 타입을 반환해야 합니다.
*/
@Builder(access = AccessLevel.PRIVATE)
private StudySessionV2(
String title,
String description,
Integer lessonAttendanceNumber,
Period lessonPeriod,
String assignmentDescriptionLink,
Period assignmentPeriod,
StudyV2 studyV2) {
this.title = title;
this.description = description;
this.lessonAttendanceNumber = lessonAttendanceNumber;
this.lessonPeriod = lessonPeriod;
this.assignmentDescriptionLink = assignmentDescriptionLink;
this.assignmentPeriod = assignmentPeriod;
this.studyV2 = studyV2;
studyV2.getStudySessions().add(this);
}

public void create(
String title,
String description,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 static 키워드 있어야 하지 않나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깜빡했네요 수정완

Integer lessonAttendanceNumber,
Period lessonPeriod,
String assignmentDescriptionLink,
Period assignmentPeriod,
StudyV2 studyV2) {
StudySessionV2.builder()
.title(title)
.description(description)
.lessonAttendanceNumber(lessonAttendanceNumber)
.lessonPeriod(lessonPeriod)
.assignmentDescriptionLink(assignmentDescriptionLink)
.assignmentPeriod(assignmentPeriod)
.studyV2(studyV2)
.build();
}
}
155 changes: 155 additions & 0 deletions src/main/java/com/gdschongik/gdsc/domain/studyv2/domain/StudyV2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.gdschongik.gdsc.domain.studyv2.domain;

import com.gdschongik.gdsc.domain.common.model.BaseEntity;
import com.gdschongik.gdsc.domain.common.vo.Period;
import com.gdschongik.gdsc.domain.common.vo.Semester;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.StudyType;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Comment;

/**
* 스터디 애그리거트 루트 엔티티입니다.
* [메타] 태그가 있는 필드는 수강 신청 시 참고용으로만 사용되며, 스터디회차 엔티티 내부 상태 검증에 사용되지 않습니다.
* 혼동이 예상되는 경우 코멘트에 해당 태그가 명시되어 있습니다.
* 그 외 필드의 경우 스터디 애그리거트 내부 상태 검증에 사용될 수 있습니다. (ex: 총 회차 수)
*/
@Getter
@Entity
@Table(name = "study_v2")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class StudyV2 extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "study_v2_id")
private Long id;

private StudyType type;

@Comment("스터디 이름")
private String title;

@Comment("스터디 소개")
private String description;

@Comment("스터디 소개 노션 링크")
@Column(columnDefinition = "TEXT")
private String descriptionNotionLink;

@Enumerated(EnumType.STRING)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Enumerated(EnumType.STRING) 필요한가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Embedded 인데 실수했네요 굿

private Semester semester;

@Comment("총 회차 수")
private Integer totalWeek;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변수명도 회차라는 의미 담아서 다시 지으면 어떤가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totalRound로 가겠읍니다


@Comment("[메타] 스터디 요일")
@Enumerated(EnumType.STRING)
private DayOfWeek dayOfWeek;

@Comment("[메타] 스터디 시작 시간")
private LocalTime startTime;

@Comment("[메타] 스터디 종료 시간")
private LocalTime endTime;

@Embedded
@AttributeOverride(name = "startDate", column = @Column(name = "application_start_date"))
@AttributeOverride(name = "endDate", column = @Column(name = "application_end_date"))
private Period applicationPeriod;

@Comment("디스코드 채널 ID")
private String discordChannelId;

@Comment("디스코드 역할 ID")
private String discordRoleId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member mentor;

@OneToMany(mappedBy = "studyV2")
private List<StudySessionV2> studySessions = new ArrayList<>();

@Builder(access = AccessLevel.PRIVATE)
private StudyV2(
StudyType type,
String title,
String description,
String descriptionNotionLink,
Semester semester,
Integer totalWeek,
DayOfWeek dayOfWeek,
LocalTime startTime,
LocalTime endTime,
Period applicationPeriod,
String discordChannelId,
String discordRoleId,
Member mentor) {
this.type = type;
this.title = title;
this.description = description;
this.descriptionNotionLink = descriptionNotionLink;
this.semester = semester;
this.totalWeek = totalWeek;
this.dayOfWeek = dayOfWeek;
this.startTime = startTime;
this.endTime = endTime;
this.applicationPeriod = applicationPeriod;
this.discordChannelId = discordChannelId;
this.discordRoleId = discordRoleId;
this.mentor = mentor;
}

public static StudyV2 create(
StudyType type,
String title,
String description,
String descriptionNotionLink,
Semester semester,
Integer totalWeek,
DayOfWeek dayOfWeek,
LocalTime startTime,
LocalTime endTime,
Period applicationPeriod,
String discordChannelId,
String discordRoleId,
Member mentor) {
return StudyV2.builder()
.type(type)
.title(title)
.description(description)
.descriptionNotionLink(descriptionNotionLink)
.semester(semester)
.totalWeek(totalWeek)
.dayOfWeek(dayOfWeek)
.startTime(startTime)
.endTime(endTime)
.applicationPeriod(applicationPeriod)
.discordChannelId(discordChannelId)
.discordRoleId(discordRoleId)
.mentor(mentor)
.build();
}
}
Loading