Skip to content

Commit f61baaa

Browse files
WIP
1 parent 1ebf1a9 commit f61baaa

5 files changed

Lines changed: 253 additions & 246 deletions

File tree

src/main/java/graphql/execution/instrumentation/dataloader/PerLevelDataLoaderDispatchStrategy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public PerLevelDataLoaderDispatchStrategy(ExecutionContext executionContext) {
9999

100100
@Override
101101
public void deferredField(ExecutionContext executionContext, MergedField currentField) {
102-
throw new UnsupportedOperationException("Data Loaders cannot be used to resolve deferred fields");
102+
// throw new UnsupportedOperationException("Data Loaders cannot be used to resolve deferred fields");
103103
}
104104

105105
@Override
Lines changed: 89 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package graphql.execution.instrumentation.dataloader
22

3+
import com.fasterxml.jackson.databind.ObjectMapper
34
import graphql.Directives
45
import graphql.GraphQL
56
import graphql.execution.instrumentation.Instrumentation
@@ -61,19 +62,23 @@ class DataLoaderPerformanceData {
6162
]]
6263
]
6364

64-
static def query = """
65+
static String getQuery(boolean enableDeferred) {
66+
return """
6567
query {
6668
shops {
6769
id name
68-
departments {
69-
id name
70-
products {
70+
... @defer(if: $enableDeferred) {
71+
departments {
7172
id name
73+
products {
74+
id name
75+
}
7276
}
73-
}
77+
}
7478
}
7579
}
7680
"""
81+
}
7782

7883
static def expectedExpensiveData = [
7984
shops : [[name : "Shop 1",
@@ -162,7 +167,8 @@ class DataLoaderPerformanceData {
162167
assert incrementalResultsItems.any { it == [path: [], data: [expensiveShops: [[id: "exshop-1", name: "ExShop 1"], [id: "exshop-2", name: "ExShop 2"], [id: "exshop-3", name: "ExShop 3"]]]] }
163168
}
164169

165-
static def expensiveQuery = """
170+
static String getExpensiveQuery(boolean deferredEnabled) {
171+
return """
166172
query {
167173
shops {
168174
name
@@ -171,180 +177,59 @@ class DataLoaderPerformanceData {
171177
products {
172178
name
173179
}
174-
expensiveProducts {
175-
name
176-
}
177-
}
178-
expensiveDepartments {
179-
name
180-
products {
181-
name
182-
}
183-
expensiveProducts {
184-
name
185-
}
186-
}
187-
}
188-
expensiveShops {
189-
name
190-
departments {
191-
name
192-
products {
193-
name
194-
}
195-
expensiveProducts {
196-
name
197-
}
180+
... @defer(if: $deferredEnabled) {
181+
expensiveProducts {
182+
name
183+
}
184+
}
198185
}
199-
expensiveDepartments {
200-
name
201-
products {
202-
name
203-
}
204-
expensiveProducts {
186+
... @defer(if: $deferredEnabled) {
187+
expensiveDepartments {
205188
name
206-
}
207-
}
208-
}
209-
}
210-
"""
211-
212-
static def expectedInitialDeferredData = [
213-
data : [
214-
shops: [
215-
[id: "shop-1", name: "Shop 1"],
216-
[id: "shop-2", name: "Shop 2"],
217-
[id: "shop-3", name: "Shop 3"],
218-
]
219-
],
220-
hasNext: true
221-
]
222-
223-
static def expectedListOfDeferredData = [
224-
[
225-
hasNext : true,
226-
incremental: [[
227-
path: ["shops", 0],
228-
data: [
229-
departments: [
230-
[id: "department-1", name: "Department 1", products: [[id: "product-1", name: "Product 1"]]],
231-
[id: "department-2", name: "Department 2", products: [[id: "product-2", name: "Product 2"]]],
232-
[id: "department-3", name: "Department 3", products: [[id: "product-3", name: "Product 3"]]]
233-
]
234-
]
235-
]],
236-
],
237-
[
238-
hasNext : true,
239-
incremental: [[
240-
path: ["shops", 1],
241-
data: [
242-
departments: [
243-
[id: "department-4", name: "Department 4", products: [[id: "product-4", name: "Product 4"]]],
244-
[id: "department-5", name: "Department 5", products: [[id: "product-5", name: "Product 5"]]],
245-
[id: "department-6", name: "Department 6", products: [[id: "product-6", name: "Product 6"]]]
246-
]
247-
],
248-
]],
249-
],
250-
[
251-
hasNext : false,
252-
incremental: [[
253-
path: ["shops", 2],
254-
data: [
255-
departments: [
256-
[id: "department-7", name: "Department 7", products: [[id: "product-7", name: "Product 7"]]],
257-
[id: "department-8", name: "Department 8", products: [[id: "product-8", name: "Product 8"]]],
258-
[id: "department-9", name: "Department 9", products: [[id: "product-9", name: "Product 9"]]]
259-
]
260-
]
261-
]],
262-
]
263-
]
264-
265-
266-
static def deferredQuery = """
267-
query {
268-
shops {
269-
id name
270-
... @defer {
271-
departments {
272-
id name
273189
products {
274-
id name
190+
name
275191
}
276-
}
277-
}
278-
}
279-
}
280-
"""
281-
282-
static def expensiveDeferredQuery = """
283-
query {
284-
shops {
285-
id name
286-
... @defer {
287-
departments {
288-
name
289-
... @defer {
290-
products {
291-
name
292-
}
293-
}
294-
... @defer {
192+
... @defer(if: $deferredEnabled) {
295193
expensiveProducts {
296194
name
297195
}
298196
}
299197
}
300198
}
301-
... @defer {
302-
expensiveDepartments {
199+
}
200+
... @defer(if: $deferredEnabled) {
201+
expensiveShops {
202+
name
203+
departments {
303204
name
304205
products {
305206
name
306207
}
307-
expensiveProducts {
208+
... @defer(if: $deferredEnabled) {
209+
expensiveProducts {
210+
name
211+
}
212+
}
213+
}
214+
... @defer(if: $deferredEnabled) {
215+
expensiveDepartments {
308216
name
217+
products {
218+
name
219+
}
220+
... @defer(if: $deferredEnabled) {
221+
expensiveProducts {
222+
name
223+
}
224+
}
309225
}
310-
}
311-
}
312-
}
313-
... @defer {
314-
expensiveShops {
315-
id name
226+
}
316227
}
317228
}
318229
}
319-
"""
230+
"""
320231

321-
static def expectedExpensiveDeferredData = [
322-
[[id: "exshop-1", name: "ExShop 1"], [id: "exshop-2", name: "ExShop 2"], [id: "exshop-3", name: "ExShop 3"]],
323-
[[name: "Department 1",products:null, expensiveProducts:null], [name: "Department 2",products:null, expensiveProducts:null], [name: "Department 3",products:null, expensiveProducts:null]],
324-
[[name: "Department 1", products: [[name: "Product 1"]], expensiveProducts: [[name: "Product 1"]]], [name: "Department 2", products: [[name: "Product 2"]], expensiveProducts: [[name: "Product 2"]]], [name: "Department 3", products: [[name: "Product 3"]], expensiveProducts: [[name: "Product 3"]]]],
325-
[[name: "Department 4",products:null, expensiveProducts:null], [name: "Department 5",products:null, expensiveProducts:null], [name: "Department 6",products:null, expensiveProducts:null]],
326-
[[name: "Department 4", products: [[name: "Product 4"]], expensiveProducts: [[name: "Product 4"]]], [name: "Department 5", products: [[name: "Product 5"]], expensiveProducts: [[name: "Product 5"]]], [name: "Department 6", products: [[name: "Product 6"]], expensiveProducts: [[name: "Product 6"]]]],
327-
[[name: "Department 7",products:null, expensiveProducts:null], [name: "Department 8",products:null, expensiveProducts:null], [name: "Department 9",products:null, expensiveProducts:null]],
328-
[[name: "Department 7", products: [[name: "Product 7"]], expensiveProducts: [[name: "Product 7"]]], [name: "Department 8", products: [[name: "Product 8"]], expensiveProducts: [[name: "Product 8"]]], [name: "Department 9", products: [[name: "Product 9"]], expensiveProducts: [[name: "Product 9"]]]],
329-
[[name: "Product 1"]],
330-
[[name: "Product 1"]],
331-
[[name: "Product 2"]],
332-
[[name: "Product 2"]],
333-
[[name: "Product 3"]],
334-
[[name: "Product 3"]],
335-
[[name: "Product 4"]],
336-
[[name: "Product 4"]],
337-
[[name: "Product 5"]],
338-
[[name: "Product 5"]],
339-
[[name: "Product 6"]],
340-
[[name: "Product 6"]],
341-
[[name: "Product 7"]],
342-
[[name: "Product 7"]],
343-
[[name: "Product 8"]],
344-
[[name: "Product 8"]],
345-
[[name: "Product 9"]],
346-
[[name: "Product 9"]],
347-
]
232+
}
348233

349234
static List<Map<String, Object>> getIncrementalResults(IncrementalExecutionResult initialResult) {
350235
Publisher<DelayedIncrementalPartialResult> deferredResultStream = initialResult.incrementalItemPublisher
@@ -356,4 +241,48 @@ class DataLoaderPerformanceData {
356241
return subscriber.getEvents()
357242
.collect { it.toSpecification() }
358243
}
244+
245+
246+
static Map<String, Object> combineExecutionResults(Map<String, Object> initialResult, List<Map<String, Object>> incrementalResults) {
247+
Map<String, Object> combinedResult = deepClone(initialResult, Map.class)
248+
249+
incrementalResults
250+
// groovy's flatMap
251+
.collectMany { (List) it.incremental }
252+
.each { result ->
253+
def parent = findByPath((Map) combinedResult.data, (List) result.path)
254+
if (parent instanceof Map) {
255+
parent.putAll((Map) result.data)
256+
} else if (parent instanceof List) {
257+
parent.addAll(result.data)
258+
} else {
259+
throw new RuntimeException("Unexpected parent type: ${parent.getClass()}")
260+
}
261+
262+
if(combinedResult.errors != null && !result.errors.isEmpty()) {
263+
if(combinedResult.errors == null) {
264+
combinedResult.errors = []
265+
}
266+
267+
combinedResult.errors.addAll(result.errors)
268+
}
269+
}
270+
271+
combinedResult.remove("hasNext")
272+
273+
combinedResult
274+
}
275+
276+
private static ObjectMapper objectMapper = new ObjectMapper()
277+
private static <T> T deepClone(Object obj, Class<T> clazz) {
278+
return objectMapper.readValue(objectMapper.writeValueAsString(obj), clazz)
279+
}
280+
281+
private static Object findByPath(Map<String, Object> data, List<Object> path) {
282+
def current = data
283+
path.each { key ->
284+
current = current[key]
285+
}
286+
current
287+
}
359288
}

0 commit comments

Comments
 (0)