Scroll API Implementation (#14435)
Co-authored-by: technoddy <mail.technoddy@gmail.com>
This commit is contained in:
parent
787ed13597
commit
aae5f7dc38
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>com.baeldung.boot.persistence</groupId>
|
||||||
|
<artifactId>spring-boot-persistence-4</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>spring-boot-persistence-4</name>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit</groupId>
|
||||||
|
<artifactId>junit-bom</artifactId>
|
||||||
|
<version>${junit-jupiter.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring.boot.dependencies}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<spring.boot.dependencies>3.1.0</spring.boot.dependencies>
|
||||||
|
<junit-jupiter.version>5.9.3</junit-jupiter.version>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.baeldung.scrollapi;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class ScrollAPIApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ScrollAPIApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.baeldung.scrollapi.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "BOOK_REVIEWS")
|
||||||
|
public class BookReview {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_reviews_reviews_id_seq")
|
||||||
|
@SequenceGenerator(name = "book_reviews_reviews_id_seq", sequenceName = "book_reviews_reviews_id_seq", allocationSize = 1)
|
||||||
|
private Long reviewsId;
|
||||||
|
private String userId;
|
||||||
|
private String isbn;
|
||||||
|
private String bookRating;
|
||||||
|
|
||||||
|
public Long getReviewsId() {
|
||||||
|
return reviewsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReviewsId(Long reviewsId) {
|
||||||
|
this.reviewsId = reviewsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIsbn() {
|
||||||
|
return isbn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsbn(String isbn) {
|
||||||
|
this.isbn = isbn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBookRating() {
|
||||||
|
return bookRating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBookRating(String bookRating) {
|
||||||
|
this.bookRating = bookRating;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "BookReview{" + "reviewsId=" + reviewsId + ", userId='" + userId + '\'' + ", isbn='" + isbn + '\'' + ", bookRating='" + bookRating + '\'' + '}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.baeldung.scrollapi.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.KeysetScrollPosition;
|
||||||
|
import org.springframework.data.domain.OffsetScrollPosition;
|
||||||
|
import org.springframework.data.domain.Window;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.repository.Repository;
|
||||||
|
|
||||||
|
import com.baeldung.scrollapi.entity.BookReview;
|
||||||
|
|
||||||
|
public interface BookRepository extends JpaRepository<BookReview, Long> {
|
||||||
|
|
||||||
|
Window<BookReview> findFirst5ByBookRating(String bookRating, OffsetScrollPosition position);
|
||||||
|
|
||||||
|
Window<BookReview> findFirst5ByBookRating(String bookRating, KeysetScrollPosition position);
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.baeldung.scrollapi.service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.KeysetScrollPosition;
|
||||||
|
import org.springframework.data.domain.OffsetScrollPosition;
|
||||||
|
import org.springframework.data.domain.ScrollPosition;
|
||||||
|
import org.springframework.data.domain.Window;
|
||||||
|
import org.springframework.data.support.WindowIterator;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.baeldung.scrollapi.entity.BookReview;
|
||||||
|
import com.baeldung.scrollapi.repository.BookRepository;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BookLogic {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookRepository bookRepository;
|
||||||
|
|
||||||
|
public List<BookReview> getBooksUsingOffset(String rating) {
|
||||||
|
OffsetScrollPosition offset = ScrollPosition.offset();
|
||||||
|
|
||||||
|
Window<BookReview> bookReviews = bookRepository.findFirst5ByBookRating(rating, offset);
|
||||||
|
List<BookReview> bookReviewsResult = new ArrayList<>();
|
||||||
|
do {
|
||||||
|
bookReviews.forEach(bookReviewsResult::add);
|
||||||
|
bookReviews = bookRepository.findFirst5ByBookRating(rating, (OffsetScrollPosition) bookReviews.positionAt(bookReviews.size() - 1));
|
||||||
|
} while (!bookReviews.isEmpty() && bookReviews.hasNext());
|
||||||
|
|
||||||
|
return bookReviewsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BookReview> getBooksUsingOffSetFilteringAndWindowIterator(String rating) {
|
||||||
|
WindowIterator<BookReview> bookReviews = WindowIterator.of(position -> bookRepository.findFirst5ByBookRating("3.5", (OffsetScrollPosition) position))
|
||||||
|
.startingAt(ScrollPosition.offset());
|
||||||
|
List<BookReview> bookReviewsResult = new ArrayList<>();
|
||||||
|
|
||||||
|
bookReviews.forEachRemaining(bookReviewsResult::add);
|
||||||
|
return bookReviewsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BookReview> getBooksUsingKeySetFiltering(String rating) {
|
||||||
|
WindowIterator<BookReview> bookReviews = WindowIterator.of(position -> bookRepository.findFirst5ByBookRating(rating, (KeysetScrollPosition) position))
|
||||||
|
.startingAt(ScrollPosition.keyset());
|
||||||
|
List<BookReview> bookReviewsResult = new ArrayList<>();
|
||||||
|
|
||||||
|
bookReviews.forEachRemaining(bookReviewsResult::add);
|
||||||
|
return bookReviewsResult;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
logging.level.org.hibernate:
|
||||||
|
SQL: DEBUG
|
||||||
|
type.descriptor.sql.BasicBinder: TRACE
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.baeldung.boot.scrollapi.service;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
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 com.baeldung.scrollapi.ScrollAPIApplication;
|
||||||
|
import com.baeldung.scrollapi.entity.BookReview;
|
||||||
|
import com.baeldung.scrollapi.repository.BookRepository;
|
||||||
|
import com.baeldung.scrollapi.service.BookLogic;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = ScrollAPIApplication.class)
|
||||||
|
class BookLogicUnitTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookRepository bookRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookLogic bookLogic;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeEach() {
|
||||||
|
IntStream.rangeClosed(1, 5)
|
||||||
|
.forEach(i -> insertBookReview());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterEach() {
|
||||||
|
bookRepository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBookReviewInTable_whenGetBooksUsingOffset_returnsBookReviews() {
|
||||||
|
List<BookReview> bookReviews = bookLogic.getBooksUsingOffset("3.5");
|
||||||
|
assertThat(bookReviews.size()).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBookReviewInTable_whenGetBooksUsingOffSetFilteringAndWindowIterator_returnsBookReviews() {
|
||||||
|
List<BookReview> bookReviews = bookLogic.getBooksUsingOffSetFilteringAndWindowIterator("3.5");
|
||||||
|
assertThat(bookReviews.size()).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBookReviewInTable_whenGetBooksUsingKeySetFiltering_returnsBookReviews() {
|
||||||
|
List<BookReview> bookReviews = bookLogic.getBooksUsingKeySetFiltering("3.5");
|
||||||
|
assertThat(bookReviews.size()).isEqualTo(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertBookReview() {
|
||||||
|
BookReview bookReview = getBookReview();
|
||||||
|
bookRepository.save(bookReview);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BookReview getBookReview() {
|
||||||
|
BookReview bookReview = new BookReview();
|
||||||
|
String seed = UUID.randomUUID()
|
||||||
|
.toString();
|
||||||
|
bookReview.setIsbn("isbn" + seed);
|
||||||
|
bookReview.setBookRating("3.5");
|
||||||
|
bookReview.setUserId(seed);
|
||||||
|
|
||||||
|
return bookReview;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
# spring.datasource.x
|
||||||
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
|
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=sa
|
Loading…
Reference in New Issue