0

I have the following schema structure (albeit with entity names changed):

type Artist {
 name: String!
 fans(first: Int, after: String, last: Int, before: String): FanConnection!
}
type ArtistConnection {
 edges: [ArtistEdge!]!
 pageInfo: PageInfo!
}
type ArtistEdge {
 cursor: String!
 node: Artist!
}
type FanConnection {
 edges: [FanEdge!]!
 pageInfo: PageInfo!
}
type FanEdge {
 cursor: String!
 node: Fan!
}
type Fan {
 name: String!
}
type PageInfo {
 hasPreviousPage: Boolean!
 hasNextPage: Boolean!
 startCursor: String
 endCursor: String
}
type Query {
 artists(first: Int, after: String, last: Int, before: String): ArtistConnection!
}

My goal is to batch resolve Fan entities when listing artists and their fans. To do this I had been using Spring Data's Window as a return value from data fetchers (controller methods) which automatically is mapped to a GraphQL connection by Spring GraphQL. I am referencing the ScrollSubrange argument provided automatically by Spring GraphQl to my controller methods, therefore, I am unable to use the @BatchMapping annotation; this means I have to register batch data loaders manually, and given all these batch data loaders' values are 'Window.class', I have to register then using forName rather than forTypePair - which then means that I end up not being able to resolve Java type issues where the data loader is expecting Mono<Map<Object, Object>>> but my data loader is returning Mono<Map<Artist, Window<Fan>>>>.

What is the correct way to handle batch loading Fan entities for all Artist entities in the result of this query:

query {
 artists {
 name
 fans(first: 10) {
 name
 }
 }
}

I can't seem to find specific batch mapping + paging examples, or documentation anywhere.

Here's what I had so far:

Registration of the data loader:

 FanController(final FanService fanService, final BatchLoaderRegistry batchLoaderRegistry) {
 this.fanService = fanService;
 batchLoaderRegistry
 .forName("artistFansDataLoader")
 .registerMappedBatchLoader((final Set<Artist> artists, final BatchLoaderEnvironment environment) -> {
 final GraphQLContext graphQLContext = Optional.ofNullable(environment.getContext())
 .map(GraphQLContext.class::cast)
 .orElseThrow(() -> new InternalError("Failed to get GraphQL Context"));
 final Identity identity = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
 .map(Authentication::getPrincipal)
 .map(Identity.class::cast)
 .orElseThrow(() -> new InternalError("Failed to get authentication principal"));
 final ScrollSubrange scrollSubrange = graphQLContext.get("scrollSubrange");
 return (Mono<Map<Object, Object>>) this.fansByArtists(artists, identity, scrollSubrange);
 });
 }

data fetcher / controller method:

 @SchemaMapping(typeName = "Artist", field = "fans")
 public CompletableFuture<Window<Fan>> artistFans(
 final GraphQLContext context,
 final ScrollSubrange scrollSubrange,
 @Qualifier("artistFansDataLoader") final DataLoader<Artist, Window<Fan>> loader,
 final Artist artist
 ) {
 return loader.load(artist);
 }

and finally, the data loader:

private Mono<Map<Artist, Window<Fan>>> fansByArtists(
 final Set<Artist> artists,
 final Identity identity,
 final ScrollSubrange scrollSubrange
) {
 final Map<Artist, Window> result = artists.parallelStream()
 .collect(Collectors.toMap(
 Function.identity(),
 artist -> this.fanService.list(
 new ListFansRequest(
 identity.accountId(),
 Collections.singleton(artist.id()),
 scrollSubrange
 )
 )
 ));
 return Mono.just(result);
}

This is the type error I'm seeing for the return statement in the registration of the batch data loader:

Inconvertible types; cannot cast 'Mono<Map<Artist,Window>>' to 'Mono<Map<Object,Object>>'

Dale K
28.4k15 gold badges62 silver badges88 bronze badges
asked Feb 2 at 9:22

1 Answer 1

0

I have managed to get this working by providing generic arguments to the forName method of the BatchLoaderRegistry:

batchLoaderRegistry
 .<Artist, Window<Fan>>forName("artistFansLoader")
 .registerMappedBatchLoader(this::fansByArtistIds);

Now, I am able to properly type the data loader method without issue or raw type warnings.

answered Feb 3 at 7:15
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.