Align OffsetScrolling to zero-based indexes.

OffsetScrollPosition is now 0-based instead of 1-based. We differentiate between ScrollPosition.offset() as initial position and ScrollPosition.offset(0) pointing to the first returned element.

Remove unused variable.

Closes #2890
Original pull request: #2891
This commit is contained in:
Mark Paluch
2024-04-10 09:45:24 +02:00
parent 8bc66fcd79
commit 3ec8e504f0
9 changed files with 18 additions and 17 deletions

View File

@@ -244,7 +244,9 @@ final class CypherQueryCreator extends AbstractQueryCreator<QueryFragmentsAndPar
queryFragments.setRequiresReverseSort(keysetScrollPosition.scrollsBackward());
} else if (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) {
queryFragments.setSkip(offsetScrollPosition.getOffset());
if (!offsetScrollPosition.isInitial()) {
queryFragments.setSkip(offsetScrollPosition.getOffset() + 1);
}
queryFragments.setLimit(limitModifier.apply(pagingParameter.isUnpaged() ? maxResults.intValue() : pagingParameter.getPageSize()));
}

View File

@@ -170,7 +170,7 @@ final class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<R> im
var skip = scrollPosition.isInitial()
? 0
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset()
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset() + 1
: 0;
Condition condition = scrollPosition instanceof KeysetScrollPosition keysetScrollPosition

View File

@@ -90,7 +90,7 @@ abstract class FluentQuerySupport<R> {
var skip = scrollPosition.isInitial()
? 0
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset()
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset() + 1
: 0;
var scrollDirection = scrollPosition instanceof KeysetScrollPosition keysetScrollPosition ? keysetScrollPosition.getDirection() : ScrollPosition.Direction.FORWARD;

View File

@@ -285,7 +285,6 @@ abstract class Neo4jQuerySupport {
var domainType = resultProcessor.getReturnedType().getDomainType();
var neo4jPersistentEntity = mappingContext.getPersistentEntity(domainType);
var limit = orderBy.getQueryFragments().getLimit().intValue() - (incrementLimit ? 1 : 0);
var conversionService = mappingContext.getConversionService();
var scrollPosition = parameterAccessor.getScrollPosition();
var scrollDirection = scrollPosition instanceof KeysetScrollPosition keysetScrollPosition ? keysetScrollPosition.getDirection() : Direction.FORWARD;
@@ -295,7 +294,7 @@ abstract class Neo4jQuerySupport {
return Window.from(getSubList(rawResult, limit, scrollDirection), v -> {
if (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) {
return offsetScrollPosition.advanceBy(v + limit);
return offsetScrollPosition.advanceBy(v);
} else {
var accessor = neo4jPersistentEntity.getPropertyAccessor(rawResult.get(v));
var keys = new LinkedHashMap<String, Object>();

View File

@@ -273,7 +273,7 @@ public final class QueryFragmentsAndParameters {
if (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) {
skip = offsetScrollPosition.isInitial()
? 0
: offsetScrollPosition.getOffset();
: offsetScrollPosition.getOffset() + 1;
return forCondition(entityMetaData, condition, null, sort, null, limit, skip, includeField);
}

View File

@@ -171,7 +171,7 @@ final class ReactiveFluentQueryByExample<S, R> extends FluentQuerySupport<R> imp
var skip = scrollPosition.isInitial()
? 0
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset()
: (scrollPosition instanceof OffsetScrollPosition offsetScrollPosition) ? offsetScrollPosition.getOffset() + 1
: 0;
Condition condition = scrollPosition instanceof KeysetScrollPosition keysetScrollPosition

View File

@@ -137,7 +137,7 @@ class QuerydslNeo4jPredicateExecutorIT {
Predicate predicate = Expressions.predicate(Ops.EQ, firstNamePath, Expressions.asString("Helge"))
.or(Expressions.predicate(Ops.EQ, lastNamePath, Expressions.asString("B.")));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(0)));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset()));
assertThat(peopleWindow.getContent()).extracting(Person::getFirstName)
.containsExactlyInAnyOrder("Helge");
@@ -145,7 +145,7 @@ class QuerydslNeo4jPredicateExecutorIT {
assertThat(peopleWindow.isLast()).isFalse();
assertThat(peopleWindow.hasNext()).isTrue();
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(1));
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(0));
}
@Test
@@ -154,14 +154,14 @@ class QuerydslNeo4jPredicateExecutorIT {
Predicate predicate = Expressions.predicate(Ops.EQ, firstNamePath, Expressions.asString("Helge"))
.or(Expressions.predicate(Ops.EQ, lastNamePath, Expressions.asString("B.")));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(1)));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(0)));
assertThat(peopleWindow.getContent()).extracting(Person::getFirstName)
.containsExactlyInAnyOrder("Bela");
assertThat(peopleWindow.isLast()).isTrue();
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(2));
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(1));
}
@Test
@@ -170,7 +170,7 @@ class QuerydslNeo4jPredicateExecutorIT {
Predicate predicate = Expressions.predicate(Ops.EQ, firstNamePath, Expressions.asString("Helge"))
.or(Expressions.predicate(Ops.EQ, lastNamePath, Expressions.asString("B.")));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(0)));
Window<Person> peopleWindow = repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset()));
ScrollPosition currentPosition = peopleWindow.positionAt(peopleWindow.getContent().get(0));
peopleWindow = repository.findBy(predicate, q -> q.limit(1).scroll(currentPosition));

