Skip to content

Commit fb68283

Browse files
committed
Cherry pick 3931 imperative filters
1 parent e20dad9 commit fb68283

File tree

10 files changed

+106
-47
lines changed

10 files changed

+106
-47
lines changed

src/main/java/graphql/analysis/values/ValueTraverser.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.ImmutableList;
44
import graphql.PublicApi;
5+
import graphql.collect.ImmutableKit;
56
import graphql.schema.DataFetchingEnvironment;
67
import graphql.schema.DataFetchingEnvironmentImpl;
78
import graphql.schema.GraphQLAppliedDirective;
@@ -22,7 +23,6 @@
2223
import java.util.LinkedHashMap;
2324
import java.util.List;
2425
import java.util.Map;
25-
import java.util.stream.Collectors;
2626

2727
import static graphql.Assert.assertShouldNeverHappen;
2828
import static graphql.Assert.assertTrue;
@@ -62,13 +62,12 @@ private InputElements(GraphQLInputSchemaElement startElement) {
6262

6363
private InputElements(ImmutableList<GraphQLInputSchemaElement> inputElements) {
6464
this.inputElements = inputElements;
65-
this.unwrappedInputElements = inputElements.stream()
66-
.filter(it -> !(it instanceof GraphQLNonNull || it instanceof GraphQLList))
67-
.collect(ImmutableList.toImmutableList());
65+
this.unwrappedInputElements = ImmutableKit.filter(inputElements,
66+
it -> !(it instanceof GraphQLNonNull || it instanceof GraphQLList));
6867

69-
List<GraphQLInputValueDefinition> inputValDefs = unwrappedInputElements.stream()
70-
.filter(it -> it instanceof GraphQLInputValueDefinition)
71-
.map(GraphQLInputValueDefinition.class::cast).collect(Collectors.toList());
68+
List<GraphQLInputValueDefinition> inputValDefs = ImmutableKit.filterAndMap(unwrappedInputElements,
69+
it -> it instanceof GraphQLInputValueDefinition,
70+
GraphQLInputValueDefinition.class::cast);
7271
this.lastElement = inputValDefs.isEmpty() ? null : inputValDefs.get(inputValDefs.size() - 1);
7372
}
7473

src/main/java/graphql/collect/ImmutableKit.java

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,26 @@
44
import com.google.common.collect.ImmutableMap;
55
import com.google.common.collect.ImmutableSet;
66
import graphql.Internal;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.Nullable;
79

810
import java.util.Collection;
911
import java.util.List;
1012
import java.util.Map;
1113
import java.util.function.Function;
14+
import java.util.function.Predicate;
1215

1316
import static graphql.Assert.assertNotNull;
1417

1518
@Internal
16-
@SuppressWarnings({"UnstableApiUsage"})
19+
@NullMarked
1720
public final class ImmutableKit {
1821

1922
public static <T> ImmutableList<T> emptyList() {
2023
return ImmutableList.of();
2124
}
2225

23-
public static <T> ImmutableList<T> nonNullCopyOf(Collection<T> collection) {
26+
public static <T> ImmutableList<T> nonNullCopyOf(@Nullable Collection<T> collection) {
2427
return collection == null ? emptyList() : ImmutableList.copyOf(collection);
2528
}
2629

@@ -41,9 +44,9 @@ public static <T> ImmutableList<T> concatLists(List<T> l1, List<T> l2) {
4144
* for the flexible style. Benchmarking has shown this to outperform `stream()`.
4245
*
4346
* @param collection the collection to map
44-
* @param mapper the mapper function
45-
* @param <T> for two
46-
* @param <R> for result
47+
* @param mapper the mapper function
48+
* @param <T> for two
49+
* @param <R> for result
4750
*
4851
* @return a map immutable list of results
4952
*/
@@ -58,15 +61,66 @@ public static <T, R> ImmutableList<R> map(Collection<? extends T> collection, Fu
5861
return builder.build();
5962
}
6063

64+
/**
65+
* This is more efficient than `c.stream().filter().collect()` because it does not create the intermediate objects needed
66+
* for the flexible style. Benchmarking has shown this to outperform `stream()`.
67+
*
68+
* @param collection the collection to map
69+
* @param filter the filter predicate
70+
* @param <T> for two
71+
*
72+
* @return a map immutable list of results
73+
*/
74+
public static <T> ImmutableList<T> filter(Collection<? extends T> collection, Predicate<? super T> filter) {
75+
assertNotNull(collection);
76+
assertNotNull(filter);
77+
return filterAndMap(collection, filter, Function.identity());
78+
}
79+
80+
/**
81+
* This is more efficient than `c.stream().filter().map().collect()` because it does not create the intermediate objects needed
82+
* for the flexible style. Benchmarking has shown this to outperform `stream()`.
83+
*
84+
* @param collection the collection to map
85+
* @param filter the filter predicate
86+
* @param mapper the mapper function
87+
* @param <T> for two
88+
* @param <R> for result
89+
*
90+
* @return a map immutable list of results
91+
*/
92+
public static <T, R> ImmutableList<R> filterAndMap(Collection<? extends T> collection, Predicate<? super T> filter, Function<? super T, ? extends R> mapper) {
93+
assertNotNull(collection);
94+
assertNotNull(mapper);
95+
assertNotNull(filter);
96+
ImmutableList.Builder<R> builder = ImmutableList.builderWithExpectedSize(collection.size());
97+
for (T t : collection) {
98+
if (filter.test(t)) {
99+
R r = mapper.apply(t);
100+
builder.add(r);
101+
}
102+
}
103+
return builder.build();
104+
}
105+
106+
public static <T> ImmutableList<T> flatMapList(Collection<List<T>> listLists) {
107+
ImmutableList.Builder<T> builder = ImmutableList.builder();
108+
for (List<T> t : listLists) {
109+
builder.addAll(t);
110+
}
111+
return builder.build();
112+
}
113+
114+
61115
/**
62116
* This will map a collection of items but drop any that are null from the input.
63117
* This is more efficient than `c.stream().map().collect()` because it does not create the intermediate objects needed
64118
* for the flexible style. Benchmarking has shown this to outperform `stream()`.
65119
*
66120
* @param collection the collection to map
67-
* @param mapper the mapper function
68-
* @param <T> for two
69-
* @param <R> for result
121+
* @param mapper the mapper function
122+
* @param <T> for two
123+
* @param <R> for result
70124
*
71125
* @return a map immutable list of results
72126
*/

src/main/java/graphql/execution/instrumentation/fieldvalidation/FieldValidationSupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import graphql.analysis.QueryTraverser;
88
import graphql.analysis.QueryVisitorFieldEnvironment;
99
import graphql.analysis.QueryVisitorStub;
10+
import graphql.collect.ImmutableKit;
1011
import graphql.execution.ExecutionContext;
1112
import graphql.execution.ResultPath;
1213
import graphql.language.Field;
@@ -140,7 +141,7 @@ private static class FieldValidationEnvironmentImpl implements FieldValidationEn
140141
FieldValidationEnvironmentImpl(ExecutionContext executionContext, Map<ResultPath, List<FieldAndArguments>> fieldArgumentsMap) {
141142
this.executionContext = executionContext;
142143
this.fieldArgumentsMap = fieldArgumentsMap;
143-
this.fieldArguments = fieldArgumentsMap.values().stream().flatMap(List::stream).collect(ImmutableList.toImmutableList());
144+
this.fieldArguments = ImmutableKit.flatMapList(fieldArgumentsMap.values());
144145
}
145146

146147

src/main/java/graphql/language/AstSignature.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package graphql.language;
22

3-
import com.google.common.collect.ImmutableList;
43
import graphql.PublicApi;
54
import graphql.collect.ImmutableKit;
65
import graphql.util.TraversalControl;
@@ -149,16 +148,15 @@ private Document dropUnusedQueryDefinitions(Document document, final String oper
149148
NodeVisitorStub visitor = new NodeVisitorStub() {
150149
@Override
151150
public TraversalControl visitDocument(Document node, TraverserContext<Node> context) {
152-
List<Definition> wantedDefinitions = node.getDefinitions().stream()
153-
.filter(d -> {
151+
List<Definition> wantedDefinitions = ImmutableKit.filter(node.getDefinitions(),
152+
d -> {
154153
if (d instanceof OperationDefinition) {
155154
OperationDefinition operationDefinition = (OperationDefinition) d;
156155
return isThisOperation(operationDefinition, operationName);
157156
}
158157
return d instanceof FragmentDefinition;
159158
// SDL in a query makes no sense - its gone should it be present
160-
})
161-
.collect(ImmutableList.toImmutableList());
159+
});
162160

163161
Document changedNode = node.transform(builder -> {
164162
builder.definitions(wantedDefinitions);

src/main/java/graphql/language/Document.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,9 @@ public List<Definition> getDefinitions() {
5555
* @return a list of definitions of that class or empty list
5656
*/
5757
public <T extends Definition> List<T> getDefinitionsOfType(Class<T> definitionClass) {
58-
return definitions.stream()
59-
.filter(d -> definitionClass.isAssignableFrom(d.getClass()))
60-
.map(definitionClass::cast)
61-
.collect(ImmutableList.toImmutableList());
58+
return ImmutableKit.filterAndMap(definitions,
59+
d -> definitionClass.isAssignableFrom(d.getClass()),
60+
definitionClass::cast);
6261
}
6362

6463
/**

src/main/java/graphql/language/NodeParentTree.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.ImmutableList;
44
import graphql.Internal;
55
import graphql.PublicApi;
6+
import graphql.collect.ImmutableKit;
67

78
import java.util.ArrayDeque;
89
import java.util.ArrayList;
@@ -42,10 +43,9 @@ public NodeParentTree(Deque<T> nodeStack) {
4243
}
4344

4445
private ImmutableList<String> mkPath(Deque<T> copy) {
45-
return copy.stream()
46-
.filter(node1 -> node1 instanceof NamedNode)
47-
.map(node1 -> ((NamedNode) node1).getName())
48-
.collect(ImmutableList.toImmutableList());
46+
return ImmutableKit.filterAndMap(copy,
47+
node1 -> node1 instanceof NamedNode,
48+
node1 -> ((NamedNode) node1).getName());
4949
}
5050

5151

src/main/java/graphql/language/SelectionSet.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ public List<Selection> getSelections() {
5454
* @return a list of selections of that class or empty list
5555
*/
5656
public <T extends Selection> List<T> getSelectionsOfType(Class<T> selectionClass) {
57-
return selections.stream()
58-
.filter(d -> selectionClass.isAssignableFrom(d.getClass()))
59-
.map(selectionClass::cast)
60-
.collect(ImmutableList.toImmutableList());
57+
return ImmutableKit.filterAndMap(selections,
58+
d -> selectionClass.isAssignableFrom(d.getClass()),
59+
selectionClass::cast);
6160
}
6261

6362
@Override

src/main/java/graphql/schema/visibility/BlockedFields.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package graphql.schema.visibility;
22

3-
import com.google.common.collect.ImmutableList;
43
import graphql.Internal;
54
import graphql.PublicApi;
5+
import graphql.collect.ImmutableKit;
66
import graphql.schema.GraphQLFieldDefinition;
77
import graphql.schema.GraphQLFieldsContainer;
88
import graphql.schema.GraphQLInputFieldsContainer;
@@ -35,9 +35,8 @@ private BlockedFields(List<Pattern> patterns) {
3535

3636
@Override
3737
public List<GraphQLFieldDefinition> getFieldDefinitions(GraphQLFieldsContainer fieldsContainer) {
38-
return fieldsContainer.getFieldDefinitions().stream()
39-
.filter(fieldDefinition -> !block(mkFQN(fieldsContainer.getName(), fieldDefinition.getName())))
40-
.collect(ImmutableList.toImmutableList());
38+
return ImmutableKit.filter(fieldsContainer.getFieldDefinitions(),
39+
fieldDefinition -> !block(mkFQN(fieldsContainer.getName(), fieldDefinition.getName())));
4140
}
4241

4342
@Override
@@ -53,9 +52,8 @@ public GraphQLFieldDefinition getFieldDefinition(GraphQLFieldsContainer fieldsCo
5352

5453
@Override
5554
public List<GraphQLInputObjectField> getFieldDefinitions(GraphQLInputFieldsContainer fieldsContainer) {
56-
return fieldsContainer.getFieldDefinitions().stream()
57-
.filter(fieldDefinition -> !block(mkFQN(fieldsContainer.getName(), fieldDefinition.getName())))
58-
.collect(ImmutableList.toImmutableList());
55+
return ImmutableKit.filter(fieldsContainer.getFieldDefinitions(),
56+
fieldDefinition -> !block(mkFQN(fieldsContainer.getName(), fieldDefinition.getName())));
5957
}
6058

6159
@Override

src/test/groovy/graphql/collect/ImmutableKitTest.groovy

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package graphql.collect
22

33
import com.google.common.collect.ImmutableList
4-
import com.google.common.collect.ImmutableMap
54
import spock.lang.Specification
65

76
class ImmutableKitTest extends Specification {
@@ -63,4 +62,16 @@ class ImmutableKitTest extends Specification {
6362
then:
6463
set == ["a", "b", "c", "d", "e", "f"] as Set
6564
}
65+
66+
def "flatMapList works"() {
67+
def listOfLists = [
68+
["A", "B"],
69+
["C"],
70+
["D", "E"],
71+
]
72+
when:
73+
def flatList = ImmutableKit.flatMapList(listOfLists)
74+
then:
75+
flatList == ["A", "B", "C", "D", "E",]
76+
}
6677
}

src/test/groovy/graphql/util/FpKitTest.groovy

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,20 +99,20 @@ class FpKitTest extends Specification {
9999
}
100100

101101
def "set intersection works"() {
102-
def set1 = ["A","B","C"] as Set
103-
def set2 = ["A","C","D"] as Set
102+
def set1 = ["A", "B", "C"] as Set
103+
def set2 = ["A", "C", "D"] as Set
104104
def singleSetA = ["A"] as Set
105-
def disjointSet = ["X","Y"] as Set
105+
def disjointSet = ["X", "Y"] as Set
106106

107107
when:
108108
def intersection = FpKit.intersection(set1, set2)
109109
then:
110-
intersection == ["A","C"] as Set
110+
intersection == ["A", "C"] as Set
111111

112112
when: // reversed parameters
113113
intersection = FpKit.intersection(set2, set1)
114114
then:
115-
intersection == ["A","C"] as Set
115+
intersection == ["A", "C"] as Set
116116

117117
when: // singles
118118
intersection = FpKit.intersection(set1, singleSetA)
@@ -130,7 +130,7 @@ class FpKitTest extends Specification {
130130
intersection.isEmpty()
131131

132132
when: // disjoint reversed
133-
intersection = FpKit.intersection(disjointSet,set1)
133+
intersection = FpKit.intersection(disjointSet, set1)
134134
then:
135135
intersection.isEmpty()
136136
}

0 commit comments

Comments
 (0)