Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
handle case where all fields are removed via Field visibility transfo…
…rmer (for input object types)
  • Loading branch information
andimarek committed Jan 7, 2026
commit de1a1523853412bc9d0f063f6dc370b4aaa0e7c0
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import graphql.schema.GraphQLInputObjectField;
import graphql.schema.GraphQLInputObjectType;
import graphql.schema.GraphQLInterfaceType;
import graphql.schema.GraphQLNamedSchemaElement;
import graphql.schema.GraphQLNamedType;
import graphql.schema.GraphQLObjectType;
import graphql.schema.GraphQLSchema;
Expand Down Expand Up @@ -160,6 +159,7 @@ private static class FieldRemovalVisitor extends GraphQLTypeVisitorStub {
private final Set<GraphQLType> removedTypes;

private final Set<GraphQLFieldDefinition> fieldDefinitionsToActuallyRemove = new LinkedHashSet<>();
private final Set<GraphQLInputObjectField> inputObjectFieldsToDelete = new LinkedHashSet<>();

private FieldRemovalVisitor(VisibleFieldPredicate visibilityPredicate,
Set<GraphQLType> removedTypes) {
Expand Down Expand Up @@ -197,6 +197,27 @@ private TraversalControl visitFieldsContainer(GraphQLFieldsContainer fieldsConta
}
}

@Override
public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType inputObjectType, TraverserContext<GraphQLSchemaElement> context) {
boolean allFieldsDeleted = true;
for (GraphQLInputObjectField inputField : inputObjectType.getFieldDefinitions()) {
VisibleFieldPredicateEnvironment environment = new VisibleFieldPredicateEnvironmentImpl(
inputField, inputObjectType);
if (!visibilityPredicate.isVisible(environment)) {
inputObjectFieldsToDelete.add(inputField);
removedTypes.add(inputField.getType());
} else {
allFieldsDeleted = false;
}
}
if (allFieldsDeleted) {
// we are deleting the whole input object type because all fields are supposed to be deleted
return deleteNode(context);
} else {
return TraversalControl.CONTINUE;
}

}

@Override
public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition definition,
Expand All @@ -211,25 +232,11 @@ public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition defin
@Override
public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField definition,
TraverserContext<GraphQLSchemaElement> context) {
return visitField(definition, context);
}

private TraversalControl visitField(GraphQLNamedSchemaElement element,
TraverserContext<GraphQLSchemaElement> context) {

VisibleFieldPredicateEnvironment environment = new VisibleFieldPredicateEnvironmentImpl(
element, context.getParentNode());
if (!visibilityPredicate.isVisible(environment)) {
deleteNode(context);

if (element instanceof GraphQLFieldDefinition) {
removedTypes.add(((GraphQLFieldDefinition) element).getType());
} else if (element instanceof GraphQLInputObjectField) {
removedTypes.add(((GraphQLInputObjectField) element).getType());
}
if (inputObjectFieldsToDelete.contains(definition)) {
return deleteNode(context);
} else {
return TraversalControl.CONTINUE;
}

return TraversalControl.CONTINUE;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1279,4 +1279,36 @@ class FieldVisibilitySchemaTransformationTest extends Specification {
(restrictedSchema.getType("Foo") as GraphQLObjectType).getFieldDefinition("toDelete") == null
}

def "remove all fields from an input type which is referenced via additional types"() {
given:
GraphQLSchema schema = TestUtil.schema("""
directive @private on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
type Query {
foo(input: Input): String
}
input Input {
foo: String
toDelete:ToDelete @private
}
input ToDelete {
toDelete:String @private
}
""")

when:
schema.typeMap
def patchedSchema = schema.transform { builder ->
schema.typeMap.each { entry ->
def type = entry.value
if (type != schema.queryType && type != schema.mutationType && type != schema.subscriptionType) {
builder.additionalType(type)
}
}
}
GraphQLSchema restrictedSchema = visibilitySchemaTransformation.apply(patchedSchema)
then:
(restrictedSchema.getType("Input") as GraphQLInputObjectType).getFieldDefinition("toDelete") == null
}


}
Loading