Skip to content

Commit b4920da

Browse files
committed
implement defer postprocessor
1 parent 3a00449 commit b4920da

7 files changed

Lines changed: 357 additions & 76 deletions

File tree

v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_defer_test.go

Lines changed: 254 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
. "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/datasourcetesting"
77
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/plan"
8+
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/postprocess"
89
"github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve"
910
)
1011

@@ -81,7 +82,7 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
8182
},
8283
}
8384

84-
t.Run("defer User.title", func(t *testing.T) {
85+
t.Run("defer User.title - defer postprocess disabled", func(t *testing.T) {
8586
RunWithPermutations(
8687
t,
8788
definition,
@@ -95,7 +96,7 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
9596
}
9697
}`,
9798
"User",
98-
&plan.SynchronousResponsePlan{
99+
&plan.DeferResponsePlan{
99100
Response: &resolve.GraphQLResponse{
100101
Fetches: resolve.Sequence(
101102
resolve.Single(&resolve.SingleFetch{
@@ -104,12 +105,82 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
104105
DeferID: "1",
105106
},
106107
FetchConfiguration: resolve.FetchConfiguration{
107-
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title}}"}}`,
108+
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title}}"}}`,
109+
PostProcessing: DefaultPostProcessingConfiguration,
110+
DataSource: &Source{},
111+
},
112+
DataSourceIdentifier: []byte("graphql_datasource.Source"),
113+
}),
114+
resolve.Single(&resolve.SingleFetch{
115+
FetchDependencies: resolve.FetchDependencies{
116+
FetchID: 1,
117+
},
118+
FetchConfiguration: resolve.FetchConfiguration{
119+
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {name}}"}}`,
108120
PostProcessing: DefaultPostProcessingConfiguration,
109121
DataSource: &Source{},
110122
},
111123
DataSourceIdentifier: []byte("graphql_datasource.Source"),
112124
}),
125+
),
126+
Data: &resolve.Object{
127+
Fields: []*resolve.Field{
128+
{
129+
Name: []byte("user"),
130+
Value: &resolve.Object{
131+
Path: []string{"user"},
132+
Nullable: false,
133+
PossibleTypes: map[string]struct{}{
134+
"User": {},
135+
},
136+
TypeName: "User",
137+
Fields: []*resolve.Field{
138+
{
139+
Name: []byte("name"),
140+
Value: &resolve.String{
141+
Path: []string{"name"},
142+
},
143+
},
144+
{
145+
Name: []byte("title"),
146+
Defer: &resolve.DeferField{
147+
DeferID: "1",
148+
},
149+
Value: &resolve.String{
150+
Path: []string{"title"},
151+
},
152+
},
153+
},
154+
},
155+
},
156+
},
157+
},
158+
},
159+
},
160+
planConfiguration,
161+
WithDefaultCustomPostProcessor(postprocess.DisableResolveInputTemplates(), postprocess.DisableCreateConcreteSingleFetchTypes(), postprocess.DisableCreateParallelNodes(), postprocess.DisableMergeFields(), postprocess.DisableDefer()),
162+
WithDefer(),
163+
WithCalculateFieldDependencies(),
164+
)
165+
})
166+
167+
t.Run("defer User.title", func(t *testing.T) {
168+
RunWithPermutations(
169+
t,
170+
definition,
171+
`
172+
query User {
173+
user {
174+
name
175+
... @defer {
176+
title
177+
}
178+
}
179+
}`,
180+
"User",
181+
&plan.DeferResponsePlan{
182+
Response: &resolve.GraphQLResponse{
183+
Fetches: resolve.Sequence(
113184
resolve.Single(&resolve.SingleFetch{
114185
FetchDependencies: resolve.FetchDependencies{
115186
FetchID: 1,
@@ -155,6 +226,25 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
155226
},
156227
},
157228
},
229+
Defers: []*resolve.DeferGraphQLResponse{
230+
{
231+
DeferID: "1",
232+
Fetches: resolve.Sequence(
233+
resolve.Single(&resolve.SingleFetch{
234+
FetchDependencies: resolve.FetchDependencies{
235+
FetchID: 0,
236+
DeferID: "1",
237+
},
238+
FetchConfiguration: resolve.FetchConfiguration{
239+
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title}}"}}`,
240+
PostProcessing: DefaultPostProcessingConfiguration,
241+
DataSource: &Source{},
242+
},
243+
DataSourceIdentifier: []byte("graphql_datasource.Source"),
244+
}),
245+
),
246+
},
247+
},
158248
},
159249
planConfiguration,
160250
WithDefaultPostProcessor(),
@@ -283,7 +373,7 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
283373
},
284374
}
285375

286-
t.Run("defer User.lastName", func(t *testing.T) {
376+
t.Run("defer User.lastName. defer postprocess disabled", func(t *testing.T) {
287377
RunWithPermutations(
288378
t,
289379
definition,
@@ -298,12 +388,12 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
298388
}
299389
}`,
300390
"User",
301-
&plan.SynchronousResponsePlan{
391+
&plan.DeferResponsePlan{
302392
Response: &resolve.GraphQLResponse{
303393
Fetches: resolve.Sequence(
304394
resolve.Single(&resolve.SingleFetch{
305395
FetchConfiguration: resolve.FetchConfiguration{
306-
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title __typename id}}"}}`,
396+
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title __typename id}}"}}`,
307397
PostProcessing: DefaultPostProcessingConfiguration,
308398
DataSource: &Source{},
309399
},
@@ -316,7 +406,7 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
316406
}, FetchConfiguration: resolve.FetchConfiguration{
317407
RequiresEntityBatchFetch: false,
318408
RequiresEntityFetch: true,
319-
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename firstName}}}","variables":{"representations":[$$0$$]}}}`,
409+
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename firstName}}}","variables":{"representations":[$$0$$]}}}`,
320410
DataSource: &Source{},
321411
SetTemplateOutputToNullOnVariableNull: true,
322412
Variables: []resolve.Variable{
@@ -354,7 +444,7 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
354444
}, FetchConfiguration: resolve.FetchConfiguration{
355445
RequiresEntityBatchFetch: false,
356446
RequiresEntityFetch: true,
357-
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename lastName}}}","variables":{"representations":[$$0$$]}}}`,
447+
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename lastName}}}","variables":{"representations":[$$0$$]}}}`,
358448
DataSource: &Source{},
359449
SetTemplateOutputToNullOnVariableNull: true,
360450
Variables: []resolve.Variable{
@@ -426,6 +516,162 @@ func TestGraphQLDataSourceDefer(t *testing.T) {
426516
},
427517
},
428518
planConfiguration,
519+
WithDefaultCustomPostProcessor(postprocess.DisableResolveInputTemplates(), postprocess.DisableCreateConcreteSingleFetchTypes(), postprocess.DisableCreateParallelNodes(), postprocess.DisableMergeFields(), postprocess.DisableDefer()),
520+
WithDefer(),
521+
WithCalculateFieldDependencies(),
522+
)
523+
})
524+
525+
t.Run("defer User.lastName", func(t *testing.T) {
526+
RunWithPermutations(
527+
t,
528+
definition,
529+
`
530+
query User {
531+
user {
532+
title
533+
firstName
534+
... @defer {
535+
lastName
536+
}
537+
}
538+
}`,
539+
"User",
540+
&plan.DeferResponsePlan{
541+
Response: &resolve.GraphQLResponse{
542+
Fetches: resolve.Sequence(
543+
resolve.Single(&resolve.SingleFetch{
544+
FetchConfiguration: resolve.FetchConfiguration{
545+
Input: `{"method":"POST","url":"http://first.service","body":{"query":"{user {title __typename id}}"}}`,
546+
PostProcessing: DefaultPostProcessingConfiguration,
547+
DataSource: &Source{},
548+
},
549+
DataSourceIdentifier: []byte("graphql_datasource.Source"),
550+
}),
551+
resolve.SingleWithPath(&resolve.SingleFetch{
552+
FetchDependencies: resolve.FetchDependencies{
553+
FetchID: 1,
554+
DependsOnFetchIDs: []int{0},
555+
}, FetchConfiguration: resolve.FetchConfiguration{
556+
RequiresEntityBatchFetch: false,
557+
RequiresEntityFetch: true,
558+
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename firstName}}}","variables":{"representations":[$$0$$]}}}`,
559+
DataSource: &Source{},
560+
SetTemplateOutputToNullOnVariableNull: true,
561+
Variables: []resolve.Variable{
562+
&resolve.ResolvableObjectVariable{
563+
Renderer: resolve.NewGraphQLVariableResolveRenderer(&resolve.Object{
564+
Nullable: true,
565+
Fields: []*resolve.Field{
566+
{
567+
Name: []byte("__typename"),
568+
Value: &resolve.String{
569+
Path: []string{"__typename"},
570+
},
571+
OnTypeNames: [][]byte{[]byte("User")},
572+
},
573+
{
574+
Name: []byte("id"),
575+
Value: &resolve.Scalar{
576+
Path: []string{"id"},
577+
},
578+
OnTypeNames: [][]byte{[]byte("User")},
579+
},
580+
},
581+
}),
582+
},
583+
},
584+
PostProcessing: SingleEntityPostProcessingConfiguration,
585+
},
586+
DataSourceIdentifier: []byte("graphql_datasource.Source"),
587+
}, "user", resolve.ObjectPath("user")),
588+
),
589+
Data: &resolve.Object{
590+
Fields: []*resolve.Field{
591+
{
592+
Name: []byte("user"),
593+
Value: &resolve.Object{
594+
Path: []string{"user"},
595+
Nullable: false,
596+
PossibleTypes: map[string]struct{}{
597+
"User": {},
598+
},
599+
TypeName: "User",
600+
Fields: []*resolve.Field{
601+
{
602+
Name: []byte("title"),
603+
Value: &resolve.String{
604+
Path: []string{"title"},
605+
},
606+
},
607+
{
608+
Name: []byte("firstName"),
609+
Value: &resolve.String{
610+
Path: []string{"firstName"},
611+
},
612+
},
613+
{
614+
Name: []byte("lastName"),
615+
Defer: &resolve.DeferField{
616+
DeferID: "1",
617+
},
618+
Value: &resolve.String{
619+
Path: []string{"lastName"},
620+
},
621+
},
622+
},
623+
},
624+
},
625+
},
626+
},
627+
},
628+
Defers: []*resolve.DeferGraphQLResponse{
629+
{
630+
DeferID: "1",
631+
Fetches: resolve.Sequence(
632+
resolve.SingleWithPath(&resolve.SingleFetch{
633+
FetchDependencies: resolve.FetchDependencies{
634+
FetchID: 2,
635+
DependsOnFetchIDs: []int{0},
636+
DeferID: "1",
637+
}, FetchConfiguration: resolve.FetchConfiguration{
638+
RequiresEntityBatchFetch: false,
639+
RequiresEntityFetch: true,
640+
Input: `{"method":"POST","url":"http://second.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {__typename lastName}}}","variables":{"representations":[$$0$$]}}}`,
641+
DataSource: &Source{},
642+
SetTemplateOutputToNullOnVariableNull: true,
643+
Variables: []resolve.Variable{
644+
&resolve.ResolvableObjectVariable{
645+
Renderer: resolve.NewGraphQLVariableResolveRenderer(&resolve.Object{
646+
Nullable: true,
647+
Fields: []*resolve.Field{
648+
{
649+
Name: []byte("__typename"),
650+
Value: &resolve.String{
651+
Path: []string{"__typename"},
652+
},
653+
OnTypeNames: [][]byte{[]byte("User")},
654+
},
655+
{
656+
Name: []byte("id"),
657+
Value: &resolve.Scalar{
658+
Path: []string{"id"},
659+
},
660+
OnTypeNames: [][]byte{[]byte("User")},
661+
},
662+
},
663+
}),
664+
},
665+
},
666+
PostProcessing: SingleEntityPostProcessingConfiguration,
667+
},
668+
DataSourceIdentifier: []byte("graphql_datasource.Source"),
669+
}, "user", resolve.ObjectPath("user")),
670+
),
671+
},
672+
},
673+
},
674+
planConfiguration,
429675
WithDefaultPostProcessor(),
430676
WithDefer(),
431677
WithCalculateFieldDependencies(),

