Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 21b9743

Browse files
authored
Merge pull request #4203 from graphql-java/remove-all-fields-visibility-transformer
All fields removed from object/interface via field visibility transformer which is reachable via additional types
2 parents 021fe1b + de1a152 commit 21b9743

File tree

2 files changed

+140
-27
lines changed

2 files changed

+140
-27
lines changed

src/main/java/graphql/schema/transform/FieldVisibilitySchemaTransformation.java

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import graphql.PublicApi;
55
import graphql.schema.GraphQLEnumType;
66
import graphql.schema.GraphQLFieldDefinition;
7+
import graphql.schema.GraphQLFieldsContainer;
78
import graphql.schema.GraphQLImplementingType;
89
import graphql.schema.GraphQLInputObjectField;
910
import graphql.schema.GraphQLInputObjectType;
1011
import graphql.schema.GraphQLInterfaceType;
11-
import graphql.schema.GraphQLNamedSchemaElement;
1212
import graphql.schema.GraphQLNamedType;
1313
import graphql.schema.GraphQLObjectType;
1414
import graphql.schema.GraphQLSchema;
@@ -24,6 +24,7 @@
2424

2525
import java.util.ArrayList;
2626
import java.util.HashSet;
27+
import java.util.LinkedHashSet;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.Objects;
@@ -45,7 +46,9 @@ public class FieldVisibilitySchemaTransformation {
4546
private final Runnable afterTransformationHook;
4647

4748
public FieldVisibilitySchemaTransformation(VisibleFieldPredicate visibleFieldPredicate) {
48-
this(visibleFieldPredicate, () -> {}, () -> {});
49+
this(visibleFieldPredicate, () -> {
50+
}, () -> {
51+
});
4952
}
5053

5154
public FieldVisibilitySchemaTransformation(VisibleFieldPredicate visibleFieldPredicate,
@@ -155,40 +158,85 @@ private static class FieldRemovalVisitor extends GraphQLTypeVisitorStub {
155158
private final VisibleFieldPredicate visibilityPredicate;
156159
private final Set<GraphQLType> removedTypes;
157160

161+
private final Set<GraphQLFieldDefinition> fieldDefinitionsToActuallyRemove = new LinkedHashSet<>();
162+
private final Set<GraphQLInputObjectField> inputObjectFieldsToDelete = new LinkedHashSet<>();
163+
158164
private FieldRemovalVisitor(VisibleFieldPredicate visibilityPredicate,
159165
Set<GraphQLType> removedTypes) {
160166
this.visibilityPredicate = visibilityPredicate;
161167
this.removedTypes = removedTypes;
162168
}
163169

164170
@Override
165-
public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition definition,
166-
TraverserContext<GraphQLSchemaElement> context) {
167-
return visitField(definition, context);
171+
public TraversalControl visitGraphQLObjectType(GraphQLObjectType objectType, TraverserContext<GraphQLSchemaElement> context) {
172+
return visitFieldsContainer(objectType, context);
168173
}
169174

170175
@Override
171-
public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField definition,
172-
TraverserContext<GraphQLSchemaElement> context) {
173-
return visitField(definition, context);
176+
public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType objectType, TraverserContext<GraphQLSchemaElement> context) {
177+
return visitFieldsContainer(objectType, context);
174178
}
175179

176-
private TraversalControl visitField(GraphQLNamedSchemaElement element,
177-
TraverserContext<GraphQLSchemaElement> context) {
178-
179-
VisibleFieldPredicateEnvironment environment = new VisibleFieldPredicateEnvironmentImpl(
180-
element, context.getParentNode());
181-
if (!visibilityPredicate.isVisible(environment)) {
182-
deleteNode(context);
180+
private TraversalControl visitFieldsContainer(GraphQLFieldsContainer fieldsContainer, TraverserContext<GraphQLSchemaElement> context) {
181+
boolean allFieldsDeleted = true;
182+
for (GraphQLFieldDefinition fieldDefinition : fieldsContainer.getFieldDefinitions()) {
183+
VisibleFieldPredicateEnvironment environment = new VisibleFieldPredicateEnvironmentImpl(
184+
fieldDefinition, fieldsContainer);
185+
if (!visibilityPredicate.isVisible(environment)) {
186+
fieldDefinitionsToActuallyRemove.add(fieldDefinition);
187+
removedTypes.add(fieldDefinition.getType());
188+
} else {
189+
allFieldsDeleted = false;
190+
}
191+
}
192+
if (allFieldsDeleted) {
193+
// we are deleting the whole interface type because all fields are supposed to be deleted
194+
return deleteNode(context);
195+
} else {
196+
return TraversalControl.CONTINUE;
197+
}
198+
}
183199

184-
if (element instanceof GraphQLFieldDefinition) {
185-
removedTypes.add(((GraphQLFieldDefinition) element).getType());
186-
} else if (element instanceof GraphQLInputObjectField) {
187-
removedTypes.add(((GraphQLInputObjectField) element).getType());
200+
@Override
201+
public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType inputObjectType, TraverserContext<GraphQLSchemaElement> context) {
202+
boolean allFieldsDeleted = true;
203+
for (GraphQLInputObjectField inputField : inputObjectType.getFieldDefinitions()) {
204+
VisibleFieldPredicateEnvironment environment = new VisibleFieldPredicateEnvironmentImpl(
205+
inputField, inputObjectType);
206+
if (!visibilityPredicate.isVisible(environment)) {
207+
inputObjectFieldsToDelete.add(inputField);
208+
removedTypes.add(inputField.getType());
209+
} else {
210+
allFieldsDeleted = false;
188211
}
189212
}
213+
if (allFieldsDeleted) {
214+
// we are deleting the whole input object type because all fields are supposed to be deleted
215+
return deleteNode(context);
216+
} else {
217+
return TraversalControl.CONTINUE;
218+
}
190219

191-
return TraversalControl.CONTINUE;
220+
}
221+
222+
@Override
223+
public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition definition,
224+
TraverserContext<GraphQLSchemaElement> context) {
225+
if (fieldDefinitionsToActuallyRemove.contains(definition)) {
226+
return deleteNode(context);
227+
} else {
228+
return TraversalControl.CONTINUE;
229+
}
230+
}
231+
232+
@Override
233+
public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField definition,
234+
TraverserContext<GraphQLSchemaElement> context) {
235+
if (inputObjectFieldsToDelete.contains(definition)) {
236+
return deleteNode(context);
237+
} else {
238+
return TraversalControl.CONTINUE;
239+
}
192240
}
193241
}
194242

@@ -216,12 +264,12 @@ public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node,
216264
public TraversalControl visitGraphQLType(GraphQLSchemaElement node,
217265
TraverserContext<GraphQLSchemaElement> context) {
218266
if (observedBeforeTransform.contains(node) &&
219-
!observedAfterTransform.contains(node) &&
220-
(node instanceof GraphQLObjectType ||
221-
node instanceof GraphQLEnumType ||
222-
node instanceof GraphQLInputObjectType ||
223-
node instanceof GraphQLInterfaceType ||
224-
node instanceof GraphQLUnionType)) {
267+
!observedAfterTransform.contains(node) &&
268+
(node instanceof GraphQLObjectType ||
269+
node instanceof GraphQLEnumType ||
270+
node instanceof GraphQLInputObjectType ||
271+
node instanceof GraphQLInterfaceType ||
272+
node instanceof GraphQLUnionType)) {
225273

226274
return deleteNode(context);
227275
}

src/test/groovy/graphql/schema/transform/FieldVisibilitySchemaTransformationTest.groovy

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ class FieldVisibilitySchemaTransformationTest extends Specification {
10731073
def visibilitySchemaTransformation = new FieldVisibilitySchemaTransformation({ environment ->
10741074
def directives = (environment.schemaElement as GraphQLDirectiveContainer).appliedDirectives
10751075
return directives.find({ directive -> directive.name == "private" }) == null
1076-
}, { -> callbacks << "before" }, { -> callbacks << "after"} )
1076+
}, { -> callbacks << "before" }, { -> callbacks << "after" })
10771077

10781078
GraphQLSchema schema = TestUtil.schema("""
10791079
@@ -1245,5 +1245,70 @@ class FieldVisibilitySchemaTransformationTest extends Specification {
12451245
then:
12461246
(restrictedSchema.getType("Account") as GraphQLObjectType).getFieldDefinition("billingStatus") == null
12471247
restrictedSchema.getType("BillingStatus") == null
1248+
1249+
}
1250+
1251+
def "remove all fields from a type which is referenced via additional types"() {
1252+
given:
1253+
GraphQLSchema schema = TestUtil.schema("""
1254+
directive @private on FIELD_DEFINITION
1255+
type Query {
1256+
foo: Foo
1257+
}
1258+
type Foo {
1259+
foo: String
1260+
toDelete: ToDelete @private
1261+
}
1262+
type ToDelete {
1263+
toDelete:String @private
1264+
}
1265+
""")
1266+
1267+
when:
1268+
schema.typeMap
1269+
def patchedSchema = schema.transform { builder ->
1270+
schema.typeMap.each { entry ->
1271+
def type = entry.value
1272+
if (type != schema.queryType && type != schema.mutationType && type != schema.subscriptionType) {
1273+
builder.additionalType(type)
1274+
}
1275+
}
1276+
}
1277+
GraphQLSchema restrictedSchema = visibilitySchemaTransformation.apply(patchedSchema)
1278+
then:
1279+
(restrictedSchema.getType("Foo") as GraphQLObjectType).getFieldDefinition("toDelete") == null
12481280
}
1281+
1282+
def "remove all fields from an input type which is referenced via additional types"() {
1283+
given:
1284+
GraphQLSchema schema = TestUtil.schema("""
1285+
directive @private on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
1286+
type Query {
1287+
foo(input: Input): String
1288+
}
1289+
input Input {
1290+
foo: String
1291+
toDelete:ToDelete @private
1292+
}
1293+
input ToDelete {
1294+
toDelete:String @private
1295+
}
1296+
""")
1297+
1298+
when:
1299+
schema.typeMap
1300+
def patchedSchema = schema.transform { builder ->
1301+
schema.typeMap.each { entry ->
1302+
def type = entry.value
1303+
if (type != schema.queryType && type != schema.mutationType && type != schema.subscriptionType) {
1304+
builder.additionalType(type)
1305+
}
1306+
}
1307+
}
1308+
GraphQLSchema restrictedSchema = visibilitySchemaTransformation.apply(patchedSchema)
1309+
then:
1310+
(restrictedSchema.getType("Input") as GraphQLInputObjectType).getFieldDefinition("toDelete") == null
1311+
}
1312+
1313+
12491314
}

0 commit comments

Comments
 (0)