View File

@@ -2923,7 +2923,7 @@ class RepositoryIT {
Example<PersonWithAllConstructor> example = Example.of(sameValuePerson,
ExampleMatcher.matchingAll().withIgnoreNullValues());
Window<PersonWithAllConstructor> person = repository.findBy(example, q -> q.sortBy(Sort.by("name")).limit(1).scroll(ScrollPosition.offset(0)));
Window<PersonWithAllConstructor> person = repository.findBy(example, q -> q.sortBy(Sort.by("name")).limit(1).scroll(ScrollPosition.offset()));
assertThat(person).isNotNull();
assertThat(person.getContent().get(0)).isEqualTo(person1);

View File

@@ -196,7 +196,7 @@ class ReactiveQuerydslNeo4jPredicateExecutorIT {
Predicate predicate = Expressions.predicate(Ops.EQ, firstNamePath, Expressions.asString("Helge"))
.or(Expressions.predicate(Ops.EQ, lastNamePath, Expressions.asString("B.")));
repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(0)))
repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset()))
.as(StepVerifier::create)
.expectNextMatches(peopleWindow -> {
@@ -206,7 +206,7 @@ class ReactiveQuerydslNeo4jPredicateExecutorIT {
assertThat(peopleWindow.isLast()).isFalse();
assertThat(peopleWindow.hasNext()).isTrue();
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(1));
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(0));
return true;
}).verifyComplete();
}
@@ -217,14 +217,14 @@ class ReactiveQuerydslNeo4jPredicateExecutorIT {
Predicate predicate = Expressions.predicate(Ops.EQ, firstNamePath, Expressions.asString("Helge"))
.or(Expressions.predicate(Ops.EQ, lastNamePath, Expressions.asString("B.")));
repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(1)))
repository.findBy(predicate, q -> q.limit(1).sortBy(Sort.by("firstName").descending()).scroll(ScrollPosition.offset(0)))
.as(StepVerifier::create)
.expectNextMatches(peopleWindow -> {
assertThat(peopleWindow.getContent()).extracting(Person::getFirstName)
.containsExactlyInAnyOrder("Bela");
assertThat(peopleWindow.isLast()).isTrue();
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(2));
assertThat(peopleWindow.positionAt(peopleWindow.getContent().get(0))).isEqualTo(ScrollPosition.offset(1));
return true;
}).verifyComplete();
}