github.com/99designs/gqlgen@v0.17.45/plugin/federation/federation.gotpl (about) 1 {{ reserveImport "context" }} 2 {{ reserveImport "errors" }} 3 {{ reserveImport "fmt" }} 4 {{ reserveImport "strings" }} 5 {{ reserveImport "sync" }} 6 7 {{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }} 8 {{ $options := .PackageOptions }} 9 {{ $usePointers := .UsePointers }} 10 11 var ( 12 ErrUnknownType = errors.New("unknown type") 13 ErrTypeNotFound = errors.New("type not found") 14 ) 15 16 func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { 17 if ec.DisableIntrospection { 18 return fedruntime.Service{}, errors.New("federated introspection disabled") 19 } 20 21 var sdl []string 22 23 for _, src := range sources { 24 if src.BuiltIn { 25 continue 26 } 27 sdl = append(sdl, src.Input) 28 } 29 30 return fedruntime.Service{ 31 SDL: strings.Join(sdl, "\n"), 32 }, nil 33 } 34 35 {{if .Entities}} 36 func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity { 37 list := make([]fedruntime.Entity, len(representations)) 38 39 repsMap := map[string]struct { 40 i []int 41 r []map[string]interface{} 42 }{} 43 44 // We group entities by typename so that we can parallelize their resolution. 45 // This is particularly helpful when there are entity groups in multi mode. 46 buildRepresentationGroups := func(reps []map[string]interface{}) { 47 for i, rep := range reps { 48 typeName, ok := rep["__typename"].(string) 49 if !ok { 50 // If there is no __typename, we just skip the representation; 51 // we just won't be resolving these unknown types. 52 ec.Error(ctx, errors.New("__typename must be an existing string")) 53 continue 54 } 55 56 _r := repsMap[typeName] 57 _r.i = append(_r.i, i) 58 _r.r = append(_r.r, rep) 59 repsMap[typeName] = _r 60 } 61 } 62 63 isMulti := func(typeName string) bool { 64 switch typeName { 65 {{- range .Entities -}} 66 {{- if .Resolvers -}} 67 {{- if .Multi -}} 68 case "{{.Def.Name}}": 69 return true 70 {{ end }} 71 {{- end -}} 72 {{- end -}} 73 default: 74 return false 75 } 76 } 77 78 resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) { 79 // we need to do our own panic handling, because we may be called in a 80 // goroutine, where the usual panic handling can't catch us 81 defer func () { 82 if r := recover(); r != nil { 83 err = ec.Recover(ctx, r) 84 } 85 }() 86 87 switch typeName { 88 {{ range $_, $entity := .Entities }} 89 {{- if and .Resolvers (not .Multi) -}} 90 case "{{.Def.Name}}": 91 resolverName, err := entityResolverNameFor{{.Def.Name}}(ctx, rep) 92 if err != nil { 93 return fmt.Errorf(`finding resolver for Entity "{{.Def.Name}}": %w`, err) 94 } 95 switch resolverName { 96 {{ range $i, $resolver := .Resolvers }} 97 case "{{.ResolverName}}": 98 {{- range $j, $keyField := .KeyFields }} 99 id{{$j}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"]) 100 if err != nil { 101 return fmt.Errorf(`unmarshalling param {{$j}} for {{$resolver.ResolverName}}(): %w`, err) 102 } 103 {{- end}} 104 entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, {{- range $j, $_ := .KeyFields -}} id{{$j}}, {{end}}) 105 if err != nil { 106 return fmt.Errorf(`resolving Entity "{{$entity.Def.Name}}": %w`, err) 107 } 108 {{ if and (index $options "explicit_requires") $entity.Requires }} 109 err = ec.Populate{{$entity.Def.Name}}Requires(ctx, {{- if (not $usePointers) -}}&{{- end -}}entity, rep) 110 if err != nil { 111 return fmt.Errorf(`populating requires for Entity "{{$entity.Def.Name}}": %w`, err) 112 } 113 {{- else }} 114 {{ range $entity.Requires }} 115 entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"]) 116 if err != nil { 117 return err 118 } 119 {{- end }} 120 {{- end }} 121 list[idx[i]] = entity 122 return nil 123 {{- end }} 124 } 125 {{ end }} 126 {{- end }} 127 } 128 return fmt.Errorf("%w: %s", ErrUnknownType, typeName) 129 } 130 131 resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) { 132 // we need to do our own panic handling, because we may be called in a 133 // goroutine, where the usual panic handling can't catch us 134 defer func () { 135 if r := recover(); r != nil { 136 err = ec.Recover(ctx, r) 137 } 138 }() 139 140 switch typeName { 141 {{ range $_, $entity := .Entities }} 142 {{ if and .Resolvers .Multi -}} 143 case "{{.Def.Name}}": 144 resolverName, err := entityResolverNameFor{{.Def.Name}}(ctx, reps[0]) 145 if err != nil { 146 return fmt.Errorf(`finding resolver for Entity "{{.Def.Name}}": %w`, err) 147 } 148 switch resolverName { 149 {{ range $i, $resolver := .Resolvers }} 150 case "{{.ResolverName}}": 151 _reps := make([]*{{.LookupInputType}}, len(reps)) 152 153 for i, rep := range reps { 154 {{ range $i, $keyField := .KeyFields -}} 155 id{{$i}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"]) 156 if err != nil { 157 return errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{.Definition.Name}}")) 158 } 159 {{end}} 160 161 _reps[i] = &{{.LookupInputType}} { 162 {{ range $i, $keyField := .KeyFields -}} 163 {{$keyField.Field.ToGo}}: id{{$i}}, 164 {{end}} 165 } 166 } 167 168 entities, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, _reps) 169 if err != nil { 170 return err 171 } 172 173 for i, entity := range entities { 174 {{- range $entity.Requires }} 175 entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, reps[i]["{{.Field.Join `"].(map[string]interface{})["`}}"]) 176 if err != nil { 177 return err 178 } 179 {{- end}} 180 list[idx[i]] = entity 181 } 182 return nil 183 {{ end }} 184 default: 185 return fmt.Errorf("unknown resolver: %s", resolverName) 186 } 187 {{ end }} 188 {{- end }} 189 default: 190 return errors.New("unknown type: "+typeName) 191 } 192 } 193 194 resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) { 195 if isMulti(typeName) { 196 err := resolveManyEntities(ctx, typeName, reps, idx) 197 if err != nil { 198 ec.Error(ctx, err) 199 } 200 } else { 201 // if there are multiple entities to resolve, parallelize (similar to 202 // graphql.FieldSet.Dispatch) 203 var e sync.WaitGroup 204 e.Add(len(reps)) 205 for i, rep := range reps { 206 i, rep := i, rep 207 go func(i int, rep map[string]interface{}) { 208 err := resolveEntity(ctx, typeName, rep, idx, i) 209 if err != nil { 210 ec.Error(ctx, err) 211 } 212 e.Done() 213 }(i, rep) 214 } 215 e.Wait() 216 } 217 } 218 buildRepresentationGroups(representations) 219 220 switch len(repsMap) { 221 case 0: 222 return list 223 case 1: 224 for typeName, reps := range repsMap { 225 resolveEntityGroup(typeName, reps.r, reps.i) 226 } 227 return list 228 default: 229 var g sync.WaitGroup 230 g.Add(len(repsMap)) 231 for typeName, reps := range repsMap { 232 go func(typeName string, reps []map[string]interface{}, idx []int) { 233 resolveEntityGroup(typeName, reps, idx) 234 g.Done() 235 }(typeName, reps.r, reps.i) 236 } 237 g.Wait() 238 return list 239 } 240 } 241 242 {{- /* Make sure the required fields are in the given entity representation and return the name of the proper resolver. */ -}} 243 244 {{ range $_, $entity := .Entities }} 245 {{- if .Resolvers }} 246 247 func entityResolverNameFor{{$entity.Name}}(ctx context.Context, rep map[string]interface{}) (string, error) { 248 {{- range .Resolvers }} 249 for { 250 var ( 251 m map[string]interface{} 252 val interface{} 253 ok bool 254 ) 255 _ = val 256 {{- range $_, $keyField := .KeyFields }} 257 m = rep 258 {{- range $i, $field := .Field }} 259 if {{ if (ne $i $keyField.Field.LastIndex ) -}}val{{- else -}}_{{- end -}}, ok = m["{{.}}"]; !ok { 260 break 261 } 262 {{- if (ne $i $keyField.Field.LastIndex ) }} 263 if m, ok = val.(map[string]interface{}); !ok { 264 break 265 } 266 {{- end}} 267 {{- end}} 268 {{- end }} 269 return "{{.ResolverName}}", nil 270 } 271 {{- end }} 272 return "", fmt.Errorf("%w for {{$entity.Name}}", ErrTypeNotFound) 273 } 274 {{- end }} 275 {{- end }} 276 277 {{end}}