v2/pkg/engine/datasourcetesting/datasourcetesting.go

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
)
2929

3030
type testOptions struct {
31-
postProcessors []*postprocess.Processor
31+
postProcessor *postprocess.Processor
3232
skipReason string
3333
withFieldInfo bool
3434
withPrintPlan bool
@@ -44,24 +44,23 @@ func WithDefer() func(*testOptions) {
4444
}
4545
}
4646

47-
func WithPostProcessors(postProcessors ...*postprocess.Processor) func(*testOptions) {
48-
return func(o *testOptions) {
49-
o.postProcessors = postProcessors
50-
}
51-
}
52-
5347
func WithSkipReason(reason string) func(*testOptions) {
5448
return func(o *testOptions) {
5549
o.skipReason = reason
5650
}
5751
}
5852

5953
func WithDefaultPostProcessor() func(*testOptions) {
60-
return WithPostProcessors(postprocess.NewProcessor(postprocess.DisableResolveInputTemplates(), postprocess.DisableCreateConcreteSingleFetchTypes(), postprocess.DisableCreateParallelNodes(), postprocess.DisableMergeFields()))
54+
return func(o *testOptions) {
55+
o.postProcessor = postprocess.NewProcessor(postprocess.DisableResolveInputTemplates(), postprocess.DisableCreateConcreteSingleFetchTypes(), postprocess.DisableCreateParallelNodes(), postprocess.DisableMergeFields())
56+
}
6157
}
6258

6359
func WithDefaultCustomPostProcessor(options ...postprocess.ProcessorOption) func(*testOptions) {
64-
return WithPostProcessors(postprocess.NewProcessor(options...))
60+
// TODO: rename to WithPostProcessor
61+
return func(o *testOptions) {
62+
o.postProcessor = postprocess.NewProcessor(options...)
63+
}
6564
}
6665

6766
func WithFieldInfo() func(*testOptions) {
@@ -244,10 +243,8 @@ func RunTestWithVariables(definition, operation, operationName, variables string
244243
t.Fatal(report.Error())
245244
}
246245

247-
if opts.postProcessors != nil {
248-
for _, processor := range opts.postProcessors {
249-
processor.Process(actualPlan)
250-
}
246+
if opts.postProcessor != nil {
247+
opts.postProcessor.Process(actualPlan)
251248
}
252249

253250
if opts.withPrintPlan {

0 commit comments

Comments
 (0)