Skip to content

ConnectionDataFetcher should handle data wrapped with DataFetcherResult #835

Closed
@Empatixx

Description

@Empatixx

Hello,

First and foremost, I'd like to express my gratitude for this incredible library. I'm reaching out to report a bug related to the ConnectionAdapter and the results from DataFetcher as represented by DataFetcherResult.

When I retrieve a result from DataFetcher that's an instance of DataFetcherResult with a specific local context and associated data that has its specific ConnectionAdapter, an error is generated. The system seems unable to locate the adapter. It appears to be looking for an adapter for the overall result rather than the specific data type of DataFetcherResult. Currently, there isn't an alternative method to pass the local context and the corresponding data that should be Connection and mapped by the ConnectionAdapter. This leads me to believe that there's a bug in the process.

I've managed to identify a potential solution...

In ConnectionFieldTypeVisitor in record ConnectionDataFetcher

        @Override
        public Object get(DataFetchingEnvironment environment) throws Exception {
            Object result = this.delegate.get(environment);
            if (result instanceof DataFetcherResult dataFetcherResult){
                Object data = dataFetcherResult.getData();
                return DataFetcherResult.newResult()
                        .data(map(data))
                        .localContext(dataFetcherResult.getLocalContext())
                        .errors(dataFetcherResult.getErrors())
                        .build();
            }

            return map(result);
        }

        private Object map(Object result) {
            if (result instanceof Mono<?> mono) {
                return mono.map(this::adapt);
            }
            else if (result instanceof CompletionStage<?> stage) {
                return stage.thenApply(this::adapt);
            }
            else {
                return adapt(result);
            }
        }

I think it should check if result is DataFetcherResult and map only its data.
My controller is like this:

    @SchemaMapping(typeName = "Parent")
    public DataFetcherResult<Connection<Item>> items(final Parent parent,
                                                final OffsetPagination pagination) {
        final List<Item> items = service.getItems(parent.getId(), pagination.offset(), pagination.limit());
        final Connection<Item> connection = Connection.create(items, pagination);
        return DataFetcherResult.<Connection<Item>>newResult()
                .localContext(GraphQLContext.newContext()
                        .of(LocalContextValues.PARENT, parent.id())
                        .build())
                .data(connection)
                .build();  
}

The Connection class functions correctly with its ConnectionAdapter. When returning entire Connection, everything operates as expected. However, when there's a need to pass a localContext, I utilize DataFetcherResult. At this point, an issue arises because it cannot handle this specific type.

type Query {
    parent: Parent!
}
type Parent {
    id: ID!
    items(after: String, before: String, first: NonNegativeInt, last: NonNegativeInt): ItemConnection!
}
type Item{
    id: ID!
}

If needed more code or more information, tell me. Thank you for library!

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions