Polishing Window scrolling API.
Moved general-purpose factory methods to the common ScrollPosition interface. Introduced a couple of domain specific methods to conveniently work with both Keyset- (to e.g. change direction) and OffsetScrollPosition (to e.g. advance the offset). Consolidated unit tests accordingly. Moved WindowIterator to ….data.support package. Fixed case of Direction enum values. Fixes #2824.
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.KeysetScrollPosition.Direction;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link KeysetScrollPosition}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class KeysetScrollPositionUnitTests {
|
||||
|
||||
@Test // GH-2151
|
||||
void equalsAndHashCode() {
|
||||
|
||||
KeysetScrollPosition foo1 = KeysetScrollPosition.of(Collections.singletonMap("k", "v"));
|
||||
KeysetScrollPosition foo2 = KeysetScrollPosition.of(Collections.singletonMap("k", "v"));
|
||||
KeysetScrollPosition bar = KeysetScrollPosition.of(Collections.singletonMap("k", "v"), Direction.Backward);
|
||||
|
||||
assertThat(foo1).isEqualTo(foo2).hasSameClassAs(foo2);
|
||||
assertThat(foo1).isNotEqualTo(bar).doesNotHaveSameHashCodeAs(bar);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.domain.OffsetScrollPosition.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link OffsetScrollPosition}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class OffsetScrollPositionUnitTests {
|
||||
|
||||
@Test // GH-2151
|
||||
void equalsAndHashCode() {
|
||||
|
||||
OffsetScrollPosition foo1 = OffsetScrollPosition.of(1);
|
||||
OffsetScrollPosition foo2 = OffsetScrollPosition.of(1);
|
||||
OffsetScrollPosition bar = OffsetScrollPosition.of(2);
|
||||
|
||||
assertThat(foo1).isEqualTo(foo2).hasSameClassAs(foo2);
|
||||
assertThat(foo1).isNotEqualTo(bar).doesNotHaveSameHashCodeAs(bar);
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void shouldCreateCorrectIndexPosition() {
|
||||
|
||||
assertThat(positionFunction(0).apply(0)).isEqualTo(OffsetScrollPosition.of(1));
|
||||
assertThat(positionFunction(0).apply(1)).isEqualTo(OffsetScrollPosition.of(2));
|
||||
|
||||
assertThat(positionFunction(100).apply(0)).isEqualTo(OffsetScrollPosition.of(101));
|
||||
assertThat(positionFunction(100).apply(1)).isEqualTo(OffsetScrollPosition.of(102));
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,6 @@ class PageRequestUnitTests extends AbstractPageRequestUnitTests {
|
||||
|
||||
PageRequest request = PageRequest.of(1, 10);
|
||||
|
||||
assertThat(request.toScrollPosition()).isEqualTo(OffsetScrollPosition.of(10));
|
||||
assertThat(request.toScrollPosition()).isEqualTo(ScrollPosition.offset(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.domain.OffsetScrollPosition.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.ScrollPosition.Direction;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link KeysetScrollPosition}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
class ScrollPositionUnitTests {
|
||||
|
||||
private static final Map<String, ?> KEYS = Collections.singletonMap("k", "v");
|
||||
|
||||
@Test // GH-2151
|
||||
void equalsAndHashCodeForKeysets() {
|
||||
|
||||
ScrollPosition foo1 = ScrollPosition.forward(KEYS);
|
||||
ScrollPosition foo2 = ScrollPosition.forward(KEYS);
|
||||
ScrollPosition bar = ScrollPosition.backward(KEYS);
|
||||
|
||||
assertThat(foo1).isEqualTo(foo2).hasSameClassAs(foo2);
|
||||
assertThat(foo1).isNotEqualTo(bar).doesNotHaveSameHashCodeAs(bar);
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void equalsAndHashCodeForOffsets() {
|
||||
|
||||
ScrollPosition foo1 = ScrollPosition.offset(1);
|
||||
ScrollPosition foo2 = ScrollPosition.offset(1);
|
||||
ScrollPosition bar = ScrollPosition.offset(2);
|
||||
|
||||
assertThat(foo1).isEqualTo(foo2).hasSameClassAs(foo2);
|
||||
assertThat(foo1).isNotEqualTo(bar).doesNotHaveSameHashCodeAs(bar);
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void shouldCreateCorrectIndexPosition() {
|
||||
|
||||
assertThat(positionFunction(0).apply(0)).isEqualTo(ScrollPosition.offset(1));
|
||||
assertThat(positionFunction(0).apply(1)).isEqualTo(ScrollPosition.offset(2));
|
||||
|
||||
assertThat(positionFunction(100).apply(0)).isEqualTo(ScrollPosition.offset(101));
|
||||
assertThat(positionFunction(100).apply(1)).isEqualTo(ScrollPosition.offset(102));
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void rejectsNegativeOffset() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> ScrollPosition.offset(-1));
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void advanceOffsetBelowZeroCapsAtZero() {
|
||||
|
||||
OffsetScrollPosition offset = ScrollPosition.offset(5);
|
||||
|
||||
assertThat(offset.getOffset()).isEqualTo(5);
|
||||
assertThat(offset.advanceBy(-10)).isEqualTo(ScrollPosition.offset(0));
|
||||
}
|
||||
|
||||
@Test // GH-2824
|
||||
void setsUpForwardScrolling() {
|
||||
|
||||
KeysetScrollPosition position = ScrollPosition.forward(KEYS);
|
||||
|
||||
assertThat(position.getKeys()).isEqualTo(KEYS);
|
||||
assertThat(position.getDirection()).isEqualTo(Direction.FORWARD);
|
||||
assertThat(position.scrollsForward()).isTrue();
|
||||
assertThat(position.scrollsBackward()).isFalse();
|
||||
|
||||
KeysetScrollPosition backward = position.backward();
|
||||
|
||||
assertThat(backward.getKeys()).isEqualTo(KEYS);
|
||||
assertThat(backward.getDirection()).isEqualTo(Direction.BACKWARD);
|
||||
assertThat(backward.scrollsForward()).isFalse();
|
||||
assertThat(backward.scrollsBackward()).isTrue();
|
||||
|
||||
assertThat(position.reverse()).isEqualTo(backward);
|
||||
}
|
||||
|
||||
@Test // GH-2824
|
||||
void setsUpBackwardScrolling() {
|
||||
|
||||
KeysetScrollPosition position = ScrollPosition.backward(KEYS);
|
||||
|
||||
assertThat(position.getKeys()).isEqualTo(KEYS);
|
||||
assertThat(position.getDirection()).isEqualTo(Direction.BACKWARD);
|
||||
assertThat(position.scrollsForward()).isFalse();
|
||||
assertThat(position.scrollsBackward()).isTrue();
|
||||
|
||||
KeysetScrollPosition forward = position.forward();
|
||||
|
||||
assertThat(forward.getKeys()).isEqualTo(KEYS);
|
||||
assertThat(forward.getDirection()).isEqualTo(Direction.FORWARD);
|
||||
assertThat(forward.scrollsForward()).isTrue();
|
||||
assertThat(forward.scrollsBackward()).isFalse();
|
||||
|
||||
assertThat(position.reverse()).isEqualTo(forward);
|
||||
}
|
||||
|
||||
@Test // GH-2824
|
||||
void initialOffsetPosition() {
|
||||
|
||||
OffsetScrollPosition position = ScrollPosition.offset();
|
||||
|
||||
assertThat(position.isInitial()).isTrue();
|
||||
assertThat(position.getOffset()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // GH-2824
|
||||
void initialKeysetPosition() {
|
||||
|
||||
KeysetScrollPosition keyset = ScrollPosition.keyset();
|
||||
|
||||
assertThat(keyset.isInitial()).isTrue();
|
||||
assertThat(keyset.scrollsForward()).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.data.support.WindowIterator;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WindowIterator}.
|
||||
@@ -45,20 +46,20 @@ class WindowIteratorUnitTests {
|
||||
void loadsDataOnNext() {
|
||||
|
||||
Function<ScrollPosition, Window<String>> fkt = mock(Function.class);
|
||||
WindowIterator<String> iterator = WindowIterator.of(fkt).startingAt(OffsetScrollPosition.initial());
|
||||
WindowIterator<String> iterator = WindowIterator.of(fkt).startingAt(ScrollPosition.offset());
|
||||
verifyNoInteractions(fkt);
|
||||
|
||||
when(fkt.apply(any())).thenReturn(Window.from(Collections.emptyList(), value -> OffsetScrollPosition.initial()));
|
||||
when(fkt.apply(any())).thenReturn(Window.from(Collections.emptyList(), value -> ScrollPosition.offset()));
|
||||
|
||||
iterator.hasNext();
|
||||
verify(fkt).apply(OffsetScrollPosition.initial());
|
||||
verify(fkt).apply(ScrollPosition.offset());
|
||||
}
|
||||
|
||||
@Test // GH-2151
|
||||
void hasNextReturnsFalseIfNoDataAvailable() {
|
||||
|
||||
Window<Object> window = Window.from(Collections.emptyList(), value -> OffsetScrollPosition.initial());
|
||||
WindowIterator<Object> iterator = WindowIterator.of(it -> window).startingAt(OffsetScrollPosition.initial());
|
||||
Window<Object> window = Window.from(Collections.emptyList(), value -> ScrollPosition.offset());
|
||||
WindowIterator<Object> iterator = WindowIterator.of(it -> window).startingAt(ScrollPosition.offset());
|
||||
|
||||
assertThat(iterator.hasNext()).isFalse();
|
||||
}
|
||||
@@ -66,8 +67,8 @@ class WindowIteratorUnitTests {
|
||||
@Test // GH-2151
|
||||
void nextThrowsExceptionIfNoElementAvailable() {
|
||||
|
||||
Window<Object> window = Window.from(Collections.emptyList(), value -> OffsetScrollPosition.initial());
|
||||
WindowIterator<Object> iterator = WindowIterator.of(it -> window).startingAt(OffsetScrollPosition.initial());
|
||||
Window<Object> window = Window.from(Collections.emptyList(), value -> ScrollPosition.offset());
|
||||
WindowIterator<Object> iterator = WindowIterator.of(it -> window).startingAt(ScrollPosition.offset());
|
||||
|
||||
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(iterator::next);
|
||||
}
|
||||
@@ -75,8 +76,8 @@ class WindowIteratorUnitTests {
|
||||
@Test // GH-2151
|
||||
void hasNextReturnsTrueIfDataAvailableButOnlyOnePage() {
|
||||
|
||||
Window<String> window = Window.from(List.of("a", "b"), value -> OffsetScrollPosition.initial());
|
||||
WindowIterator<String> iterator = WindowIterator.of(it -> window).startingAt(OffsetScrollPosition.initial());
|
||||
Window<String> window = Window.from(List.of("a", "b"), value -> ScrollPosition.offset());
|
||||
WindowIterator<String> iterator = WindowIterator.of(it -> window).startingAt(ScrollPosition.offset());
|
||||
|
||||
assertThat(iterator.hasNext()).isTrue();
|
||||
assertThat(iterator.next()).isEqualTo("a");
|
||||
@@ -89,14 +90,14 @@ class WindowIteratorUnitTests {
|
||||
@Test // GH-2151
|
||||
void hasNextReturnsCorrectlyIfNextPageIsEmpty() {
|
||||
|
||||
Window<String> window = Window.from(List.of("a", "b"), value -> OffsetScrollPosition.initial());
|
||||
Window<String> window = Window.from(List.of("a", "b"), value -> ScrollPosition.offset());
|
||||
WindowIterator<String> iterator = WindowIterator.of(it -> {
|
||||
if (it.isInitial()) {
|
||||
return window;
|
||||
}
|
||||
|
||||
return Window.from(Collections.emptyList(), OffsetScrollPosition::of, false);
|
||||
}).startingAt(OffsetScrollPosition.initial());
|
||||
}).startingAt(ScrollPosition.offset());
|
||||
|
||||
assertThat(iterator.hasNext()).isTrue();
|
||||
assertThat(iterator.next()).isEqualTo("a");
|
||||
@@ -109,15 +110,15 @@ class WindowIteratorUnitTests {
|
||||
@Test // GH-2151
|
||||
void allowsToIterateAllWindows() {
|
||||
|
||||
Window<String> window1 = Window.from(List.of("a", "b"), OffsetScrollPosition::of, true);
|
||||
Window<String> window2 = Window.from(List.of("c", "d"), value -> OffsetScrollPosition.of(2 + value));
|
||||
Window<String> window1 = Window.from(List.of("a", "b"), ScrollPosition::offset, true);
|
||||
Window<String> window2 = Window.from(List.of("c", "d"), value -> ScrollPosition.offset(2 + value));
|
||||
WindowIterator<String> iterator = WindowIterator.of(it -> {
|
||||
if (it.isInitial()) {
|
||||
return window1;
|
||||
}
|
||||
|
||||
return window2;
|
||||
}).startingAt(OffsetScrollPosition.initial());
|
||||
}).startingAt(ScrollPosition.offset());
|
||||
|
||||
List<String> capturedResult = new ArrayList<>(4);
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
@@ -58,13 +58,13 @@ class WindowUnitTests {
|
||||
|
||||
Window<Integer> window = Window.from(List.of(1, 2, 3), OffsetScrollPosition.positionFunction(0));
|
||||
|
||||
assertThat(window.positionAt(0)).isEqualTo(OffsetScrollPosition.of(1));
|
||||
assertThat(window.positionAt(window.size() - 1)).isEqualTo(OffsetScrollPosition.of(3));
|
||||
assertThat(window.positionAt(0)).isEqualTo(ScrollPosition.offset(1));
|
||||
assertThat(window.positionAt(window.size() - 1)).isEqualTo(ScrollPosition.offset(3));
|
||||
|
||||
// by index
|
||||
assertThat(window.positionAt(1)).isEqualTo(OffsetScrollPosition.of(2));
|
||||
assertThat(window.positionAt(1)).isEqualTo(ScrollPosition.offset(2));
|
||||
|
||||
// by object
|
||||
assertThat(window.positionAt(Integer.valueOf(1))).isEqualTo(OffsetScrollPosition.of(1));
|
||||
assertThat(window.positionAt(Integer.valueOf(1))).isEqualTo(ScrollPosition.offset(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.OffsetScrollPosition;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.ScrollPosition;
|
||||
@@ -84,7 +83,7 @@ class ParametersParameterAccessorUnitTests {
|
||||
var method = Sample.class.getMethod("method", ScrollPosition.class, String.class);
|
||||
var parameters = new DefaultParameters(method);
|
||||
|
||||
var accessor = new ParametersParameterAccessor(parameters, new Object[] { OffsetScrollPosition.of(1), "Foo" });
|
||||
var accessor = new ParametersParameterAccessor(parameters, new Object[] { ScrollPosition.offset(1), "Foo" });
|
||||
|
||||
assertThat(accessor).hasSize(1);
|
||||
assertThat(accessor.getBindableValue(0)).isEqualTo("Foo");
|
||||
|
||||
@@ -19,7 +19,6 @@ import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.domain.OffsetScrollPosition;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.ScrollPosition;
|
||||
@@ -61,7 +60,8 @@ class SimpleParameterAccessorUnitTests {
|
||||
|
||||
@Test
|
||||
void rejectsTooLittleNumberOfArguments() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new ParametersParameterAccessor(parameters, new Object[0]));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new ParametersParameterAccessor(parameters, new Object[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,7 +82,7 @@ class SimpleParameterAccessorUnitTests {
|
||||
@Test // GH-2151
|
||||
void returnsScrollPositionIfAvailable() {
|
||||
|
||||
var cursorRequest = OffsetScrollPosition.of(1);
|
||||
var cursorRequest = ScrollPosition.offset(1);
|
||||
ParameterAccessor accessor = new ParametersParameterAccessor(cursorRequestParameters,
|
||||
new Object[] { cursorRequest });
|
||||
|
||||
@@ -103,7 +103,8 @@ class SimpleParameterAccessorUnitTests {
|
||||
void returnsPageableIfAvailable() {
|
||||
|
||||
Pageable pageable = PageRequest.of(0, 10);
|
||||
ParameterAccessor accessor = new ParametersParameterAccessor(pageableParameters, new Object[] { "test", pageable });
|
||||
ParameterAccessor accessor = new ParametersParameterAccessor(pageableParameters,
|
||||
new Object[] { "test", pageable });
|
||||
|
||||
assertThat(accessor.getPageable()).isEqualTo(pageable);
|
||||
assertThat(accessor.getSort().isSorted()).isFalse();
|
||||
@@ -114,7 +115,8 @@ class SimpleParameterAccessorUnitTests {
|
||||
|
||||
var sort = Sort.by("foo");
|
||||
Pageable pageable = PageRequest.of(0, 10, sort);
|
||||
ParameterAccessor accessor = new ParametersParameterAccessor(pageableParameters, new Object[] { "test", pageable });
|
||||
ParameterAccessor accessor = new ParametersParameterAccessor(pageableParameters,
|
||||
new Object[] { "test", pageable });
|
||||
|
||||
assertThat(accessor.getPageable()).isEqualTo(pageable);
|
||||
assertThat(accessor.getSort()).isEqualTo(sort);
|
||||
|
||||
Reference in New Issue
Block a user