Skip to content

Commit

Permalink
refactor: 패키지 구조 개선 및 QueryDsl 적용 (#363)
Browse files Browse the repository at this point in the history
* refactor: 조직 검색 리팩토링

* refactor: 불필요한 테스트 코드 삭제

* chore: ignore 추가
  • Loading branch information
seheonnn authored Jul 22, 2024
1 parent a2be0c4 commit 8e3a794
Show file tree
Hide file tree
Showing 16 changed files with 217 additions and 204 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

*-secret.yml
**/src/main/generated/
**/out/
**/firebase/*.json
data/**
db/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import com.sponus.coredomain.domain.organization.Organization;
import com.sponus.coredomain.domain.organization.enums.OrganizationType;

import lombok.Builder;

@Builder
public record OrganizationSearchResponse(
Long id,
String name,
String imageUrl,
OrganizationType organizationType
) {
public static OrganizationSearchResponse of(Organization organization) {
return new OrganizationSearchResponse(
organization.getId(),
organization.getName(),
organization.getImageUrl(),
organization.getOrganizationType()
);
return OrganizationSearchResponse.builder()
.id(organization.getId())
.name(organization.getName())
.imageUrl(organization.getImageUrl())
.organizationType(organization.getOrganizationType())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.sponus.coredomain.domain.organization.enums.OrganizationType;
import com.sponus.coredomain.domain.organization.enums.ProfileStatus;
import com.sponus.coredomain.domain.organization.repository.OrganizationRepository;
import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition;
import com.sponus.coreinfraredis.entity.SearchHistory;
import com.sponus.coreinfraredis.repository.SearchHistoryRepository;
import com.sponus.coreinfras3.S3Service;
Expand Down Expand Up @@ -110,6 +111,16 @@ public PageResponse<OrganizationSearchResponse> searchOrganizations(PageConditio
() -> organizationRepository.countByNameContains(keyword)));
}

public PageResponse<OrganizationSearchResponse> searchOrganizationsV2(PageCondition pageCondition, String keyword,
Long organizationId) {

OrganizationSearchCondition condition = OrganizationSearchCondition.of(keyword, organizationId);
Pageable pageable = PageRequest.of(pageCondition.getPage() - 1, pageCondition.getSize());

return PageResponse.of(organizationRepository.searchOrganizationV2(condition, pageable)
.map(OrganizationSearchResponse::of));
}

public void createSearchHistory(Long organizationId, String keyword) {
SearchHistory searchHistory = findSearchHistory(organizationId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.sponus.sponusbe.domain.organization;

import java.util.List;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import com.sponus.coredomain.domain.organization.Organization;
import com.sponus.coredomain.domain.organization.enums.OrganizationType;
import com.sponus.coredomain.domain.organization.enums.ProfileStatus;
import com.sponus.sponusbe.domain.organization.dto.request.PageCondition;
import com.sponus.sponusbe.domain.organization.dto.response.OrganizationSearchResponse;
import com.sponus.sponusbe.domain.organization.dto.response.PageResponse;
import com.sponus.sponusbe.domain.organization.service.OrganizationService;

import jakarta.persistence.EntityManager;

@SpringBootTest
@Transactional
@ActiveProfiles("test")
class OrganizationServiceTest {

@Autowired
OrganizationService organizationService;

@Autowired
EntityManager em;

@BeforeEach
public void init() {
for (int i = 1; i <= 5; i++) {
Organization organization = Organization.builder()
.email("sponus_company" + i + "@gmail.com")
.name("sponus_company" + i)
.password("sponus_company1234#")
.organizationType(OrganizationType.COMPANY)
.profileStatus(ProfileStatus.ACTIVE)
.build();

em.persist(organization);
}
em.flush();
em.clear();
}

@Test
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
void searchV1() {
// given
PageCondition pageCondition = new PageCondition(0, 10);

// when
PageResponse<OrganizationSearchResponse> searchOrganizations = organizationService.searchOrganizations(
pageCondition, "sponus", null);

// then
List<String> expectedOrganizationNames = List.of(
"sponus_company1",
"sponus_company2",
"sponus_company3",
"sponus_company4",
"sponus_company5");
List<String> actualOrganizationNames = searchOrganizations.content().stream()
.map(OrganizationSearchResponse::name)
.toList();

Assertions.assertThat(actualOrganizationNames).containsExactlyInAnyOrderElementsOf(expectedOrganizationNames);
}

@Test
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
void searchV2() {
// given
PageCondition pageCondition = new PageCondition(0, 10);

// when
PageResponse<OrganizationSearchResponse> searchOrganizations = organizationService.searchOrganizationsV2(
pageCondition, "sponus", null);

// then
List<String> expectedOrganizationNames = List.of(
"sponus_company1",
"sponus_company2",
"sponus_company3",
"sponus_company4",
"sponus_company5");
List<String> actualOrganizationNames = searchOrganizations.content().stream()
.map(OrganizationSearchResponse::name)
.toList();

Assertions.assertThat(actualOrganizationNames).containsExactlyInAnyOrderElementsOf(expectedOrganizationNames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ void joinTest() {
"sponus_company", OrganizationType.COMPANY);

// when
Long organizationId = organizationService.createOrganization(request);
organizationService.createOrganization(request);

// then
List<Organization> organizationList = organizationRepository.findAll();
Assertions.assertThat(organizationList.size()).isEqualTo(1);
Assertions.assertThat(organizationList).hasSize(1);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.sponus.coredomain.domain.organization.Organization;
import com.sponus.coredomain.domain.organization.enums.OrganizationType;

public interface OrganizationRepository extends JpaRepository<Organization, Long> {
public interface OrganizationRepository extends JpaRepository<Organization, Long>, OrganizationRepositoryCustom {

Optional<Organization> findOrganizationByEmail(String email);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sponus.coredomain.domain.organization.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import com.sponus.coredomain.domain.organization.Organization;
import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition;

public interface OrganizationRepositoryCustom {

Page<Organization> searchOrganizationV2(OrganizationSearchCondition condition, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.sponus.coredomain.domain.organization.repository;

import static com.sponus.coredomain.domain.organization.QOrganization.*;
import static org.springframework.util.StringUtils.*;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;

import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.sponus.coredomain.domain.organization.Organization;
import com.sponus.coredomain.domain.organization.enums.ProfileStatus;
import com.sponus.coredomain.domain.organization.repository.conditions.OrganizationSearchCondition;

import jakarta.persistence.EntityManager;

public class OrganizationRepositoryCustomImpl implements OrganizationRepositoryCustom {

private final JPAQueryFactory queryFactory;

public OrganizationRepositoryCustomImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}

@Override
public Page<Organization> searchOrganizationV2(OrganizationSearchCondition condition, Pageable pageable) {

List<Organization> content = queryFactory
.selectFrom(organization)
.where(
keywordContains(condition.keyword()),
organizationIdNotEq(condition.organizationId()),
isActive()
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

long count = queryFactory
.selectFrom(organization)
.where(
keywordContains(condition.keyword()),
organizationIdNotEq(condition.organizationId()),
isActive()
)
.fetch()
.size();

return PageableExecutionUtils.getPage(content, pageable, () -> count);
}

private BooleanExpression keywordContains(String keyword) {
return hasText(keyword) ? organization.name.containsIgnoreCase(keyword) : null;
}

private BooleanExpression organizationIdNotEq(Long organizationId) {
return organizationId != null ? organization.id.ne(organizationId) : null;
}

private BooleanExpression isActive() {
return organization.profileStatus.eq(ProfileStatus.ACTIVE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sponus.coredomain.domain.organization.repository.conditions;

import lombok.Builder;

@Builder
public record OrganizationSearchCondition(
String keyword,
Long organizationId
) {
public static OrganizationSearchCondition of(String keyword, Long organizationId) {
return OrganizationSearchCondition.builder()
.keyword(keyword)
.organizationId(organizationId)
.build();
}
}
9 changes: 0 additions & 9 deletions core/core-infra-db/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
dependencies {

implementation project(':core:core-domain');
implementation 'com.mysql:mysql-connector-j:8.4.0'

//querydsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"

runtimeOnly 'com.h2database:h2'
}

Expand Down
41 changes: 0 additions & 41 deletions core/core-infra-db/out/production/resources/application-db.yml

This file was deleted.

Loading

0 comments on commit 8e3a794

Please sign in to comment.