graphql.nadel.engine.transform.hydration.batch.NadelBatchHydrationTransform.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nadel Show documentation
Show all versions of nadel Show documentation
Nadel is a Java library that combines multiple GrahpQL services together into one API.
package graphql.nadel.engine.transform.hydration.batch
import graphql.nadel.NextgenEngine
import graphql.nadel.Service
import graphql.nadel.ServiceExecutionHydrationDetails
import graphql.nadel.ServiceExecutionResult
import graphql.nadel.engine.NadelExecutionContext
import graphql.nadel.engine.blueprint.NadelBatchHydrationFieldInstruction
import graphql.nadel.engine.blueprint.NadelOverallExecutionBlueprint
import graphql.nadel.engine.blueprint.getTypeNameToInstructionsMap
import graphql.nadel.engine.transform.GraphQLObjectTypeName
import graphql.nadel.engine.transform.NadelTransform
import graphql.nadel.engine.transform.NadelTransformFieldResult
import graphql.nadel.engine.transform.NadelTransformUtil.makeTypeNameField
import graphql.nadel.engine.transform.artificial.NadelAliasHelper
import graphql.nadel.engine.transform.hydration.NadelHydrationFieldsBuilder
import graphql.nadel.engine.transform.hydration.batch.NadelBatchHydrationTransform.State
import graphql.nadel.engine.transform.query.NadelQueryPath
import graphql.nadel.engine.transform.query.NadelQueryTransformer
import graphql.nadel.engine.transform.result.NadelResultInstruction
import graphql.nadel.engine.transform.result.json.JsonNodes
import graphql.nadel.engine.util.queryPath
import graphql.nadel.engine.util.toBuilder
import graphql.normalized.ExecutableNormalizedField
internal class NadelBatchHydrationTransform(
engine: NextgenEngine,
) : NadelTransform {
private val hydrator = NadelBatchHydrator(engine)
data class State(
val executionBlueprint: NadelOverallExecutionBlueprint,
val instructionsByObjectTypeNames: Map>,
val executionContext: NadelExecutionContext,
val hydratedField: ExecutableNormalizedField,
val hydratedFieldService: Service,
val aliasHelper: NadelAliasHelper,
)
override suspend fun isApplicable(
executionContext: NadelExecutionContext,
executionBlueprint: NadelOverallExecutionBlueprint,
services: Map,
service: Service,
overallField: ExecutableNormalizedField,
hydrationDetails: ServiceExecutionHydrationDetails?,
): State? {
val instructionsByObjectTypeName = executionBlueprint.fieldInstructions
.getTypeNameToInstructionsMap(overallField)
return if (instructionsByObjectTypeName.isNotEmpty()) {
return State(
executionBlueprint = executionBlueprint,
instructionsByObjectTypeNames = instructionsByObjectTypeName,
executionContext = executionContext,
hydratedField = overallField,
hydratedFieldService = service,
aliasHelper = NadelAliasHelper.forField(tag = "batch_hydration", overallField),
)
} else {
null
}
}
override suspend fun transformField(
executionContext: NadelExecutionContext,
transformer: NadelQueryTransformer,
executionBlueprint: NadelOverallExecutionBlueprint,
service: Service,
field: ExecutableNormalizedField,
state: State,
): NadelTransformFieldResult {
val objectTypesNoRenames = field.objectTypeNames.filterNot { it in state.instructionsByObjectTypeNames }
return NadelTransformFieldResult(
newField = objectTypesNoRenames
.takeIf(List::isNotEmpty)
?.let {
field.toBuilder()
.clearObjectTypesNames()
.objectTypeNames(it)
.build()
},
artificialFields = state.instructionsByObjectTypeNames
.flatMap { (objectTypeName, instructions) ->
NadelHydrationFieldsBuilder.makeRequiredSourceFields(
service = service,
executionBlueprint = executionBlueprint,
aliasHelper = state.aliasHelper,
objectTypeName = objectTypeName,
instructions = instructions
)
}
.let { fields ->
when (val typeNameField = makeTypeNameField(state, field)) {
null -> fields
else -> fields + typeNameField
}
},
)
}
override suspend fun getResultInstructions(
executionContext: NadelExecutionContext,
executionBlueprint: NadelOverallExecutionBlueprint,
service: Service,
overallField: ExecutableNormalizedField,
underlyingParentField: ExecutableNormalizedField?,
result: ServiceExecutionResult,
state: State,
nodes: JsonNodes,
): List {
val parentNodes = nodes.getNodesAt(
queryPath = underlyingParentField?.queryPath ?: NadelQueryPath.root,
flatten = true,
)
return hydrator.hydrate(state, executionBlueprint, parentNodes)
}
private fun makeTypeNameField(
state: State,
field: ExecutableNormalizedField,
): ExecutableNormalizedField? {
val typeNamesWithInstructions = state.instructionsByObjectTypeNames.keys
val objectTypeNames = field.objectTypeNames
.filter { it in typeNamesWithInstructions }
.takeIf { it.isNotEmpty() }
?: return null
return makeTypeNameField(
aliasHelper = state.aliasHelper,
objectTypeNames = objectTypeNames,
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy