You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2021/05/12 08:46:02 UTC
[sling-org-apache-sling-graphql-core] branch SLING-10309/experiment
updated: SLING-10309 - rename a few things and add GenericConnectionTest
This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch SLING-10309/experiment
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-graphql-core.git
The following commit(s) were added to refs/heads/SLING-10309/experiment by this push:
new b9aaf40 SLING-10309 - rename a few things and add GenericConnectionTest
b9aaf40 is described below
commit b9aaf40b34d04e3ab7838b38963551f3f725f8cb
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Wed May 12 10:45:19 2021 +0200
SLING-10309 - rename a few things and add GenericConnectionTest
---
.../sling/graphql/api/pagination/Cursor.java | 14 +++
.../api/pagination/helpers/GenericConnection.java | 99 ++++++++++----------
.../sling/graphql/core/engine/CursorTest.java | 14 +++
.../core/pagination/GenericConnectionTest.java | 104 +++++++++++++++++++++
.../PaginatedHumansTest.java | 6 +-
src/test/resources/paginated-humans-schema.txt | 8 +-
6 files changed, 189 insertions(+), 56 deletions(-)
diff --git a/src/main/java/org/apache/sling/graphql/api/pagination/Cursor.java b/src/main/java/org/apache/sling/graphql/api/pagination/Cursor.java
index bc391e4..ae455a8 100644
--- a/src/main/java/org/apache/sling/graphql/api/pagination/Cursor.java
+++ b/src/main/java/org/apache/sling/graphql/api/pagination/Cursor.java
@@ -39,6 +39,20 @@ public class Cursor {
this.encoded = encode(this.rawValue);
}
+ @Override
+ public boolean equals(Object obj) {
+ if(!(obj instanceof Cursor)) {
+ return false;
+ }
+ final Cursor other = (Cursor)obj;
+ return other.rawValue.equals(this.rawValue);
+ }
+
+ @Override
+ public int hashCode() {
+ return rawValue == null ? null : rawValue.hashCode();
+ }
+
public static Cursor fromEncodedString(@Nullable String encoded) {
if(encoded == null) {
return null;
diff --git a/src/main/java/org/apache/sling/graphql/api/pagination/helpers/GenericConnection.java b/src/main/java/org/apache/sling/graphql/api/pagination/helpers/GenericConnection.java
index 06527b3..2d54150 100644
--- a/src/main/java/org/apache/sling/graphql/api/pagination/helpers/GenericConnection.java
+++ b/src/main/java/org/apache/sling/graphql/api/pagination/helpers/GenericConnection.java
@@ -34,52 +34,13 @@ import org.osgi.annotation.versioning.ConsumerType;
* is a page of results for a paginated query.
*/
@ConsumerType
-public class GenericConnection<T> implements Connection<T> {
+public class GenericConnection<T> implements Connection<T>, PageInfo {
private final List<Edge<T>> edges;
-
- static class LocalPageInfo implements PageInfo {
- Cursor startCursor = null;
- Cursor endCursor = null;
- boolean hasPreviousPage;
- boolean hasNextPage;
-
- @Override
- public Cursor getStartCursor() {
- return startCursor;
- }
-
- @Override
- public Cursor getEndCursor() {
- return endCursor;
- }
-
- @Override
- public boolean isHasPreviousPage() {
- return hasPreviousPage;
- }
-
- @Override
- public boolean isHasNextPage() {
- return hasNextPage;
- }
- };
-
- private final LocalPageInfo pageInfo = new LocalPageInfo();
-
- private Edge<T> newEdge(final T node, final Function<T, String> cursorStringFunction) {
- return new Edge<T>() {
- @Override
- public T getNode() {
- return node;
- }
-
- @Override
- public Cursor getCursor() {
- return new Cursor(cursorStringFunction.apply(node));
- }
- };
- }
+ private Cursor startCursor = null;
+ private Cursor endCursor = null;
+ private boolean hasPreviousPage;
+ private boolean hasNextPage;
/** Build a Connection that will output the supplied data, optionally skipping items
* at the beginning and considering a set maximum of items.
@@ -103,11 +64,11 @@ public class GenericConnection<T> implements Connection<T> {
if(startAfter == null) {
inRange = true;
addThisNode = true;
- pageInfo.hasPreviousPage = false;
+ hasPreviousPage = false;
} else {
final String rawCursor = cursorStringFunction.apply(node);
inRange = startAfter.getRawValue().equals(rawCursor);
- pageInfo.hasPreviousPage = true;
+ hasPreviousPage = true;
}
} else {
addThisNode = true;
@@ -115,10 +76,10 @@ public class GenericConnection<T> implements Connection<T> {
if(addThisNode) {
final Edge<T> toAdd = newEdge(node, cursorStringFunction);
- if(pageInfo.startCursor == null) {
- pageInfo.startCursor = toAdd.getCursor();
+ if(startCursor == null) {
+ startCursor = toAdd.getCursor();
}
- pageInfo.endCursor = toAdd.getCursor();
+ endCursor = toAdd.getCursor();
edges.add(toAdd);
itemsToAdd--;
}
@@ -127,14 +88,50 @@ public class GenericConnection<T> implements Connection<T> {
if(!inRange && maxItemsReturned > 0) {
throw new RuntimeException("Start cursor not found in supplied data:" + startAfter);
}
- pageInfo.hasNextPage = dataIterator.hasNext();
+ hasNextPage = dataIterator.hasNext();
}
+ private Edge<T> newEdge(final T node, final Function<T, String> cursorStringFunction) {
+ return new Edge<T>() {
+ @Override
+ public T getNode() {
+ return node;
+ }
+
+ @Override
+ public Cursor getCursor() {
+ return new Cursor(cursorStringFunction.apply(node));
+ }
+ };
+ }
+
+ @Override
public Iterable<Edge<T>> getEdges() {
return edges::iterator;
}
+ @Override
public PageInfo getPageInfo() {
- return pageInfo;
+ return this;
+ }
+
+ @Override
+ public Cursor getStartCursor() {
+ return startCursor;
+ }
+
+ @Override
+ public Cursor getEndCursor() {
+ return endCursor;
+ }
+
+ @Override
+ public boolean isHasPreviousPage() {
+ return hasPreviousPage;
+ }
+
+ @Override
+ public boolean isHasNextPage() {
+ return hasNextPage;
}
}
diff --git a/src/test/java/org/apache/sling/graphql/core/engine/CursorTest.java b/src/test/java/org/apache/sling/graphql/core/engine/CursorTest.java
index 7f83d1e..72bd83e 100644
--- a/src/test/java/org/apache/sling/graphql/core/engine/CursorTest.java
+++ b/src/test/java/org/apache/sling/graphql/core/engine/CursorTest.java
@@ -78,4 +78,18 @@ public class CursorTest {
assertNull(Cursor.fromEncodedString(null));
assertNull(Cursor.fromEncodedString("\t\n "));
}
+
+ @Test
+ public void testEquals() {
+ final String key = UUID.randomUUID().toString();
+ assertEquals(new Cursor(key), new Cursor(key));
+ assertNotEquals(new Cursor(key), new Cursor("something else"));
+ }
+
+ @Test
+ public void testHashCode() {
+ final String key = UUID.randomUUID().toString();
+ final Cursor c = new Cursor(key);
+ assertEquals(key.hashCode(), c.hashCode());
+ }
}
diff --git a/src/test/java/org/apache/sling/graphql/core/pagination/GenericConnectionTest.java b/src/test/java/org/apache/sling/graphql/core/pagination/GenericConnectionTest.java
new file mode 100644
index 0000000..a152c93
--- /dev/null
+++ b/src/test/java/org/apache/sling/graphql/core/pagination/GenericConnectionTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.sling.graphql.core.pagination;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.StreamSupport;
+
+import org.apache.sling.graphql.api.pagination.Connection;
+import org.apache.sling.graphql.api.pagination.Cursor;
+import org.apache.sling.graphql.api.pagination.Edge;
+import org.apache.sling.graphql.api.pagination.helpers.GenericConnection;
+import org.junit.Test;
+
+public class GenericConnectionTest {
+ private static final List<Integer> data = Arrays.asList(1,2,3,4,5 );
+ private static final Function<Integer, String> cursorize = (i) -> "cursor-" + i;
+
+ private static void assertValues(Connection<Integer> data, int start, int end, boolean hasPreviousPage, boolean hasNextPage) {
+ // assert edge values
+ final AtomicInteger current = new AtomicInteger(start);
+ StreamSupport.stream(data.getEdges().spliterator(), false).map(edge -> edge.getNode()).forEach(actual -> {
+ assertEquals(Integer.valueOf(current.get()), actual);
+ if(actual > end) {
+ fail("Got a value after expected end: " + actual);
+ }
+ current.incrementAndGet();
+ });
+
+ // cursors and previous/next page
+ final Iterator<Edge<Integer>> it = data.getEdges().iterator();
+ if(it.hasNext()) {
+ final Cursor startCursor = new Cursor(cursorize.apply(it.next().getNode()));
+ assertEquals("Expecting start cursor " + startCursor, startCursor, data.getPageInfo().getStartCursor());
+ final Cursor endCursor = new Cursor(cursorize.apply(end));
+ assertEquals("Expecting end cursor " + endCursor, endCursor, data.getPageInfo().getEndCursor());
+ } else {
+ // Empty data stream
+ assertEquals(null, data.getPageInfo().getStartCursor());
+ assertEquals(null, data.getPageInfo().getEndCursor());
+ }
+ assertEquals("Expecting hasNextPage=" + hasNextPage, hasNextPage, data.getPageInfo().isHasNextPage());
+ assertEquals("Expecting hasPreviousPage=" + hasPreviousPage, hasPreviousPage, data.getPageInfo().isHasPreviousPage());
+ }
+
+ @Test
+ public void minimalArguments() {
+ final GenericConnection<Integer> c = new GenericConnection<>(data.iterator(), cursorize, null, 2);
+ assertValues(c, 1, 2, false, true);
+ }
+
+ @Test
+ public void zeroLimit() {
+ final GenericConnection<Integer> c = new GenericConnection<>(data.iterator(), cursorize, null, 0);
+ assertValues(c, -1, -1, false, true);
+ }
+
+ @Test
+ public void largeLimit() {
+ final GenericConnection<Integer> c = new GenericConnection<>(data.iterator(), cursorize, null, 999);
+ assertValues(c, 1, 5, false, false);
+ }
+
+ @Test
+ public void startAtThree() {
+ final Cursor startAfter = new Cursor(cursorize.apply(2));
+ final GenericConnection<Integer> c = new GenericConnection<>(data.iterator(), cursorize, startAfter, 2);
+ assertValues(c, 3, 4, true, true);
+ }
+
+ @Test
+ public void startCursorNotFound() {
+ final Cursor startAfter = new Cursor(cursorize.apply(999));
+ try {
+ new GenericConnection<>(data.iterator(), cursorize, startAfter, 2);
+ fail("Expecting a RuntimeException");
+ } catch(RuntimeException rex) {
+ assertTrue(rex.getMessage().contains("Start cursor not found"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/graphql/core/engine/PaginatedHumansTest.java b/src/test/java/org/apache/sling/graphql/core/pagination/PaginatedHumansTest.java
similarity index 97%
rename from src/test/java/org/apache/sling/graphql/core/engine/PaginatedHumansTest.java
rename to src/test/java/org/apache/sling/graphql/core/pagination/PaginatedHumansTest.java
index 6e4dd3d..04b6550 100644
--- a/src/test/java/org/apache/sling/graphql/core/engine/PaginatedHumansTest.java
+++ b/src/test/java/org/apache/sling/graphql/core/pagination/PaginatedHumansTest.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.graphql.core.engine;
+package org.apache.sling.graphql.core.pagination;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +30,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import org.apache.sling.graphql.core.mocks.TestUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.apache.sling.graphql.core.engine.ResourceQueryTestBase;
import org.apache.sling.graphql.core.mocks.HumanDTO;
import org.apache.sling.graphql.api.SlingDataFetcher;
import org.apache.sling.graphql.api.SlingDataFetcherEnvironment;
@@ -62,11 +63,10 @@ public class PaginatedHumansTest extends ResourceQueryTestBase {
@Override
protected void setupAdditionalServices() {
final List<HumanDTO> humans = new ArrayList<>();
-
for(int i=1 ; i < 100 ; i++) {
humans.add(new HumanDTO("human-" + i, "Luke-" + i, "Tatooine"));
}
- TestUtil.registerSlingDataFetcher(context.bundleContext(), "humans/paginated", new HumansPageFetcher(humans));
+ TestUtil.registerSlingDataFetcher(context.bundleContext(), "humans/connection", new HumansPageFetcher(humans));
}
private void assertPageInfo(String json, Cursor startCursor, Cursor endCursor, Boolean hasPreviousPage, Boolean hasNextPage) {
diff --git a/src/test/resources/paginated-humans-schema.txt b/src/test/resources/paginated-humans-schema.txt
index b222cd6..62c1e40 100644
--- a/src/test/resources/paginated-humans-schema.txt
+++ b/src/test/resources/paginated-humans-schema.txt
@@ -23,7 +23,7 @@ directive @fetcher(
) on FIELD_DEFINITION
type Query {
- paginatedHumans (after : String, limit : Int) : PaginatedHumans @fetcher(name:"humans/paginated")
+ paginatedHumans (after : String, limit : Int) : HumanConnection @fetcher(name:"humans/connection")
}
type Human {
@@ -32,6 +32,10 @@ type Human {
address: String
}
+# The connection-specific parts of the schema might be
+# generated based on a schema directive later, but
+# writing them "by hand" also works
+
type PageInfo {
startCursor : String
endCursor : String
@@ -44,7 +48,7 @@ type HumanEdge {
node: Human
}
-type PaginatedHumans {
+type HumanConnection {
edges : [HumanEdge]
pageInfo : PageInfo
}
\ No newline at end of file