![JAR search and dependency download from the Maven repository](/logo.png)
graphql.nadel.enginekt.transform.query.NadelQueryTransformer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nadel-engine-nextgen Show documentation
Show all versions of nadel-engine-nextgen Show documentation
Nadel is a Java library that combines multiple GrahpQL services together into one API.
The newest version!
package graphql.nadel.enginekt.transform.query
import graphql.nadel.Service
import graphql.nadel.enginekt.NadelExecutionContext
import graphql.nadel.enginekt.blueprint.NadelOverallExecutionBlueprint
import graphql.nadel.enginekt.plan.NadelExecutionPlan
import graphql.nadel.enginekt.transform.NadelTransform
import graphql.nadel.enginekt.transform.NadelTransformFieldResult
import graphql.nadel.enginekt.util.toBuilder
import graphql.normalized.ExecutableNormalizedField
class NadelQueryTransformer private constructor(
private val executionBlueprint: NadelOverallExecutionBlueprint,
private val service: Service,
private val executionContext: NadelExecutionContext,
private val executionPlan: NadelExecutionPlan,
private val transformContext: TransformContext,
) {
companion object {
suspend fun transformQuery(
executionBlueprint: NadelOverallExecutionBlueprint,
service: Service,
executionContext: NadelExecutionContext,
executionPlan: NadelExecutionPlan,
field: ExecutableNormalizedField,
): TransformResult {
val transformContext = TransformContext()
val transformer = NadelQueryTransformer(
executionBlueprint,
service,
executionContext,
executionPlan,
transformContext,
)
val result = transformer.transform(field)
.also { rootFields ->
transformer.fixParentRefs(parent = null, rootFields)
}
return TransformResult(
result = result,
artificialFields = transformContext.artificialFields,
overallToUnderlyingFields = transformContext.overallToUnderlyingFields,
)
}
}
private data class TransformContext(
val artificialFields: MutableList = mutableListOf(),
val overallToUnderlyingFields: MutableMap> = mutableMapOf(),
)
data class TransformResult(
/**
* The transformed fields.
*/
val result: List,
/**
* A list of fields that were added to the query that do not belong in the overall result.
*/
val artificialFields: List,
val overallToUnderlyingFields: Map>,
)
fun markArtificial(field: ExecutableNormalizedField) {
transformContext.artificialFields.add(field)
}
/**
* Helper for calling [transform] for all the given [fields].
*/
suspend fun transform(
fields: List,
): List {
return fields.flatMap {
transform(it)
}
}
suspend fun transform(
field: ExecutableNormalizedField,
): List {
val transformationSteps: List> = executionPlan.transformationSteps[field]
?: return listOf(
transformPlain(field)
)
return transform(field, transformationSteps)
}
private suspend fun transform(
field: ExecutableNormalizedField,
transformationSteps: List>,
): List {
val transformResult = applyTransformationSteps(field, transformationSteps)
val artificialFields = transformResult.artificialFields.map {
it.toBuilder()
.clearObjectTypesNames()
.objectTypeNames(getUnderlyingTypeNames(it.objectTypeNames))
.build()
}
val newField = listOfNotNull(
transformResult.newField?.let {
it.toBuilder()
.clearObjectTypesNames()
.objectTypeNames(getUnderlyingTypeNames(it.objectTypeNames))
.children(transform(it.children))
.build()
},
)
transformContext.artificialFields.addAll(artificialFields)
// Track overall -> underlying fields
transformContext.overallToUnderlyingFields.compute(field) { _, oldValue ->
(oldValue ?: emptyList()) + newField + artificialFields
}
return artificialFields + newField
}
/**
* Transforms a field with no [NadelTransform]s associated with it.
*/
private suspend fun transformPlain(field: ExecutableNormalizedField): ExecutableNormalizedField {
return field.toBuilder()
.clearObjectTypesNames()
.objectTypeNames(getUnderlyingTypeNames(field.objectTypeNames))
.children(transform(field.children))
.build()
.also { newField ->
// Track overall -> underlying fields
transformContext.overallToUnderlyingFields.compute(field) { _, oldValue ->
(oldValue ?: emptyList()) + newField
}
}
}
private suspend fun applyTransformationSteps(
field: ExecutableNormalizedField,
transformationSteps: List>,
): NadelTransformFieldResult {
var fieldFromPreviousTransform: ExecutableNormalizedField = field
var aggregatedTransformResult: NadelTransformFieldResult? = null
for ((_, _, transform, state) in transformationSteps) {
val transformResultForStep = transform.transformField(
executionContext,
this,
executionBlueprint,
service,
fieldFromPreviousTransform,
state,
)
aggregatedTransformResult = if (aggregatedTransformResult == null) {
transformResultForStep
} else {
NadelTransformFieldResult(
transformResultForStep.newField,
aggregatedTransformResult.artificialFields + transformResultForStep.artificialFields,
)
}
fieldFromPreviousTransform = transformResultForStep.newField ?: break
}
return aggregatedTransformResult!!
}
private fun getUnderlyingTypeNames(objectTypeNames: Collection): List {
return objectTypeNames.map {
executionBlueprint.getUnderlyingTypeName(service, overallTypeName = it)
}
}
private fun fixParentRefs(
parent: ExecutableNormalizedField?,
transformFields: List,
) {
transformFields.forEach {
it.replaceParent(parent)
fixParentRefs(parent = it, it.children)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy