graphql.nadel.enginekt.transform.hydration.NadelHydrationFieldsBuilder.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.hydration
import graphql.nadel.Service
import graphql.nadel.enginekt.blueprint.NadelBatchHydrationFieldInstruction
import graphql.nadel.enginekt.blueprint.NadelGenericHydrationInstruction
import graphql.nadel.enginekt.blueprint.NadelHydrationFieldInstruction
import graphql.nadel.enginekt.blueprint.NadelOverallExecutionBlueprint
import graphql.nadel.enginekt.blueprint.hydration.NadelHydrationActorInputDef
import graphql.nadel.enginekt.transform.GraphQLObjectTypeName
import graphql.nadel.enginekt.transform.artificial.NadelAliasHelper
import graphql.nadel.enginekt.transform.hydration.batch.NadelBatchHydrationInputBuilder
import graphql.nadel.enginekt.transform.hydration.batch.NadelBatchHydrationObjectIdFieldBuilder.makeObjectIdFields
import graphql.nadel.enginekt.transform.query.NFUtil
import graphql.nadel.enginekt.transform.result.json.JsonNode
import graphql.nadel.enginekt.util.deepClone
import graphql.nadel.enginekt.util.resolveObjectTypes
import graphql.nadel.enginekt.util.toBuilder
import graphql.nadel.enginekt.util.unwrapAll
import graphql.nadel.hooks.ServiceExecutionHooks
import graphql.normalized.ExecutableNormalizedField
import graphql.normalized.NormalizedInputValue
internal object NadelHydrationFieldsBuilder {
fun makeActorQueries(
instruction: NadelHydrationFieldInstruction,
aliasHelper: NadelAliasHelper,
fieldToHydrate: ExecutableNormalizedField,
parentNode: JsonNode,
): List {
return NadelHydrationInputBuilder.getInputValues(
instruction = instruction,
aliasHelper = aliasHelper,
fieldToHydrate = fieldToHydrate,
parentNode = parentNode,
).map { args ->
makeActorQueries(
instruction = instruction,
fieldArguments = args,
fieldChildren = deepClone(fields = fieldToHydrate.children),
)
}
}
fun makeBatchActorQueries(
executionBlueprint: NadelOverallExecutionBlueprint,
instruction: NadelBatchHydrationFieldInstruction,
aliasHelper: NadelAliasHelper,
hydratedField: ExecutableNormalizedField,
parentNodes: List,
hooks: ServiceExecutionHooks,
): List {
val argBatches = NadelBatchHydrationInputBuilder.getInputValueBatches(
instruction = instruction,
aliasHelper = aliasHelper,
hydrationField = hydratedField,
parentNodes = parentNodes,
hooks = hooks
)
val actorFieldOverallObjectTypeNames = getActorFieldOverallObjectTypenames(instruction, executionBlueprint)
val fieldChildren = deepClone(fields = hydratedField.children)
.mapNotNull { childField ->
val objectTypesAreNotReturnedByActorField =
actorFieldOverallObjectTypeNames.none { it in childField.objectTypeNames }
if (objectTypesAreNotReturnedByActorField) {
null
} else {
childField.toBuilder()
.clearObjectTypesNames()
.objectTypeNames(childField.objectTypeNames.filter { it in actorFieldOverallObjectTypeNames })
.build()
}
}
.let { children ->
children + makeObjectIdFields(executionBlueprint, aliasHelper, instruction)
}
return argBatches.map { argBatch ->
makeActorQueries(
instruction = instruction,
fieldArguments = argBatch.mapKeys { (inputDef: NadelHydrationActorInputDef) -> inputDef.name },
fieldChildren = fieldChildren,
)
}
}
private fun getActorFieldOverallObjectTypenames(
instruction: NadelBatchHydrationFieldInstruction,
executionBlueprint: NadelOverallExecutionBlueprint,
): Set {
val overallTypeName = instruction.actorFieldDef.type.unwrapAll().name
val overallType = executionBlueprint.engineSchema.getType(overallTypeName)
?: error("Unable to find overall type $overallTypeName")
val actorFieldOverallObjectTypes = resolveObjectTypes(executionBlueprint.engineSchema, overallType) { type ->
error("Unable to resolve to object type: $type")
}
return actorFieldOverallObjectTypes
.asSequence()
.map { it.name }
.toSet()
}
fun makeRequiredSourceFields(
service: Service,
executionBlueprint: NadelOverallExecutionBlueprint,
aliasHelper: NadelAliasHelper,
objectTypeName: GraphQLObjectTypeName,
instructions: List,
): List {
val underlyingTypeName = executionBlueprint.getUnderlyingTypeName(service, overallTypeName = objectTypeName)
val underlyingObjectType = service.underlyingSchema.getObjectType(underlyingTypeName)
?: error("No underlying object type")
return instructions
.asSequence()
.flatMap { it.sourceFields }
.map {
aliasHelper.toArtificial(
NFUtil.createField(
schema = service.underlyingSchema,
parentType = underlyingObjectType,
queryPathToField = it,
fieldArguments = emptyMap(),
fieldChildren = emptyList(), // This must be a leaf node
),
)
}
.toList()
}
private fun makeActorQueries(
instruction: NadelGenericHydrationInstruction,
fieldArguments: Map,
fieldChildren: List,
): ExecutableNormalizedField {
return NFUtil.createField(
schema = instruction.actorService.underlyingSchema,
parentType = instruction.actorService.underlyingSchema.queryType,
queryPathToField = instruction.queryPathToActorField,
fieldArguments = fieldArguments,
fieldChildren = fieldChildren,
)
}
}