Skip to content

Commit

Permalink
pagination changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubh-arya committed Apr 13, 2024
1 parent 48ac4f4 commit 8ce9f26
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 13 deletions.
10 changes: 5 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@
<version>${graphql.java}</version>
</dependency>

<!-- <dependency>-->
<!-- <groupId>com.graphql-java</groupId>-->
<!-- <artifactId>graphql-java-extended-validation</artifactId>-->
<!-- <version>${graphql.java}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-extended-validation</artifactId>
<version>${graphql.java}</version>
</dependency>

<!-- <dependency>-->
<!-- <groupId>com.netflix.graphql.dgs</groupId>-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,34 @@
import com.netflix.graphql.dgs.InputArgument;
import com.sarya.graphql.service.codegen.types.Customer;
import com.sarya.graphql.service.codegen.types.PaginationInput;
import com.sarya.graphql.service.util.pagination.CursorDecoder;
import com.sarya.graphql.service.util.pagination.CursorEncoder;
import com.sarya.graphql.service.util.pagination.GenericConnection;
import graphql.relay.Connection;
import graphql.relay.SimpleListConnection;
import graphql.schema.DataFetchingEnvironment;

import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@DgsComponent
@Slf4j
@AllArgsConstructor
public class CustomerResolver {

private final CursorEncoder cursorEncoder;
private final CursorDecoder cursorDecoder;

@DgsQuery
Connection<Customer> fetchCustomers(
DataFetchingEnvironment dfe,
@InputArgument PaginationInput paginationInput
) {
log.info("pagination Input: {}", paginationInput);
int offset = cursorDecoder.apply(paginationInput.getAfter(), 0);
var customer = Customer.newBuilder().name("James").customerId(UUID.randomUUID())
.email("[email protected]").build();
return new SimpleListConnection<>(List.of(customer)).get(dfe);
return new GenericConnection<>(cursorEncoder, List.of(customer), offset).get(dfe);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.netflix.graphql.dgs.InputArgument;
import com.sarya.graphql.service.application.usecase.CreateProductUseCase;
import com.sarya.graphql.service.application.usecase.FetchProductUseCase;
import com.sarya.graphql.service.codegen.types.CreateProduct;
import com.sarya.graphql.service.codegen.types.CreateProductInput;
import com.sarya.graphql.service.codegen.types.Product;
import com.sarya.graphql.service.codegen.types.ProductStatus;
import com.sarya.graphql.service.codegen.types.ProductType;
Expand Down Expand Up @@ -34,7 +34,7 @@ public List<Product> fetchProducts() {
}

@DgsMutation
public boolean createProduct(@InputArgument CreateProduct input) {
public boolean createProduct(@InputArgument CreateProductInput input) {
log.info("incoming message: {}", input);
Product output = new Product();
BeanUtils.copyProperties(input, output, Product.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.sarya.graphql.service.util.pagination;

import com.google.common.base.Strings;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.function.BiFunction;
import org.apache.tomcat.util.codec.binary.StringUtils;
import org.springframework.stereotype.Component;

@Component
public class CursorDecoder implements BiFunction<String, Integer, Integer> {

@Override
public Integer apply(String cursor, Integer defaultValue) {
if (Strings.isNullOrEmpty(cursor)) {
return defaultValue;
}
var hash = Base64.getDecoder().decode(cursor.getBytes(StandardCharsets.UTF_8));
var cursorLiteral = StringUtils.newStringUtf8(hash);
try {
return (Integer.valueOf(cursorLiteral.substring(5)));
} catch (NumberFormatException nfe) {
throw new RuntimeException("unparsable cursor: {}" + cursor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sarya.graphql.service.util.pagination;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.function.Function;
import org.springframework.stereotype.Component;

@Component
public class CursorEncoder implements Function<Integer, String> {

@Override
public String apply(Integer offset) {
byte[] bytes = ("prefix" + offset).getBytes(StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(bytes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.sarya.graphql.service.util.pagination;

import graphql.relay.Connection;
import graphql.relay.DefaultConnection;
import graphql.relay.DefaultConnectionCursor;
import graphql.relay.DefaultEdge;
import graphql.relay.DefaultPageInfo;
import graphql.relay.Edge;
import graphql.relay.PageInfo;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class GenericConnection<T> implements DataFetcher<Connection<T>> {

private final CursorEncoder cursorEncoder;

private final List<T> data;
private final int offset;

@Override
public Connection<T> get(DataFetchingEnvironment environment) {
List<Edge<T>> edges = buildEdges();

if (edges.size() == 0) {
return emptyConnection();
}

var firstEdge = edges.get(0);
var lastEdge = edges.get(edges.size() - 1);

return new DefaultConnection<>(
edges,
new GenericPageInfo(firstEdge.getCursor(), lastEdge.getCursor(), false, false, edges.size())
);
}

private Connection<T> emptyConnection() {
PageInfo pageInfo = new DefaultPageInfo(null, null, false, false);
return new DefaultConnection<>(List.of(), pageInfo);
}

private List<Edge<T>> buildEdges() {
List<Edge<T>> edges = new ArrayList<>();
int ix = 0;
for (T object : data) {
edges.add(
new DefaultEdge<>(object, new DefaultConnectionCursor(cursorEncoder.apply(offset + ix++)))
);
}
return edges;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.sarya.graphql.service.util.pagination;

import graphql.relay.ConnectionCursor;
import graphql.relay.DefaultPageInfo;
import lombok.ToString;

@ToString
public class GenericPageInfo extends DefaultPageInfo {

private final long totalCount;

public GenericPageInfo(
ConnectionCursor startCursor,
ConnectionCursor endCursor,
boolean hasPreviousPage,
boolean hasNextPage,
long totalCount
) {
super(startCursor, endCursor, hasPreviousPage, hasNextPage);
this.totalCount = totalCount;
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ spring:
graphql:
graphiql:
enabled: true

# websocket:
# path: /graphql
schema:
Expand All @@ -24,6 +25,7 @@ dgs:
reload: true
graphql:
enable-entity-fetcher-custom-scalar-parsing: true
schema-wiring-validation-enabled: true
spring:
webmvc:
asyncdispatch:
Expand Down
16 changes: 12 additions & 4 deletions src/main/resources/schema/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
directive @connection on OBJECT
directive @Range(min: Int = 0, max: Int = 2147483647, message: String= "Invalid input value") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
directive @Size(min : Int = 0, max : Int = 2147483647, message : String = "graphql.validation.Size.message")
on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
directive @NotBlank(message : String = "graphql.validation.NotBlank.message") on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION

scalar Currency
scalar UUID
scalar BigDecimal


scalar Long

type Query {
Expand All @@ -9,11 +17,11 @@ type Query {
}

type Mutation {
createProduct(input: CreateProduct): Boolean
createProduct(input: CreateProductInput): Boolean
}

input CreateProduct {
name: String
input CreateProductInput {
name: String @NotBlank
productType: ProductType
productStatus: ProductStatus
active: Boolean
Expand Down Expand Up @@ -77,6 +85,6 @@ type CustomerEdge {
}

input PaginationInput {
first: Int = 10
first: Int = 10 @Range(min: 1, max: 1000)
after: String
}

0 comments on commit 8ce9f26

Please sign in to comment.