diff --git a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcFragment.java b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcFragment.java index 659fcbf..26e7140 100644 --- a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcFragment.java +++ b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcFragment.java @@ -9,6 +9,9 @@ import java.util.Optional; import java.util.function.Function; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + public interface QuerydslJdbcFragment { /** @@ -24,6 +27,8 @@ public interface QuerydslJdbcFragment { List queryMany(Function, SQLQuery> query); + Page queryMany(Function, SQLQuery> query, Pageable pageable); + /** * @return amount of affected rows */ diff --git a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcPredicateExecutor.java b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcPredicateExecutor.java index 9e83a96..091e871 100644 --- a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcPredicateExecutor.java +++ b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/QuerydslJdbcPredicateExecutor.java @@ -184,6 +184,15 @@ List queryMany(SQLQuery query) { return result; } + Page queryMany(SQLQuery query, Pageable pageable) { + Assert.notNull(query, "Query must not be null!"); + Assert.notNull(pageable, "Pageable must not be null!"); + + var content = queryMany(querydsl.applyPagination(pageable, query)); + + return PageableExecutionUtils.getPage(content, pageable, query::fetchCount); + } + @Nullable private List query(SQLQuery query, RowMapperResultSetExtractor rowMapperResultSetExtractor) { diff --git a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/SimpleQuerydslJdbcFragment.java b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/SimpleQuerydslJdbcFragment.java index 520805e..88e686a 100644 --- a/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/SimpleQuerydslJdbcFragment.java +++ b/infobip-spring-data-jdbc-querydsl/src/main/java/com/infobip/spring/data/jdbc/SimpleQuerydslJdbcFragment.java @@ -15,15 +15,22 @@ */ package com.infobip.spring.data.jdbc; -import com.querydsl.core.types.*; -import com.querydsl.sql.*; -import com.querydsl.sql.dml.SQLUpdateClause; -import org.springframework.transaction.annotation.Transactional; - import java.util.List; import java.util.Optional; import java.util.function.Function; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Transactional; + +import com.querydsl.core.types.ConstructorExpression; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.Predicate; +import com.querydsl.sql.RelationalPath; +import com.querydsl.sql.SQLQuery; +import com.querydsl.sql.SQLQueryFactory; +import com.querydsl.sql.dml.SQLUpdateClause; + @Transactional(readOnly = true) public class SimpleQuerydslJdbcFragment implements QuerydslJdbcFragment { @@ -58,6 +65,12 @@ public List queryMany(Function, SQLQuery> query) { return querydslJdbcPredicateExecutor.queryMany(query.apply(sqlQueryFactory.query())); } + @Override + public Page queryMany(Function, SQLQuery> query, Pageable pageable) { + var newQuery = sqlQueryFactory.query().select(entityProjection()); + return querydslJdbcPredicateExecutor.queryMany(query.apply(newQuery), pageable); + } + @Override @Transactional public long update(Function update) { diff --git a/infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc/QuerydslJdbcRepositoryTest.java b/infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc/QuerydslJdbcRepositoryTest.java index 8a8fc94..dee773f 100644 --- a/infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc/QuerydslJdbcRepositoryTest.java +++ b/infobip-spring-data-jdbc-querydsl/src/test/java/com/infobip/spring/data/jdbc/QuerydslJdbcRepositoryTest.java @@ -1,23 +1,27 @@ package com.infobip.spring.data.jdbc; -import static com.infobip.spring.data.jdbc.QPerson.person; -import static com.infobip.spring.data.jdbc.QPersonSettings.personSettings; -import static org.assertj.core.api.BDDAssertions.then; +import static com.infobip.spring.data.jdbc.QPerson.*; +import static com.infobip.spring.data.jdbc.QPersonSettings.*; +import static org.assertj.core.api.BDDAssertions.*; import java.time.ZoneOffset; import java.util.List; import java.util.TimeZone; import java.util.stream.Collectors; -import com.infobip.spring.data.jdbc.extension.CustomQuerydslJdbcRepository; -import com.querydsl.core.types.Projections; -import com.querydsl.sql.SQLQueryFactory; -import lombok.AllArgsConstructor; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; +import com.infobip.spring.data.jdbc.extension.CustomQuerydslJdbcRepository; +import com.querydsl.core.types.Projections; +import com.querydsl.sql.SQLQueryFactory; + +import lombok.AllArgsConstructor; + @AllArgsConstructor public class QuerydslJdbcRepositoryTest extends TestBase { @@ -53,7 +57,8 @@ void shouldStreamAll() { actual = stream.collect(Collectors.toList()); } - then(actual).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder(johnDoe, johnyRoe, janeDoe); + then(actual).usingRecursiveFieldByFieldElementComparator() + .containsExactlyInAnyOrder(johnDoe, johnyRoe, janeDoe); } @Test @@ -151,6 +156,27 @@ void shouldQueryMany() { then(actual).containsOnly(johnDoe); } + @Test + void shouldQueryManyWithPageable() { + // given + givenSavedPerson("John", "Doe"); + givenSavedPerson("Johny", "Roe"); + var janeDoe = givenSavedPerson("Jane", "Doe"); + givenSavedPerson("John", "Roe"); + givenSavedPerson("Janie", "Doe"); + var janeStone = givenSavedPerson("Jane", "Stone"); + + var page = PageRequest.of(0, 2, Sort.by(Sort.Order.asc("firstName"))); + + var actual = repository.queryMany(sqlQuery -> sqlQuery.from(person) + .where(person.firstName.in("John", "Jane")), page); + + then(actual.getSize()).isEqualTo(2); + then(actual.getTotalElements()).isEqualTo(4); + then(actual.getTotalPages()).isEqualTo(2); + then(actual).containsExactlyInAnyOrder(janeDoe, janeStone); + } + @Test void shouldProject() { @@ -184,8 +210,8 @@ void shouldUpdate() { then(actual).isEqualTo(1); then(repository.findAll()).extracting(Person::firstName) - .containsExactlyInAnyOrder("John", "John", "Jane") - .hasSize(3); + .containsExactlyInAnyOrder("John", "John", "Jane") + .hasSize(3); } @Test @@ -259,7 +285,7 @@ void shouldSupportMultipleConstructors() { void shouldExtendSimpleQuerydslJdbcRepository() { // then then(repository).isInstanceOf(QuerydslJdbcRepository.class) - .isNotInstanceOf(CustomQuerydslJdbcRepository.class); + .isNotInstanceOf(CustomQuerydslJdbcRepository.class); } @Transactional @@ -270,9 +296,9 @@ void springDataAndQuerydslShouldHandleTimeZoneTheSameForSameTimeZone() { // when sqlQueryFactory.insert(person) - .columns(person.firstName, person.lastName, person.createdAt) - .values(givenPerson.firstName(), givenPerson.lastName(), givenPerson.createdAt()) - .execute(); + .columns(person.firstName, person.lastName, person.createdAt) + .values(givenPerson.firstName(), givenPerson.lastName(), givenPerson.createdAt()) + .execute(); repository.save(givenPerson); // then