New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batched resolver with arguments #93

Closed
picodotdev opened this Issue Nov 30, 2017 · 0 comments

Comments

Projects
None yet
1 participant
@picodotdev

picodotdev commented Nov 30, 2017

I'm trying to use a batched resolver with arguments that implements pagination with cursors for the batchedComments property in the following graphql schema:

type Book {
    id: Long
    title: String
    author: Author
    isbn: String
    comments(after: String, limit: Long): CommentsConnection
    batchedComments(after: String, limit: Long): CommentsConnection
}

type Comment {
    id: Long
    text: String
}

type Author {
    id: Long
    name: String
}

input BookFilter {
    title: String
}

type CommentsConnection {
    edges: [CommentEdge]
    pageInfo: PageInfo
}

type CommentEdge {
    node: Comment
    cursor: String
}

type PageInfo {
    startCursor: String
    endCursor: String
    hasNextPage: Boolean
}

type Query {
    books: [Book]!
    findBooks(filter: BookFilter): [Book]!
    authors: [Author]!
    author(id: Long): Author!
}

type Mutation {
    addBook(title: String, author: Long): Book
}

schema {
    query: Query
    mutation: Mutation
}

This is my resolver:

public class BookResolver implements GraphQLResolver<Book> {

    private LibraryRepository libraryRespository;

    public BookResolver(LibraryRepository libraryRespository) {
        this.libraryRespository = libraryRespository;
    }

    public String getIsbn(Book book) {
        return UUID.randomUUID().toString();
    }

    public CommentsConnection getComments(Book book, String after, Long limit) {
        Long idAfter = null;
        Long limitPlusOne = null;

        if (after != null) {
            idAfter = CommentEdge.fromGlobalId(after);
        }
        if (limit != null && limit < Long.MAX_VALUE) {
            limitPlusOne = limit + 1;
        }

        List<Comment> commentsPlusOne = libraryRespository.findComments(book.getId(), idAfter, limitPlusOne);
        Stream<Comment> stream = commentsPlusOne.stream();
        if (limit != null) {
            stream = stream.limit(limit);
        }
        List<Comment> comments = stream.collect(Collectors.toList());

        Comment firstComment = (!comments.isEmpty()) ? comments.get(0) : null;
        Comment lastComment = (!comments.isEmpty()) ? comments.get(comments.size() - 1) : null;

        String startCursor = (firstComment != null) ? CommentEdge.toGlobalId(firstComment) : null;
        String endCursor = (lastComment != null) ? CommentEdge.toGlobalId(lastComment) : null;

        boolean hasNextPage = commentsPlusOne.size() > comments.size();

        return new CommentsConnection(comments, new PageInfo(startCursor, endCursor, hasNextPage));
    }

    @Batched
    public List<CommentsConnection> getBatchedComments(List<Book> books, List<String> after, List<Long> limit) {
        List<CommentsConnection> ccs = new ArrayList<>();
        for (int i = 0; i < books.size(); ++i) {
            CommentsConnection cc = getComments(books.get(i), null, null);
            ccs.add(cc);
        }
        return ccs;
    }
}

But when I do this request I get an exception:

$ curl -XPOST -H "Content-Type: application/json" -d '{"query": "query Books{books{title isbn batchedComments(limit:1){edges{node{text}}}}}"}' http://localhost:8080/library
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_NUMBER_INT token
 at [Source: N/A; line: -1, column: -1]
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.DeserializationContext.reportMappingException(DeserializationContext.java:1234) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1122) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1075) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:338) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:269) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26) ~[jackson-databind-2.8.10.jar:2.8.10]
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3600) ~[jackson-databind-2.8.10.jar:2.8.10]
	... 74 common frames omitted

Maybe I would expect the batched resolver signature was this instead:

@Batched
public List<CommentsConnection> getBatchedComments(List<Book> books, String after, Long limit)

But with this resolver signature on application start throws this exception:

Caused by: com.coxautodev.graphql.tools.SchemaClassScannerError: Unable to match type definition (TypeName{name='String'}) with java type (class java.lang.String): Method was marked as @Batched but parameter was not a list!
	at com.coxautodev.graphql.tools.TypeClassMatcher.error(TypeClassMatcher.kt:22) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.TypeClassMatcher.stripBatchedType(TypeClassMatcher.kt:99) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.TypeClassMatcher.match(TypeClassMatcher.kt:26) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner.scanResolverInfoForPotentialMatches(SchemaClassScanner.kt:215) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner.scanQueueItemForPotentialMatches(SchemaClassScanner.kt:206) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner.scanQueue(SchemaClassScanner.kt:103) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaClassScanner.scanForClasses(SchemaClassScanner.kt:81) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaParserBuilder.scan(SchemaParserBuilder.kt:149) ~[graphql-java-tools-4.3.0.jar:na]
	at com.coxautodev.graphql.tools.SchemaParserBuilder.build(SchemaParserBuilder.kt:155) ~[graphql-java-tools-4.3.0.jar:na]
	at io.github.picodotdev.blogbitix.graphql.Main.graphQLServletRegistrationBean(Main.java:42) [main/:na]

The full source code with a spring boot example is here: https://github.com/picodotdev/blog-ejemplos/tree/master/GraphQL

How I can use a batched resolver with arguments? Is it possible?

PaveLiArcH added a commit to PaveLiArcH/graphql-java-tools that referenced this issue Dec 3, 2017

PaveLiArcH added a commit to PaveLiArcH/graphql-java-tools that referenced this issue Jan 25, 2018

@apottere apottere closed this in #95 May 19, 2018

apottere added a commit that referenced this issue May 19, 2018

Expect only first parameter as List in Batched (#95)
* Expect only first parameter as List (fixes #93)

* Expect only RETURN_TYPE to be List (fixes #93)

* Added tests to check batched methods with parameters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment