All Downloads are FREE. Search and download functionalities are using the official Maven repository.

graphql.nadel.validation.NadelFieldValidation.kt Maven / Gradle / Ivy

Go to download

Nadel is a Java library that combines multiple GrahpQL services together into one API.

The newest version!
package graphql.nadel.validation

import graphql.nadel.Service
import graphql.nadel.enginekt.util.strictAssociateBy
import graphql.nadel.enginekt.util.unwrapAll
import graphql.nadel.validation.NadelSchemaValidationError.MissingArgumentOnUnderlying
import graphql.nadel.validation.NadelSchemaValidationError.MissingUnderlyingField
import graphql.nadel.validation.util.NadelCombinedTypeUtil.getFieldsThatServiceContributed
import graphql.nadel.validation.util.NadelCombinedTypeUtil.isCombinedType
import graphql.nadel.validation.util.NadelSchemaUtil.hasHydration
import graphql.nadel.validation.util.NadelSchemaUtil.hasRename
import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLFieldsContainer
import graphql.schema.GraphQLNamedSchemaElement
import graphql.schema.GraphQLSchema

internal class NadelFieldValidation(
    private val overallSchema: GraphQLSchema,
    services: Map,
    private val typeValidation: NadelTypeValidation,
) {
    private val renameValidation = NadelRenameValidation(this)
    private val inputValidation = NadelInputValidation()
    private val hydrationValidation = NadelHydrationValidation(services, typeValidation, overallSchema)

    fun validate(
        schemaElement: NadelServiceSchemaElement,
    ): List {
        return if (schemaElement.overall is GraphQLFieldsContainer && schemaElement.underlying is GraphQLFieldsContainer) {
            validate(
                schemaElement,
                overallFields = schemaElement.overall.fields,
                underlyingFields = schemaElement.underlying.fields,
            )
        } else {
            emptyList()
        }
    }

    fun validate(
        parent: NadelServiceSchemaElement,
        overallFields: List,
        underlyingFields: List,
    ): List {
        val underlyingFieldsByName = underlyingFields.strictAssociateBy { it.name }

        return overallFields
            .asSequence()
            .let { fieldSequence ->
                // Apply filter if necessary
                if (isCombinedType(type = parent.overall)) {
                    val fieldsThatServiceContributed = getFieldsThatServiceContributed(parent)
                    fieldSequence.filter { it.name in fieldsThatServiceContributed }
                } else {
                    fieldSequence
                }
            }
            .flatMap { overallField ->
                validate(parent, overallField, underlyingFieldsByName)
            }
            .toList()
    }

    fun validate(
        parent: NadelServiceSchemaElement,
        overallField: GraphQLFieldDefinition,
        underlyingFieldsByName: Map,
    ): List {
        return if (hasRename(overallField)) {
            renameValidation.validate(parent, overallField)
        } else if (hasHydration(overallField)) {
            hydrationValidation.validate(parent, overallField)
        } else {
            val underlyingField = underlyingFieldsByName[overallField.name]
            if (underlyingField == null) {
                listOf(
                    MissingUnderlyingField(parent, overallField = overallField),
                )
            } else {
                validate(
                    parent,
                    overallField = overallField,
                    underlyingField = underlyingField,
                )
            }
        }
    }

    fun validate(
        parent: NadelServiceSchemaElement,
        overallField: GraphQLFieldDefinition,
        underlyingField: GraphQLFieldDefinition,
    ): List {
        val argumentIssues = overallField.arguments.flatMap { overallArg ->
            val underlyingArg = underlyingField.getArgument(overallArg.name)
            if (underlyingArg == null) {
                listOf(
                    MissingArgumentOnUnderlying(parent, overallField, underlyingField, overallArg),
                )
            } else {
                val unwrappedTypeIssues = typeValidation.validate(
                    NadelServiceSchemaElement(
                        service = parent.service,
                        overall = overallArg.type.unwrapAll(),
                        underlying = underlyingArg.type.unwrapAll(),
                    )
                )

                val inputTypeIssues = inputValidation.validate(parent, overallField, overallArg, underlyingArg)

                unwrappedTypeIssues + inputTypeIssues
            }
        }

        val outputTypeIssues = typeValidation.validateOutputType(parent, overallField, underlyingField)

        return argumentIssues + outputTypeIssues
    }

    private fun isCombinedType(type: GraphQLNamedSchemaElement): Boolean {
        return isCombinedType(overallSchema, type)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy