Subqueries
Context.query can be used to execute a subquery, i.e., a GraphQL query operation rooted in the full-schema's Query root type. As an example, we can modify the resolver for User.displayName to incorporate data that it loads from Query:
@Resolver(
"fragment _ on User { id firstName lastName }"
)
class UserDisplayNameResolver: UserResolvers.DisplayName() {
override suspend fun resolve(ctx: Context): String? {
val id = ctx.objectValue.getId()
val fn = ctx.objectValue.getFirstName()
val ln = ctx.objectValue.getLastName()
// determine if user is the logged-in user, in which case
// we add a suffix to their displayName
// first, construct a selection set on the Query object
val querySelections = ctx.selectionsFor(
Query.Reflection,
"{ viewer { user { id } } }"
)
// second, load the selections on Query
val query = ctx.query(querySelections)
val isViewer = id == query.getViewer()?.getUser()?.getId()
val suffix = if (isViewer) " (you!)" else ""
return when {
fn == null && ln == null -> null
fn == null -> ln
ln == null -> fn
else -> "$fn $ln$suffix"
}
}
}
We call this process of loading a selection set an "imperative subquery", which is distinguished from the more "declarative" method of data loading used by the @Resolver annotation. It can be used to load selections on the root Query object that are not known until runtime.