-
Notifications
You must be signed in to change notification settings - Fork 0
/
builder.go
154 lines (115 loc) · 3.4 KB
/
builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package grapher
import (
"encoding/json"
"github.com/graphql-go/graphql"
"reflect"
)
type ResolverFn[argT any, outT any] func(p graphql.ResolveParams, arg argT) (outT, error)
type ResolverMiddlewareFn func(nextFn graphql.FieldResolveFn) graphql.FieldResolveFn
type ArgValidatorFn func(arg any) (err error)
type NoArgs struct{}
type FieldBuilderConfig struct {
Translator Translator
ArgValidator ArgValidatorFn
Middlewares []ResolverMiddlewareFn
}
// FieldBuilder interface, put NoArgs to use no args
type FieldBuilder[argT any, outT any] interface {
WithDescription(desc string) FieldBuilder[argT, outT]
WithResolver(resolverFunc ResolverFn[argT, outT]) FieldBuilder[argT, outT]
WithCustomArgValidator(fn ArgValidatorFn) FieldBuilder[argT, outT]
Build() (field *graphql.Field, err error)
MustBuild() *graphql.Field
AddMiddleware(middlewareFn ResolverMiddlewareFn) FieldBuilder[argT, outT]
}
type fieldBuilder[argT any, outT any] struct {
desc string
resolver ResolverFn[argT, outT]
argValidator ArgValidatorFn
translator Translator
middlewares []ResolverMiddlewareFn
}
func (f *fieldBuilder[argT, outT]) WithDescription(desc string) FieldBuilder[argT, outT] {
f.desc = desc
return f
}
func (f *fieldBuilder[argT, outT]) WithResolver(resolverFunc ResolverFn[argT, outT]) FieldBuilder[argT, outT] {
f.resolver = resolverFunc
return f
}
func (f *fieldBuilder[argT, outT]) WithCustomArgValidator(fn ArgValidatorFn) FieldBuilder[argT, outT] {
f.argValidator = fn
return f
}
func (f *fieldBuilder[argT, outT]) Build() (field *graphql.Field, err error) {
field = &graphql.Field{}
field.Description = f.desc
useArgs := !isGrapherNoArgs[argT]()
if useArgs {
fieldArgT, argErr := f.translator.TranslateArgs(new(argT))
if argErr != nil {
err = argErr
return
}
field.Args = fieldArgT
}
fieldOutT, _ := f.translator.Translate(new(outT))
//if err != nil {
// return
//}
field.Resolve = f.createResolver(useArgs)
field.Type = fieldOutT
return
}
func (f *fieldBuilder[argT, outT]) AddMiddleware(middlewareFn ResolverMiddlewareFn) FieldBuilder[argT, outT] {
f.middlewares = append(f.middlewares, middlewareFn)
return f
}
func (f *fieldBuilder[argT, outT]) MustBuild() *graphql.Field {
ret, err := f.Build()
if err != nil {
panic(err)
}
return ret
}
func NewFieldBuilder[argT any, outT any](cfgArgs ...FieldBuilderConfig) FieldBuilder[argT, outT] {
if len(cfgArgs) != 0 {
if cfgArgs[0].Translator != nil {
return &fieldBuilder[argT, outT]{
translator: cfgArgs[0].Translator,
argValidator: cfgArgs[0].ArgValidator,
middlewares: cfgArgs[0].Middlewares,
}
}
}
return &fieldBuilder[argT, outT]{
translator: NewTranslator(),
}
}
func isGrapherNoArgs[T any]() bool {
return reflect.TypeOf(new(T)).String() == "*grapher.NoArgs"
}
func (f *fieldBuilder[argT, outT]) createResolver(useArgs bool) func(p graphql.ResolveParams) (res interface{}, err error) {
lastFn := func(p graphql.ResolveParams) (res interface{}, err error) {
args := new(argT)
if !useArgs {
return f.resolver(p, *args)
}
r, _ := json.Marshal(p.Args)
json.Unmarshal(r, &args)
if f.argValidator != nil {
if err = f.argValidator(args); err != nil {
return
}
}
return f.resolver(p, *args)
}
if len(f.middlewares) == 0 {
return lastFn
}
endFn := f.middlewares[0](lastFn)
for i := 1; i < len(f.middlewares); i++ {
endFn = f.middlewares[i](endFn)
}
return endFn
}