Skip to content

Commit

Permalink
๐Ÿฉน [STMT-62] ์Šคํ„ฐ๋”” ๋„๋ฉ”์ธ ๋ˆ„๋ฝ๋œ ์ปฌ๋Ÿผ๋“ค ์ถ”๊ฐ€ (#109)
Browse files Browse the repository at this point in the history
* ๐Ÿฉน [STMT-62] ์Šคํ„ฐ๋”” ๋„๋ฉ”์ธ ๋ˆ„๋ฝ๋œ ์ปฌ๋Ÿผ ์ถ”๊ฐ€

- ์ •๊ธฐ๋ชจ์ž„ ์‹œ๊ฐ„
- ์ •๊ธฐ๋ชจ์ž„ ๋ฐ˜๋ณต

* ๐Ÿฉน [STMT-62] ์Šคํ„ฐ๋”” ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ api - ๋ˆ„๋ฝ๋œ ์ •๋ณด ๋ฐ˜ํ™˜ ์‘๋‹ต์— ์ถ”๊ฐ€

* ๐Ÿฉน [STMT-62] sql - table `study` ddl ์ˆ˜์ • ๋ฐ dummy data ์ˆ˜์ •

* ๐Ÿšง [STMT-62] ๋ฆฌ๋ทฐ๋ฐ˜์˜: ํด๋ž˜์Šค ๋‹จ์— ํŠธ๋žœ์žญ์…˜ ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€

* ๐Ÿšง [STMT-62] ๋ฆฌ๋ทฐ๋ฐ˜์˜: ๋ชจ์ž„ ๋ฐ˜๋ณต mapping ๋กœ์ง mapper์— ์œ„์ž„

- repeat๋Š” ํ•œ๋ฒˆ ๋ฐ˜๋ณต ํ•œ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ์žˆ์–ด ๋ช…์‚ฌํ˜•์˜ ์—ฌ๋Ÿฌ๋ฒˆ ๋ฐ˜๋ณตํ•œ๋‹ค๋Š” ๋œป์„ ๊ฐ€์ง„ repetition์œผ๋กœ ํด๋ž˜์Šค๋ช… ๋ณ€๊ฒฝ
- MeetingRepetitionPersistenceMapper ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ Repetition์„ mappingํ•˜๋Š” ๋กœ์ง ๊ตฌํ˜„

* ๐ŸŽจ [STMT-62] StudyPersistenceMapper ์ฝ”๋“œ ํฌ๋งทํŒ…

* ๐ŸŽจ [STMT-62] StudyPersistenceMapper ์žฌํฌ๋งทํŒ…

* ๐Ÿฉน [STMT-62] ์ปฌ๋Ÿผ ์ถ”๊ฐ€์— ๋”ฐ๋ฅธ ์Šคํ„ฐ๋”” ์ƒ์„ธ ์ •๋ณด ์‘๋‹ต์— ์ถ”๊ฐ€

* โœ… [STMT-62] ์Šคํ„ฐ๋”” ์ƒ์„ธ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ api test ์ˆ˜์ •
  • Loading branch information
05AM authored Mar 31, 2024
1 parent b7bf2b5 commit 9b32074
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stumeet.server.study.adapter.in.web.response;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

import lombok.Builder;
Expand All @@ -18,6 +19,9 @@ public record StudyDetailResponse(
int headcount,
LocalDateTime startDate,
LocalDateTime endDate,
LocalTime meetingTime,
String meetingRepetitionType,
List<String> meetingRepetitionDates,
boolean isFinished,
boolean isDeleted
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stumeet.server.study.adapter.out.persistance.entity;

import java.time.LocalDateTime;
import java.time.LocalTime;

import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.Comment;
Expand Down Expand Up @@ -72,6 +73,14 @@ public class StudyJpaEntity extends BaseTimeEntity {
@Comment("์ข…๋ฃŒ์ผ")
private LocalDateTime endDate;

@Column(name = "meeting_time", nullable = false)
@Comment("์ •๊ธฐ๋ชจ์ž„ ์‹œ๊ฐ„")
private LocalTime meetingTime;

@Column(name = "meeting_repetition")
@Comment("์ •๊ธฐ๋ชจ์ž„ ๋ฐ˜๋ณต")
private String meetingRepetition;

@Column(name = "is_finished", nullable = false)
@ColumnDefault("false")
@Comment("์™„๋ฃŒ ์—ฌ๋ถ€")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.stumeet.server.study.adapter.out.persistance.mapper;

import java.util.List;

import org.springframework.stereotype.Component;

import com.stumeet.server.study.domain.ScheduleRepetitionType;
import com.stumeet.server.study.domain.StudyMeetingSchedule;

@Component
public class MeetingRepetitionPersistenceMapper {

private static final String REPEAT_DELIMITER = ";";

public StudyMeetingSchedule.Repetition toDomain(String meetingRepetition) {
List<String> repetitionElements = List.of(meetingRepetition.split(REPEAT_DELIMITER));

return StudyMeetingSchedule.Repetition.of(
ScheduleRepetitionType.valueOf(repetitionElements.getFirst()),
repetitionElements.subList(1, repetitionElements.size()));
}

public String toColumn(StudyMeetingSchedule.Repetition repetition) {
return repetition.getType().toString()
+ REPEAT_DELIMITER
+ String.join(REPEAT_DELIMITER, repetition.getDates());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.stumeet.server.study.adapter.out.persistance.entity.StudyJpaEntity;
import com.stumeet.server.study.domain.Study;
import com.stumeet.server.study.domain.StudyHeadCount;
import com.stumeet.server.study.domain.StudyMeetingSchedule;
import com.stumeet.server.study.domain.StudyPeriod;

import lombok.RequiredArgsConstructor;
Expand All @@ -14,6 +15,7 @@
public class StudyPersistenceMapper {

private final StudyDomainPersistenceMapper studyDomainPersistenceMapper;
private final MeetingRepetitionPersistenceMapper meetingRepetitionPersistenceMapper;

public Study toDomain(StudyJpaEntity entity) {
return Study.builder()
Expand All @@ -26,6 +28,10 @@ public Study toDomain(StudyJpaEntity entity) {
.period(StudyPeriod.of(entity.getStartDate(), entity.getEndDate()))
.headcount(StudyHeadCount.from(entity.getHeadcount()))
.image(entity.getImage())
.meetingSchedule(
StudyMeetingSchedule.of(
entity.getMeetingTime(),
meetingRepetitionPersistenceMapper.toDomain(entity.getMeetingRepetition())))
.isFinished(entity.getIsFinished())
.isDeleted(entity.getIsDeleted())
.build();
Expand All @@ -43,6 +49,9 @@ public StudyJpaEntity toEntity(Study domain) {
.endDate(domain.getEndDate())
.headcount(domain.getHeadcountNumber())
.image(domain.getImage())
.meetingTime(domain.getMeetingSchedule().getTime())
.meetingRepetition(
meetingRepetitionPersistenceMapper.toColumn(domain.getMeetingSchedule().getRepetition()))
.isFinished(domain.isFinished())
.isDeleted(domain.isDeleted())
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public StudyDetailResponse toStudyDetailResponse(Study study) {
.endDate(study.getEndDate())
.headcount(study.getHeadcountNumber())
.image(study.getImage())
.meetingTime(study.getMeetingTime())
.meetingRepetitionType(study.getMeetingRepeatTypeName())
.meetingRepetitionDates(study.getRepetitionDates())
.isFinished(study.isFinished())
.isDeleted(study.isDeleted())
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.stumeet.server.study.application.service;

import org.springframework.transaction.annotation.Transactional;

import com.stumeet.server.common.annotation.UseCase;
import com.stumeet.server.study.adapter.in.web.response.StudyDetailResponse;
import com.stumeet.server.study.application.port.in.StudyQueryUseCase;
Expand All @@ -11,6 +13,7 @@

@UseCase
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class StudyQueryService implements StudyQueryUseCase {

private final StudyQueryPort studyQueryPort;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.stumeet.server.study.domain;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
public enum ScheduleRepetitionType {

DAILY("๋งค์ผ"),
WEEKLY("๋งค์ฃผ"),
MONTHLY("๋งค๋‹ฌ");

private final String name;
}
16 changes: 15 additions & 1 deletion src/main/java/com/stumeet/server/study/domain/Study.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stumeet.server.study.domain;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

import lombok.AccessLevel;
Expand All @@ -21,6 +22,8 @@ public class Study {

private String region;

private StudyMeetingSchedule meetingSchedule;

private String intro;

private String rule;
Expand Down Expand Up @@ -54,5 +57,16 @@ public LocalDateTime getStartDate() {
public LocalDateTime getEndDate() {
return period.getEndDate();
}
}

public String getMeetingRepeatTypeName() {
return meetingSchedule.getRepetitionType().name();
}

public List<String> getRepetitionDates() {
return meetingSchedule.getRepetitionDates();
}

public LocalTime getMeetingTime() {
return meetingSchedule.getTime();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.stumeet.server.study.domain;

import java.time.LocalTime;
import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class StudyMeetingSchedule {

private final LocalTime time;
private final Repetition repetition;

@Getter
@AllArgsConstructor(staticName = "of")
public static class Repetition {

private final ScheduleRepetitionType type;

private final List<String> dates;
}

public static StudyMeetingSchedule of(LocalTime time, Repetition repetition) {
return new StudyMeetingSchedule(time, repetition);
}

public LocalTime getTime() {
return time;
}

public ScheduleRepetitionType getRepetitionType() {
return repetition.getType();
}

public List<String> getRepetitionDates() {
return repetition.getDates();
}
}
32 changes: 17 additions & 15 deletions src/main/resources/db/migration/V1.4__add_study_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@ CREATE TABLE `study_domain`

CREATE TABLE `study`
(
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '์Šคํ„ฐ๋”” ID',
`study_domain_id` BIGINT NOT NULL COMMENT '์Šคํ„ฐ๋”” ๋„๋ฉ”์ธ ID',
`name` VARCHAR(255) NOT NULL COMMENT '์Šคํ„ฐ๋””๋ช…',
`region` VARCHAR(50) NOT NULL COMMENT 'ํ™œ๋™ ์ง€์—ญ',
`intro` VARCHAR(200) NOT NULL COMMENT '์†Œ๊ฐœ',
`rule` VARCHAR(200) NULL COMMENT '๊ทœ์น™',
`image` VARCHAR(500) NOT NULL COMMENT '์Šคํ„ฐ๋”” ์ด๋ฏธ์ง€์˜ URL',
`headcount` TINYINT(100) NOT NULL DEFAULT 1 COMMENT '์ธ์› ์ˆ˜',
`start_date` DATETIME NOT NULL COMMENT '์‹œ์ž‘์ผ',
`end_date` DATETIME NOT NULL COMMENT '์ข…๋ฃŒ์ผ',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '์ƒ์„ฑ ์‹œ๊ฐ„',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '์ˆ˜์ • ์‹œ๊ฐ„',
`is_finished` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT '์Šคํ„ฐ๋”” ์™„๋ฃŒ ์—ฌ๋ถ€',
`is_deleted` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT '์Šคํ„ฐ๋”” ์‚ญ์ œ ์—ฌ๋ถ€',
`deleted_at` DATETIME NULL COMMENT '์Šคํ„ฐ๋”” ์‚ญ์ œ ์ผ์ž',
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '์Šคํ„ฐ๋”” ID',
`study_domain_id` BIGINT NOT NULL COMMENT '์Šคํ„ฐ๋”” ๋„๋ฉ”์ธ ID',
`name` VARCHAR(255) NOT NULL COMMENT '์Šคํ„ฐ๋””๋ช…',
`region` VARCHAR(50) NOT NULL COMMENT 'ํ™œ๋™ ์ง€์—ญ',
`intro` VARCHAR(200) NOT NULL COMMENT '์†Œ๊ฐœ',
`rule` VARCHAR(200) NULL COMMENT '๊ทœ์น™',
`image` VARCHAR(500) NOT NULL COMMENT '์Šคํ„ฐ๋”” ์ด๋ฏธ์ง€์˜ URL',
`headcount` TINYINT(100) NOT NULL DEFAULT 1 COMMENT '์ธ์› ์ˆ˜',
`start_date` DATETIME NOT NULL COMMENT '์‹œ์ž‘์ผ',
`end_date` DATETIME NOT NULL COMMENT '์ข…๋ฃŒ์ผ',
`meeting_time` TIME NOT NULL COMMENT '์ •๊ธฐ๋ชจ์ž„ ์‹œ๊ฐ„',
`meeting_repetition` VARCHAR(100) NOT NULL COMMENT '์ •๊ธฐ๋ชจ์ž„ ๋ฐ˜๋ณต',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '์ƒ์„ฑ ์‹œ๊ฐ„',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '์ˆ˜์ • ์‹œ๊ฐ„',
`is_finished` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT '์Šคํ„ฐ๋”” ์™„๋ฃŒ ์—ฌ๋ถ€',
`is_deleted` TINYINT(1) NOT NULL DEFAULT FALSE COMMENT '์Šคํ„ฐ๋”” ์‚ญ์ œ ์—ฌ๋ถ€',
`deleted_at` DATETIME NULL COMMENT '์Šคํ„ฐ๋”” ์‚ญ์ œ ์ผ์ž',

CONSTRAINT fk_study_domain_with_study FOREIGN KEY (study_domain_id)
REFERENCES study_domain (id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
INSERT INTO study_domain (id, study_field_id) VALUES (1, 6);

INSERT INTO study (id, study_domain_id, name, region, intro, rule, image, start_date, end_date)
INSERT INTO study (id, study_domain_id, name, region, intro, rule, image,
meeting_time, meeting_repetition, start_date, end_date)
VALUES (1, 1, '[์ž„์‹œ] ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํ„ฐ๋””', '์„œ์šธ', 'ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์Šคํ„ฐ๋”” ์ž…๋‹ˆ๋‹ค.', '- ๋งค์ฃผ ๋ชฉ์š”์ผ 8์‹œ\n- ์žฅ์†Œ: ์•ˆ์•”์—ญ\n- ์ œ์‹œ๊ฐ„์— ์ œ์ถœํ•˜๊ธฐ!',
'https://stumeet.s3.ap-northeast-2.amazonaws.com/study/1/image/2023062711172178420.png',
'2024-04-01', '2024-05-01');
'21:00:00', 'WEEKLY;์›”;์ˆ˜;๋ชฉ;', '2024-04-01', '2024-05-01');

INSERT INTO study_tag (study_domain_id, name) VALUES (1, 'springboot');
INSERT INTO study_tag (study_domain_id, name) VALUES (1, 'java');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@

import com.stumeet.server.common.auth.model.AuthenticationHeader;
import com.stumeet.server.helper.WithMockMember;
import com.stumeet.server.stub.StudyStub;
import com.stumeet.server.stub.TokenStub;
import com.stumeet.server.template.ApiTest;

class StudyQueryApiTest extends ApiTest {

private final Long testStudyId = 1L;
private final Long notFoundTestStudyId = 0L;

@Nested
@DisplayName("์Šคํ„ฐ๋”” ์ƒ์„ธ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ")
class GetStudyDetail {
Expand All @@ -32,7 +30,7 @@ class GetStudyDetail {
@WithMockMember
@DisplayName("[์„ฑ๊ณต] ์Šคํ„ฐ๋”” ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ๋ฅผ ์„ฑ๊ณตํ•œ๋‹ค.")
void successTest() throws Exception {
mockMvc.perform(get("/api/v1/studies/{id}", testStudyId)
mockMvc.perform(get("/api/v1/studies/{id}", StudyStub.getStudyId())
.header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()))
.andExpect(status().isOk())
.andDo(document("get-study-detail/success",
Expand All @@ -57,6 +55,11 @@ void successTest() throws Exception {
fieldWithPath("data.headcount").description("์ฐธ์—ฌ ์ธ์› ์ˆ˜"),
fieldWithPath("data.startDate").description("์‹œ์ž‘ ๋‚ ์งœ"),
fieldWithPath("data.endDate").description("์ข…๋ฃŒ ๋‚ ์งœ"),
fieldWithPath("data.meetingTime").description("์ •๊ธฐ๋ชจ์ž„ ์‹œ๊ฐ„"),
fieldWithPath("data.meetingRepetitionType")
.description("์ •๊ธฐ๋ชจ์ž„ ๋ฐ˜๋ณต ์œ ํ˜• / `๋งค์ผ`, `๋งค์ฃผ`, `๋งค๋‹ฌ`"),
fieldWithPath("data.meetingRepetitionDates")
.description("์ •๊ธฐ๋ชจ์ž„ ๋ฐ˜๋ณต์ผ / ๋งค์ฃผ: ์š”์ผ, ๋งค๋‹ฌ: ๋‚ ์งœ"),
fieldWithPath("data.isFinished").description("์ข…๋ฃŒ ์—ฌ๋ถ€"),
fieldWithPath("data.isDeleted").description("์‚ญ์ œ ์—ฌ๋ถ€")
)));
Expand All @@ -66,7 +69,7 @@ void successTest() throws Exception {
@WithMockMember
@DisplayName("[์‹คํŒจ] ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์Šคํ„ฐ๋””์˜ ID๋กœ ์š”์ฒญํ•œ ๊ฒฝ์šฐ ์Šคํ„ฐ๋”” ์ƒ์„ธ์ •๋ณด ์กฐํšŒ๋ฅผ ์‹คํŒจํ•œ๋‹ค.")
void invalidRequestTest() throws Exception {
mockMvc.perform(get("/api/v1/studies/{id}", notFoundTestStudyId)
mockMvc.perform(get("/api/v1/studies/{id}", StudyStub.getInvalidStudyId())
.header(AuthenticationHeader.ACCESS_TOKEN.getName(), TokenStub.getMockAccessToken()))
.andExpect(status().isNotFound())
.andDo(document("get-study-detail/fail/not-found",
Expand Down

0 comments on commit 9b32074

Please sign in to comment.