Skip to content

Commit

Permalink
Merge pull request #51 from Project-Catcher/feat-hs-schedules-list
Browse files Browse the repository at this point in the history
schedules/list 구현 (일부 조건 미구현)
  • Loading branch information
toad0403 authored Dec 21, 2023
2 parents f7a2b82 + 4ff17ca commit 2741701
Show file tree
Hide file tree
Showing 12 changed files with 307 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.catcher.core.domain.entity.Schedule;
import com.catcher.core.domain.entity.User;
import com.catcher.core.domain.entity.enums.ScheduleStatus;
import com.catcher.core.dto.request.ScheduleListRequest;

import java.util.List;
import java.util.Optional;
Expand All @@ -12,7 +13,7 @@ public interface ScheduleRepository {

List<Schedule> findByUserAndStatus(User user, ScheduleStatus scheduleStatus);

void save(Schedule schedule);
Schedule save(Schedule schedule);

List<Schedule> upcomingScheduleList(Long userId);

Expand All @@ -25,4 +26,7 @@ public interface ScheduleRepository {
void saveAll(List<Schedule> scheduleList);

void deleteDraftSchedule(Long userId, Long scheduleId);

List<Schedule> findMainScheduleList(ScheduleListRequest scheduleListRequest);

}
2 changes: 1 addition & 1 deletion src/main/java/com/catcher/core/db/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface UserRepository {

Optional<User> findById(Long id);

void save(User user);
User save(User user);

void saveAll(List<User> userList);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.catcher.core.domain.entity.enums;

public enum SearchOption {
ALL, TITLE, WRITER, DESCRIPTION, TAG, TITLEANDDESCRIPTION
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.catcher.core.dto.request;

import com.catcher.core.domain.entity.enums.SearchOption;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;

@Getter
@Setter
public class ScheduleListRequest {
private Long participantFrom;
private Long participantTo;
private Long budgetFrom;
private Long budgetTo;
private String keyword;
private SearchOption keywordOption;
private String categoryName;
private LocalDateTime startAt;
private LocalDateTime endAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.catcher.core.dto.response;

import com.catcher.core.domain.entity.Location;
import com.catcher.core.domain.entity.Schedule;
import lombok.Getter;

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

@Getter
public class ScheduleListResponse {
private final List<ScheduleDTO> schedules;

public ScheduleListResponse(List<ScheduleDTO> schedules) {
this.schedules = schedules;
}

@Getter
public static class ScheduleDTO {
private final Long id;
private final Long participantLimit;
private final String title;
private final String description;
private final String thumbnailUrl;
private final Long viewCount;
private final Long budget;
//private final int participantCount;
private final Location location;
private final LocalDateTime startAt;
private final LocalDateTime endAt;
private final LocalDateTime participantStartAt;
private final LocalDateTime participantEndAt;
//private final List<Tag> scheduleTags;

public ScheduleDTO(Schedule schedule) {
this.id = schedule.getId();
this.participantLimit = schedule.getParticipantLimit();
this.title = schedule.getTitle();
this.description = schedule.getDescription();
this.thumbnailUrl = schedule.getThumbnailUrl();
this.viewCount = schedule.getViewCount();
this.budget = schedule.getBudget();
//this.participantCount = schedule.getScheduleParticipants().size();
this.location = schedule.getLocation();
this.startAt = schedule.getStartAt();
this.endAt = schedule.getEndAt();
this.participantStartAt = schedule.getParticipateStartAt();
this.participantEndAt = schedule.getParticipateEndAt();
//this.scheduleTags = schedule.getScheduleTags().stream().map(ScheduleTag::getTag).collect(Collectors.toList());

}
}
}
18 changes: 14 additions & 4 deletions src/main/java/com/catcher/core/service/ScheduleService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import com.catcher.common.exception.BaseResponseStatus;
import com.catcher.core.database.*;
import com.catcher.core.domain.entity.*;
import com.catcher.core.domain.entity.enums.ContentType;
import com.catcher.core.domain.entity.enums.ItemType;
import com.catcher.core.domain.entity.enums.RecommendedStatus;
import com.catcher.core.domain.entity.enums.ScheduleStatus;
import com.catcher.core.domain.entity.enums.*;
import com.catcher.core.dto.request.*;
import com.catcher.core.dto.response.*;
import com.catcher.core.port.AddressPort;
Expand Down Expand Up @@ -54,6 +51,7 @@ public DraftScheduleResponse getDraftSchedule(User user) {

@Transactional
public SaveScheduleDetailResponse saveScheduleDetail(SaveScheduleDetailRequest request, Long scheduleId, User user) {

Schedule schedule = getSchedule(scheduleId, user);
isValidItem(request.getItemType(), request.getItemId());

Expand Down Expand Up @@ -255,6 +253,18 @@ public void deleteDraftSchedule(Long userId, Long scheduleId) {
scheduleRepository.deleteDraftSchedule(userId, scheduleId);
}

@Transactional(readOnly = true)
public ScheduleListResponse getScheduleListByFilter(ScheduleListRequest scheduleListRequest) {

List<Schedule> schedules = scheduleRepository.findMainScheduleList(scheduleListRequest);

List<ScheduleListResponse.ScheduleDTO> scheduleDTOList = schedules.stream()
.map(ScheduleListResponse.ScheduleDTO::new)
.toList();

return new ScheduleListResponse(scheduleDTOList);
}

private ScheduleDetail getScheduleDetail(User user, Long scheduleDetailId) {
ScheduleDetail scheduleDetail = scheduleDetailRepository.findByIdWithUser(scheduleDetailId)
.orElseThrow(() -> new BaseException(BaseResponseStatus.DATA_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.catcher.core.specification;

import com.catcher.core.domain.entity.*;
import com.catcher.core.domain.entity.enums.ScheduleStatus;
import jakarta.persistence.criteria.*;
import org.springframework.data.jpa.domain.Specification;

import java.time.LocalDateTime;

public class ScheduleSpecification {

public static Specification<Schedule> likeTitle(String title) {
/*
select s from Schedule s
where s.title like '%' || :title || '%'
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.like(root.get("title"), "%" + title + "%");
}

public static Specification<Schedule> likeDescription (String description) {
/*
select s from Schedule s
where s.description like '%' || :description || '%'
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.like(root.get("description"), "%" + description + "%");
}

public static Specification<Schedule> fromBudget(Long budget) {
/*
select s from Schedule s
where s.budget >= :budget
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.greaterThanOrEqualTo(root.get("budget"), budget);
}

public static Specification<Schedule> toBudget(Long budget) {
/*
select s from Schedule s
where s.budget <= :budget
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.lessThanOrEqualTo(root.get("budget"), budget);
}

public static Specification<Schedule> fromStartAt(LocalDateTime startAt) {
/*
select s from Schedule s
where s.startAt >= :startAt
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.greaterThanOrEqualTo(root.get("startAt"), startAt);
}

public static Specification<Schedule> toEndAt(LocalDateTime endAt) {
/*
select s from Schedule s
where s.endAt <= :endAt
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.lessThanOrEqualTo(root.get("endAt"), endAt);
}

public static Specification<Schedule> fromParticipant(Long participantFrom) {
/*
select s from Schedule s
where s.participantLimit >= :participantFrom
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.greaterThanOrEqualTo(root.get("participantLimit"), participantFrom);
}

public static Specification<Schedule> toParticipant(Long participantTo) {
/*
select s from Schedule s
where s.participantLimit <= :participantTo
*/
return (root, query, criteriaBuilder)
-> criteriaBuilder.lessThanOrEqualTo(root.get("participantLimit"), participantTo);
}

public static Specification<Schedule> likeByUsername(String username) {
/*
select s from Schedule s
left join User u s.u
where u.username like '%' || :username || '%'
*/
return (root, query, criteriaBuilder) -> {
Join<Schedule, User> join = root.join("user", JoinType.LEFT);

return criteriaBuilder.like(join.get("username"), "%" + username + "%");
};
}

public static Specification<Schedule> scheduleStatus(ScheduleStatus scheduleStatus) {
/*
select s from Schedule s
where s.scheduleStatus = :scheduleStatus
*/
return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("scheduleStatus"), scheduleStatus);
}

public static Specification<Schedule> inTagName(String tagName) {
/*
select s from Schedule s
where
s.id in (select st.schedule.id from ScheduleTag st where st.tag.name = :tagName)
*/
return (root, query, criteriaBuilder) -> {

Subquery<Long> subquery = query.subquery(Long.class);
Root<ScheduleTag> subRoot = subquery.from(ScheduleTag.class);

subquery.select(subRoot.get("schedule").get("id"))
.where(criteriaBuilder.equal(subRoot.get("tag").get("name"), tagName));

return criteriaBuilder.in(root.get("id")).value(subquery);
};
}
}
61 changes: 59 additions & 2 deletions src/main/java/com/catcher/datasource/ScheduleRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
import com.catcher.core.domain.entity.User;
import com.catcher.core.domain.entity.enums.ParticipantStatus;
import com.catcher.core.domain.entity.enums.ScheduleStatus;
import com.catcher.core.domain.entity.enums.SearchOption;
import com.catcher.core.dto.request.ScheduleListRequest;
import com.catcher.core.specification.ScheduleSpecification;
import com.catcher.datasource.repository.ScheduleJpaRepository;
import com.catcher.datasource.repository.ScheduleParticipantJpaRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
Expand Down Expand Up @@ -42,8 +46,37 @@ public List<Schedule> findByUserAndStatus(User user, ScheduleStatus scheduleStat
}

@Override
public void save(Schedule schedule) {
scheduleJpaRepository.save(schedule);
public Schedule save(Schedule schedule) {
return scheduleJpaRepository.save(schedule);
}

@Override
public List<Schedule> findMainScheduleList(ScheduleListRequest scheduleListRequest) {

Specification<Schedule> specification = Specification.where(ScheduleSpecification.scheduleStatus(ScheduleStatus.NORMAL));

if(scheduleListRequest.getParticipantFrom() != null)
specification = specification.and(ScheduleSpecification.fromParticipant(scheduleListRequest.getParticipantFrom()));

if(scheduleListRequest.getParticipantTo() != null)
specification = specification.and(ScheduleSpecification.toParticipant(scheduleListRequest.getParticipantTo()));

if(scheduleListRequest.getStartAt() != null)
specification = specification.and(ScheduleSpecification.fromStartAt(scheduleListRequest.getStartAt()));

if(scheduleListRequest.getEndAt() != null)
specification = specification.and(ScheduleSpecification.toEndAt(scheduleListRequest.getEndAt()));

if(scheduleListRequest.getBudgetFrom() != null)
specification = specification.and(ScheduleSpecification.fromBudget(scheduleListRequest.getBudgetFrom()));

if(scheduleListRequest.getBudgetTo() != null)
specification = specification.and(ScheduleSpecification.toBudget(scheduleListRequest.getBudgetTo()));

if(scheduleListRequest.getKeyword() != null && scheduleListRequest.getKeywordOption() != null)
specification = specification.and(getSpecificationByKeywordOption(scheduleListRequest.getKeywordOption(), scheduleListRequest.getKeyword()));

return scheduleJpaRepository.findAll(specification);
}

@Override
Expand Down Expand Up @@ -127,4 +160,28 @@ public void deleteDraftSchedule(Long userId, Long scheduleId) {
throw new BaseException(BaseResponseStatus.FAIL_DELETE_DRAFT_SCHEDULE);
}
}

private Specification<Schedule> getSpecificationByKeywordOption(SearchOption keywordOption, String keyword) {
Specification<Schedule> specification = Specification.where(null);

if(keywordOption.equals(SearchOption.ALL)){
specification = specification.or(ScheduleSpecification.likeTitle(keyword))
.or(ScheduleSpecification.likeDescription(keyword))
.or(ScheduleSpecification.likeByUsername(keyword))
.or(ScheduleSpecification.inTagName(keyword));
} else if(keywordOption.equals(SearchOption.TITLE)) {
specification = specification.or(ScheduleSpecification.likeTitle(keyword));
} else if(keywordOption.equals(SearchOption.DESCRIPTION)) {
specification = specification.or(ScheduleSpecification.likeDescription(keyword));
} else if(keywordOption.equals(SearchOption.TITLEANDDESCRIPTION)) {
specification = specification.or(ScheduleSpecification.likeTitle(keyword))
.or(ScheduleSpecification.likeDescription(keyword));
} else if(keywordOption.equals(SearchOption.WRITER)) {
specification = specification.or(ScheduleSpecification.likeByUsername(keyword));
} else if(keywordOption.equals(SearchOption.TAG)) {
specification = specification.or(ScheduleSpecification.inTagName(keyword));
}

return specification;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.catcher.core.domain.entity.User;
import com.catcher.core.domain.entity.enums.ScheduleStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -12,7 +13,7 @@
import java.util.List;
import java.util.Optional;

public interface ScheduleJpaRepository extends JpaRepository<Schedule, Long> {
public interface ScheduleJpaRepository extends JpaRepository<Schedule, Long>, JpaSpecificationExecutor<Schedule> {
Optional<Schedule> findByIdAndUser(Long scheduleId, User user);

List<Schedule> findByUserAndScheduleStatus(User user, ScheduleStatus scheduleStatus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public Optional<User> findById(Long id) {
}

@Override
public void save(User user) {
userJpaRepository.save(user);
public User save(User user) {
return userJpaRepository.save(user);
}

@Override
Expand Down
Loading

0 comments on commit 2741701

Please sign in to comment.