Связь нового типа регистра GraphQL с аргументом сборщика данных
Имея схему GraphQL:
type TypeA {
id: ID,
name: String,
other: TypeC
}
type TypeB {
id: ID,
name: String,
other: TypeC
}
Как мне реализовать проводку TypeC независимо от типа исходного объекта? Я знаю, что могу:
RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("TypeA")
.dataFetcher("other", dataFetcher_typeC.get())
.type(TypeRuntimeWiring.newTypeWiring("TypeB")
.dataFetcher("other", dataFetcher_typeC.get())
.build()
но тогда сборщик данных зависит от типа исходного объекта:
DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
return dataFetchingEnvironment -> {
<??> sourceObj = dataFetchingEnvironment.getSource();
return getObject(sourceObj.someProperty);
};
}
Учитывая, что оба POJO (TypeA и TypeB) имеют поле ссылки на TypeC, как разрешить поле TypeC по данной ссылке, а не по исходному объекту?
2 ответа
Из документации здесь
dataFetchingEnvironment предоставляет метод getExecutionStepInfo(), который возвращает объект ExecutionStepInfo. Оттуда вы можете получить информацию о родителях.
ExecutionStepInfo executionStepInfo = environment.getExecutionStepInfo();
ExecutionStepInfo parentInfo = executionStepInfo.getParent();
GraphQLObjectType parentType = (GraphQLObjectType) parentInfo.getUnwrappedNonNullType();
// parentType.getName() returns you "TypeA" or "TypeB"
На самом деле я нашел два возможных решения проблемы:
- При определении новой проводки получите исходный объект и от него поле. Вызвать метод dataFetcher с параметром, как обычный метод Java:
- Внутренний сборщик данных получает имя поля из DataFetcherEnvironment. Используйте отражение, чтобы получить поле из исходного объекта
Пример №1:
RuntimeWiring.newRuntimeWiring()
.type(TypeRuntimeWiring.newTypeWiring("TypeA")
.dataFetcher("other", environment -> {
TypeA sourceObj = environment.getSource();
return dataFetcher_typeC.get(sourceObj.other)})
.type(TypeRuntimeWiring.newTypeWiring("TypeB")
TypeB sourceObj = environment.getSource();
return dataFetcher_typeC.get(sourceObj.other)})
.build()
Пример №2:
DataFetcher<CompletableFuture<Collection<TypeC>>> get() {
return dataFetchingEnvironment -> {
Field declaredField = dataFetchingEnvironment.getSource().getClass()
.getDeclaredField(dataFetchingEnvironment.getField().getName());
declaredField.setAccessible(true);
String value = (String) declaredField.get(dataFetchingEnvironment.getSource());
return getObject(sourceObj.someProperty);
};
}
Второй вариант выглядит лучше, но все еще не уверен, что это правильный подход.