Skip to content

Commit

Permalink
querydsl with jpa is implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
musab.bozkurt committed Feb 5, 2024
1 parent f38a39d commit 8678c97
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 6 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,5 @@
- [Spring Boot Rest Controller Unit Test with @WebMvcTest](https://www.bezkoder.com/spring-boot-webmvctest/)
- [Redis Commands](https://auth0.com/blog/introduction-to-redis-install-cli-commands-and-data-types/)
- [Running RedisInsight using Docker Compose](https://collabnix.com/running-redisinsight-using-docker-compose/)
- [Google Play Integrity API](https://developer.android.com/google/play/integrity)
- [Google Play Integrity API](https://developer.android.com/google/play/integrity)
- [A Guide to Querydsl with JPA](https://www.baeldung.com/querydsl-with-jpa-tutorial)
32 changes: 32 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@
<artifactId>spring-data-envers</artifactId>
</dependency>

<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>5.0.0</version>
<classifier>jakarta</classifier>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
<classifier>jakarta</classifier>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down Expand Up @@ -224,6 +239,23 @@
</configuration>
</plugin>

<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.mb.livedataservice.api.controller;

import com.mb.livedataservice.api.filter.ApiTutorialFilter;
import com.mb.livedataservice.api.request.ApiTutorialRequest;
import com.mb.livedataservice.api.request.ApiTutorialUpdateRequest;
import com.mb.livedataservice.api.response.ApiTutorialResponse;
import com.mb.livedataservice.mapper.TutorialMapper;
import com.mb.livedataservice.service.TutorialService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -57,4 +60,9 @@ public ResponseEntity<HttpStatus> deleteAllTutorials() {
public ResponseEntity<List<ApiTutorialResponse>> findByPublished() {
return new ResponseEntity<>(tutorialMapper.map(tutorialService.findByPublished(true)), HttpStatus.OK);
}

@GetMapping("/tutorials/filter")
public ResponseEntity<Page<ApiTutorialResponse>> findAll(ApiTutorialFilter apiTutorialFilter, Pageable pageable) {
return new ResponseEntity<>(tutorialService.findAll(tutorialMapper.map(apiTutorialFilter), pageable).map(tutorialMapper::map), HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.mb.livedataservice.api.filter;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiTutorialFilter {

private String title;

private String description;

private boolean published;
}
8 changes: 8 additions & 0 deletions src/main/java/com/mb/livedataservice/data/filter/Filter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mb.livedataservice.data.filter;

import com.querydsl.core.types.Predicate;

public interface Filter {

Predicate toPredicate();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.mb.livedataservice.data.filter;

import com.mb.livedataservice.data.model.QTutorial;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TutorialFilter implements Filter {

private String title;

private String description;

private boolean published;

@Override
public Predicate toPredicate() {
QTutorial qTutorial = QTutorial.tutorial;
BooleanExpression predicate = qTutorial.id.isNotNull();

if (StringUtils.isNotBlank(title)) {
predicate = predicate.and(qTutorial.title.equalsIgnoreCase(title));
}

if (StringUtils.isNotBlank(description)) {
predicate = predicate.and(qTutorial.description.equalsIgnoreCase(description));
}

return predicate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface ScoreBoardRepository extends JpaRepository<ScoreBoard, Long> {
public interface ScoreBoardRepository extends JpaRepository<ScoreBoard, Long>, QuerydslPredicateExecutor<ScoreBoard> {

Optional<ScoreBoard> findByHomeTeamNameAndAwayTeamNameAndDeletedIsFalse(String homeTeamName, String awayTeamName);

Expand All @@ -20,4 +21,4 @@ public interface ScoreBoardRepository extends JpaRepository<ScoreBoard, Long> {
Optional<ScoreBoard> findByIdAndDeletedIsFalse(Long id);

List<ScoreBoard> findAllByDeletedIsTrue(Sort sort);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import com.mb.livedataservice.data.model.Tutorial;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;

import java.util.List;

public interface TutorialRepository extends JpaRepository<Tutorial, Long> {
public interface TutorialRepository extends JpaRepository<Tutorial, Long>, QuerydslPredicateExecutor<Tutorial> {

List<Tutorial> findByPublished(boolean published);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.mb.livedataservice.mapper;

import com.mb.livedataservice.api.filter.ApiTutorialFilter;
import com.mb.livedataservice.api.request.ApiTutorialRequest;
import com.mb.livedataservice.api.request.ApiTutorialUpdateRequest;
import com.mb.livedataservice.api.response.ApiTutorialResponse;
import com.mb.livedataservice.data.filter.TutorialFilter;
import com.mb.livedataservice.data.model.Tutorial;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
Expand All @@ -21,4 +23,6 @@ public interface TutorialMapper {
ApiTutorialResponse map(Tutorial tutorial);

List<ApiTutorialResponse> map(List<Tutorial> tutorial);

TutorialFilter map(ApiTutorialFilter apiTutorialFilter);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.mb.livedataservice.service;

import com.mb.livedataservice.data.filter.TutorialFilter;
import com.mb.livedataservice.data.model.Tutorial;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

Expand All @@ -19,4 +22,6 @@ public interface TutorialService {
void deleteAll();

List<Tutorial> findByPublished(boolean b);

Page<Tutorial> findAll(TutorialFilter filter, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mb.livedataservice.service.impl;

import com.mb.livedataservice.data.filter.TutorialFilter;
import com.mb.livedataservice.data.model.Tutorial;
import com.mb.livedataservice.data.repository.TutorialRepository;
import com.mb.livedataservice.exception.BaseException;
Expand All @@ -8,6 +9,8 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
Expand Down Expand Up @@ -61,4 +64,9 @@ public void deleteAll() {
public List<Tutorial> findByPublished(boolean b) {
return tutorialRepository.findByPublished(b);
}
}

@Override
public Page<Tutorial> findAll(TutorialFilter filter, Pageable pageable) {
return tutorialRepository.findAll(filter.toPredicate(), pageable);
}
}
5 changes: 5 additions & 0 deletions src/test/java/com/mb/livedataservice/base/BaseUnitTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mb.livedataservice.base;

import com.mb.livedataservice.api.filter.ApiTutorialFilter;
import com.mb.livedataservice.api.request.ApiScoreBoardRequest;
import com.mb.livedataservice.api.request.ApiScoreBoardUpdateRequest;
import com.mb.livedataservice.api.request.ApiTutorialRequest;
Expand Down Expand Up @@ -139,4 +140,8 @@ public Tutorial getUpdatedTutorial() {
public ApiTutorialResponse getUpdatedApiTutorialResponse() {
return new ApiTutorialResponse(1, "Updated", "Updated", true);
}

public ApiTutorialFilter getApiTutorialFilter() {
return new ApiTutorialFilter("Updated", "Updated", true);
}
}
42 changes: 42 additions & 0 deletions src/test/java/com/mb/livedataservice/helper/RestResponsePage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.mb.livedataservice.helper;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.util.ArrayList;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class RestResponsePage<T> extends PageImpl<T> {

@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public RestResponsePage(@JsonProperty("content") List<T> content,
@JsonProperty("number") int number,
@JsonProperty("size") int size,
@JsonProperty("totalElements") Long totalElements,
@JsonProperty("pageable") JsonNode pageable,
@JsonProperty("first") boolean first,
@JsonProperty("last") boolean last,
@JsonProperty("totalPages") int totalPages,
@JsonProperty("sort") JsonNode sort,
@JsonProperty("numberOfElements") int numberOfElements) {
super(content, PageRequest.of(number, size), totalElements);
}

public RestResponsePage(List<T> content, Pageable pageable, long total) {
super(content, pageable, total);
}

public RestResponsePage(List<T> content) {
super(content);
}

public RestResponsePage() {
super(new ArrayList<>());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@
import com.mb.livedataservice.api.response.ApiTutorialResponse;
import com.mb.livedataservice.base.BaseUnitTest;
import com.mb.livedataservice.data.model.Tutorial;
import com.mb.livedataservice.helper.RestResponsePage;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.KafkaContainer;
import org.testcontainers.containers.PostgreSQLContainer;
Expand Down Expand Up @@ -149,4 +153,24 @@ void shouldGetAllTutorialsByPublishedTrue() {

assertThat(tutorials.length).isGreaterThan(100);
}
}

@Test
void shouldGetAllTutorialsByFilter() {
ParameterizedTypeReference<RestResponsePage<ApiTutorialResponse>> responseType = new ParameterizedTypeReference<>() {
};

UriComponents uriComponents = UriComponentsBuilder.fromPath("/api/tutorials/filter")
.queryParam("pageSize", "2")
.queryParam("page", "0")
.queryParam("description", "Description1")
.queryParam("published", true)
.build();

ResponseEntity<RestResponsePage<ApiTutorialResponse>> tutorials = restTemplate.exchange(uriComponents.toString(), HttpMethod.GET, null, responseType);
RestResponsePage<ApiTutorialResponse> tutorialsBody = tutorials.getBody();

assertThat(tutorials.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(tutorialsBody).isNotNull();
assertThat(tutorialsBody.getNumberOfElements()).isGreaterThanOrEqualTo(1);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.mb.livedataservice.mapper;

import com.mb.livedataservice.api.filter.ApiTutorialFilter;
import com.mb.livedataservice.api.request.ApiTutorialRequest;
import com.mb.livedataservice.api.request.ApiTutorialUpdateRequest;
import com.mb.livedataservice.api.response.ApiTutorialResponse;
import com.mb.livedataservice.base.BaseUnitTest;
import com.mb.livedataservice.data.filter.TutorialFilter;
import com.mb.livedataservice.data.model.Tutorial;
import org.junit.jupiter.api.Test;
import org.mapstruct.factory.Mappers;
Expand Down Expand Up @@ -73,4 +75,18 @@ void map_ListOfTutorialToListOfApiTutorialResponse_ShouldSucceed() {
assertEquals(tutorials.getFirst().getDescription(), result.getFirst().getDescription());
assertEquals(tutorials.getFirst().isPublished(), result.getFirst().isPublished());
}

@Test
void map_ApiTutorialFilterToTutorialFilter_ShouldSucceed() {
// arrange
ApiTutorialFilter apiTutorialFilter = getApiTutorialFilter();

// act
TutorialFilter result = tutorialMapper.map(apiTutorialFilter);

// assertion
assertEquals(apiTutorialFilter.getTitle(), result.getTitle());
assertEquals(apiTutorialFilter.getDescription(), result.getDescription());
assertEquals(apiTutorialFilter.isPublished(), result.isPublished());
}
}

0 comments on commit 8678c97

Please sign in to comment.