Merge branch '1.2.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.graphql.data.query;
|
||||
import java.util.Collection;
|
||||
|
||||
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.graphql.data.pagination.ConnectionAdapter;
|
||||
@@ -34,6 +35,9 @@ import org.springframework.graphql.data.pagination.CursorStrategy;
|
||||
public final class WindowConnectionAdapter
|
||||
extends ConnectionAdapterSupport<ScrollPosition> implements ConnectionAdapter {
|
||||
|
||||
private static final long ZERO_OFFSET_ADJUSTMENT =
|
||||
OffsetScrollPosition.positionFunction(0).apply(0).getOffset();
|
||||
|
||||
|
||||
public WindowConnectionAdapter(CursorStrategy<ScrollPosition> strategy) {
|
||||
super(strategy);
|
||||
@@ -55,7 +59,7 @@ public final class WindowConnectionAdapter
|
||||
public boolean hasPrevious(Object container) {
|
||||
Window<?> window = window(container);
|
||||
if (!window.isEmpty()) {
|
||||
ScrollPosition position = window.positionAt(0);
|
||||
ScrollPosition position = positionAt(window, 0);
|
||||
if (position instanceof KeysetScrollPosition keysetPosition) {
|
||||
return (keysetPosition.scrollsBackward() && window.hasNext());
|
||||
}
|
||||
@@ -70,7 +74,7 @@ public final class WindowConnectionAdapter
|
||||
public boolean hasNext(Object container) {
|
||||
Window<?> window = window(container);
|
||||
if (!window.isEmpty()) {
|
||||
ScrollPosition pos = window.positionAt(0);
|
||||
ScrollPosition pos = positionAt(window, 0);
|
||||
if (pos instanceof KeysetScrollPosition keysetPos) {
|
||||
return (keysetPos.scrollsForward() && window.hasNext());
|
||||
}
|
||||
@@ -83,10 +87,22 @@ public final class WindowConnectionAdapter
|
||||
|
||||
@Override
|
||||
public String cursorAt(Object container, int index) {
|
||||
ScrollPosition position = window(container).positionAt(index);
|
||||
ScrollPosition position = positionAt(window(container), index);
|
||||
return getCursorStrategy().toCursor(position);
|
||||
}
|
||||
|
||||
private ScrollPosition positionAt(Window<?> window, int index) {
|
||||
ScrollPosition position = window.positionAt(index);
|
||||
|
||||
// Workaround for OffsetScrollPosition#positionFunction adding 1 to the actual offset:
|
||||
// See https://github.com/spring-projects/spring-data-commons/issues/3070
|
||||
if (ZERO_OFFSET_ADJUSTMENT > 0 && position instanceof OffsetScrollPosition offsetPos) {
|
||||
position = offsetPos.advanceBy(-ZERO_OFFSET_ADJUSTMENT);
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Window<T> window(Object container) {
|
||||
return (Window<T>) container;
|
||||
|
||||
@@ -327,14 +327,6 @@ public class GraphQlWebSocketHandler extends TextWebSocketHandler implements Sub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable exception) {
|
||||
SessionState info = this.sessionInfoMap.remove(session.getId());
|
||||
if (info != null) {
|
||||
info.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
|
||||
String id = session.getId();
|
||||
|
||||
@@ -55,13 +55,13 @@ public class SchemaMappingPaginationTests {
|
||||
ResponseHelper.forResponse(response).assertData(
|
||||
"{\"books\":{" +
|
||||
"\"edges\":[" +
|
||||
"{\"cursor\":\"O_0\",\"node\":{\"id\":\"4\",\"name\":\"To The Lighthouse\"}}," +
|
||||
"{\"cursor\":\"O_1\",\"node\":{\"id\":\"5\",\"name\":\"Animal Farm\"}}" +
|
||||
"{\"cursor\":\"O_3\",\"node\":{\"id\":\"4\",\"name\":\"To The Lighthouse\"}}," +
|
||||
"{\"cursor\":\"O_4\",\"node\":{\"id\":\"5\",\"name\":\"Animal Farm\"}}" +
|
||||
"]," +
|
||||
"\"pageInfo\":{" +
|
||||
"\"startCursor\":\"O_0\"," +
|
||||
"\"endCursor\":\"O_1\"," +
|
||||
"\"hasPreviousPage\":false," +
|
||||
"\"startCursor\":\"O_3\"," +
|
||||
"\"endCursor\":\"O_4\"," +
|
||||
"\"hasPreviousPage\":true," +
|
||||
"\"hasNextPage\":false" +
|
||||
"}}}");
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class SchemaMappingPaginationTests {
|
||||
int offset = (int) ((OffsetScrollPosition) subrange.position().orElse(ScrollPosition.offset())).getOffset();
|
||||
int count = subrange.count().orElse(5);
|
||||
List<Book> books = BookSource.books().subList(offset, offset + count);
|
||||
return Window.from(books, ScrollPosition::offset);
|
||||
return Window.from(books, OffsetScrollPosition.positionFunction(offset));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2023 the original author or authors.
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.data.domain.OffsetScrollPosition;
|
||||
import org.springframework.data.domain.ScrollPosition;
|
||||
import org.springframework.data.domain.Window;
|
||||
import org.springframework.graphql.Book;
|
||||
@@ -42,7 +43,7 @@ public class WindowConnectionAdapterTests {
|
||||
@Test
|
||||
void paged() {
|
||||
List<Book> books = BookSource.books();
|
||||
Window<Book> window = Window.from(books, offset -> ScrollPosition.offset(35 + offset), true);
|
||||
Window<Book> window = Window.from(books, OffsetScrollPosition.positionFunction(35), true);
|
||||
|
||||
assertThat(this.adapter.getContent(window)).isEqualTo(books);
|
||||
assertThat(this.adapter.hasNext(window)).isTrue();
|
||||
@@ -53,7 +54,7 @@ public class WindowConnectionAdapterTests {
|
||||
@Test
|
||||
void unpaged() {
|
||||
List<Book> books = BookSource.books();
|
||||
Window<Book> window = Window.from(books, ScrollPosition::offset);
|
||||
Window<Book> window = Window.from(books, OffsetScrollPosition.positionFunction(0));
|
||||
|
||||
assertThat(this.adapter.getContent(window)).isEqualTo(books);
|
||||
assertThat(this.adapter.hasNext(window)).isFalse();
|
||||
|
||||
@@ -141,13 +141,13 @@ class QueryByExampleDataFetcherJpaTests {
|
||||
|
||||
List<Map<String, Object>> edges = ResponseHelper.forResponse(response).toEntity("books.edges", List.class);
|
||||
assertThat(edges.size()).isEqualTo(2);
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_4");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_5");
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_3");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_4");
|
||||
|
||||
Map<String, Object> pageInfo = ResponseHelper.forResponse(response).toEntity("books.pageInfo", Map.class);
|
||||
assertThat(pageInfo.size()).isEqualTo(4);
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_5");
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_3");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("hasPreviousPage")).isEqualTo(true);
|
||||
assertThat(pageInfo.get("hasNextPage")).isEqualTo(false);
|
||||
};
|
||||
|
||||
@@ -138,13 +138,13 @@ class QueryByExampleDataFetcherMongoDbTests {
|
||||
|
||||
List<Map<String, Object>> edges = ResponseHelper.forResponse(response).toEntity("books.edges", List.class);
|
||||
assertThat(edges.size()).isEqualTo(2);
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_4");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_5");
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_3");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_4");
|
||||
|
||||
Map<String, Object> pageInfo = ResponseHelper.forResponse(response).toEntity("books.pageInfo", Map.class);
|
||||
assertThat(pageInfo.size()).isEqualTo(4);
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_5");
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_3");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("hasPreviousPage")).isEqualTo(true);
|
||||
assertThat(pageInfo.get("hasNextPage")).isEqualTo(false);
|
||||
};
|
||||
|
||||
@@ -163,13 +163,13 @@ class QueryByExampleDataFetcherReactiveMongoDbTests {
|
||||
|
||||
List<Map<String, Object>> edges = ResponseHelper.forResponse(response).toEntity("books.edges", List.class);
|
||||
assertThat(edges.size()).isEqualTo(2);
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_4");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_5");
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_3");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_4");
|
||||
|
||||
Map<String, Object> pageInfo = ResponseHelper.forResponse(response).toEntity("books.pageInfo", Map.class);
|
||||
assertThat(pageInfo.size()).isEqualTo(4);
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_5");
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_3");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("hasPreviousPage")).isEqualTo(true);
|
||||
assertThat(pageInfo.get("hasNextPage")).isEqualTo(false);
|
||||
};
|
||||
|
||||
@@ -140,13 +140,13 @@ class QueryByExampleDataFetcherNeo4jTests {
|
||||
|
||||
List<Map<String, Object>> edges = ResponseHelper.forResponse(response).toEntity("books.edges", List.class);
|
||||
assertThat(edges.size()).isEqualTo(2);
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_4");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_5");
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_3");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_4");
|
||||
|
||||
Map<String, Object> pageInfo = ResponseHelper.forResponse(response).toEntity("books.pageInfo", Map.class);
|
||||
assertThat(pageInfo.size()).isEqualTo(4);
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_5");
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_3");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("hasPreviousPage")).isEqualTo(true);
|
||||
assertThat(pageInfo.get("hasNextPage")).isEqualTo(false);
|
||||
};
|
||||
|
||||
@@ -176,13 +176,13 @@ class QueryByExampleDataFetcherReactiveNeo4jDbTests {
|
||||
|
||||
List<Map<String, Object>> edges = ResponseHelper.forResponse(response).toEntity("books.edges", List.class);
|
||||
assertThat(edges.size()).isEqualTo(2);
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_4");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_5");
|
||||
assertThat(edges.get(0).get("cursor")).isEqualTo("O_3");
|
||||
assertThat(edges.get(1).get("cursor")).isEqualTo("O_4");
|
||||
|
||||
Map<String, Object> pageInfo = ResponseHelper.forResponse(response).toEntity("books.pageInfo", Map.class);
|
||||
assertThat(pageInfo.size()).isEqualTo(4);
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_5");
|
||||
assertThat(pageInfo.get("startCursor")).isEqualTo("O_3");
|
||||
assertThat(pageInfo.get("endCursor")).isEqualTo("O_4");
|
||||
assertThat(pageInfo.get("hasPreviousPage")).isEqualTo(true);
|
||||
assertThat(pageInfo.get("hasNextPage")).isEqualTo(false);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user