All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.apollographql.apollo3.ast.check_key_fields.kt Maven / Gradle / Ivy
package com.apollographql.apollo3.ast
private class CheckKeyFieldsScope(
val schema: Schema,
val allFragmentDefinitions: Map,
)
fun checkKeyFields(operation: GQLOperationDefinition, schema: Schema, allFragmentDefinitions: Map) {
val parentType = operation.rootTypeDefinition(schema)!!.name
CheckKeyFieldsScope(schema, allFragmentDefinitions).checkField("Operation(${operation.name})", operation.selectionSet.selections, parentType)
}
fun checkKeyFields(fragmentDefinition: GQLFragmentDefinition, schema: Schema, allFragmentDefinitions: Map) {
CheckKeyFieldsScope(schema, allFragmentDefinitions).checkField("Fragment(${fragmentDefinition.name})", fragmentDefinition.selectionSet.selections, fragmentDefinition.typeCondition.name)
}
private fun CheckKeyFieldsScope.checkField(
path: String,
selections: List,
parentType: String,
) {
schema.typeDefinitions.values.filterIsInstance().forEach {
checkFieldSet(path, selections, parentType, it.name)
}
}
private fun CheckKeyFieldsScope.checkFieldSet(path: String, selections: List, parentType: String, possibleType: String) {
val implementedTypes = schema.implementedTypes(possibleType)
val mergedFields = collectFields(selections, parentType, implementedTypes).groupBy {
it.field.name
}.values
if (implementedTypes.contains(parentType)) {
// only check types that are actually possible
val fieldNames = mergedFields.map { it.first().field }
.filter { it.alias == null }
.map { it.name }.toSet()
val keyFieldNames = schema.keyFields(possibleType)
val missingFieldNames = keyFieldNames.subtract(fieldNames)
check(missingFieldNames.isEmpty()) {
"Key Field(s) '$missingFieldNames' are not queried on $possibleType at $path"
}
}
mergedFields.forEach {
val first = it.first()
val rawTypeName = first.field.definitionFromScope(schema, first.parentType)!!.type.leafType().name
checkField(path + "." + first.field.name, it.flatMap { it.field.selectionSet?.selections ?: emptyList() }, rawTypeName)
}
}
private class FieldWithParent(val field: GQLField, val parentType: String)
private fun CheckKeyFieldsScope.collectFields(
selections: List,
parentType: String,
implementedTypes: Set,
): List {
if (!implementedTypes.contains(parentType)) {
return emptyList()
}
return selections.flatMap {
when (it) {
is GQLField -> {
if (it.directives.hasCondition()) {
return@flatMap emptyList()
}
listOf(FieldWithParent(it, parentType))
}
is GQLInlineFragment -> {
if (it.directives.hasCondition()) {
return@flatMap emptyList()
}
collectFields(it.selectionSet.selections, it.typeCondition.name, implementedTypes)
}
is GQLFragmentSpread -> {
if (it.directives.hasCondition()) {
return@flatMap emptyList()
}
val fragmentDefinition = allFragmentDefinitions[it.name]!!
collectFields(fragmentDefinition.selectionSet.selections, fragmentDefinition.typeCondition.name, implementedTypes)
}
}
}
}
private fun List?.hasCondition(): Boolean {
return this?.any {
it.name == "skip" && (it.arguments!!.arguments.first().value as? GQLStringValue)?.value != "false"
|| it.name == "include" && (it.arguments!!.arguments.first().value as? GQLStringValue)?.value != "true"
} ?: false
}