github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/example/starwars/resolvers.go (about) 1 //go:generate rm -rf generated 2 //go:generate go run ../../testdata/gqlgen.go 3 4 package starwars 5 6 import ( 7 "context" 8 "encoding/base64" 9 "errors" 10 "strconv" 11 "strings" 12 "time" 13 14 "github.com/99designs/gqlgen/example/starwars/generated" 15 16 "github.com/99designs/gqlgen/example/starwars/models" 17 ) 18 19 type Resolver struct { 20 humans map[string]models.Human 21 droid map[string]models.Droid 22 starships map[string]models.Starship 23 reviews map[models.Episode][]*models.Review 24 } 25 26 func (r *Resolver) Droid() generated.DroidResolver { 27 return &droidResolver{r} 28 } 29 30 func (r *Resolver) FriendsConnection() generated.FriendsConnectionResolver { 31 return &friendsConnectionResolver{r} 32 } 33 34 func (r *Resolver) Human() generated.HumanResolver { 35 return &humanResolver{r} 36 } 37 38 func (r *Resolver) Mutation() generated.MutationResolver { 39 return &mutationResolver{r} 40 } 41 42 func (r *Resolver) Query() generated.QueryResolver { 43 return &queryResolver{r} 44 } 45 46 func (r *Resolver) Starship() generated.StarshipResolver { 47 return &starshipResolver{r} 48 } 49 50 func (r *Resolver) resolveCharacters(ctx context.Context, ids []string) ([]models.Character, error) { 51 result := make([]models.Character, len(ids)) 52 for i, id := range ids { 53 char, err := r.Query().Character(ctx, id) 54 if err != nil { 55 return nil, err 56 } 57 result[i] = char 58 } 59 return result, nil 60 } 61 62 type droidResolver struct{ *Resolver } 63 64 func (r *droidResolver) Friends(ctx context.Context, obj *models.Droid) ([]models.Character, error) { 65 return r.resolveCharacters(ctx, obj.FriendIds) 66 } 67 68 func (r *droidResolver) FriendsConnection(ctx context.Context, obj *models.Droid, first *int, after *string) (*models.FriendsConnection, error) { 69 return r.resolveFriendConnection(ctx, obj.FriendIds, first, after) 70 } 71 72 type friendsConnectionResolver struct{ *Resolver } 73 74 func (r *Resolver) resolveFriendConnection(_ context.Context, ids []string, first *int, after *string) (*models.FriendsConnection, error) { 75 from := 0 76 if after != nil { 77 b, err := base64.StdEncoding.DecodeString(*after) 78 if err != nil { 79 return nil, err 80 } 81 i, err := strconv.Atoi(strings.TrimPrefix(string(b), "cursor")) 82 if err != nil { 83 return nil, err 84 } 85 from = i 86 } 87 88 to := len(ids) 89 if first != nil { 90 to = from + *first 91 if to > len(ids) { 92 to = len(ids) 93 } 94 } 95 96 return &models.FriendsConnection{ 97 Ids: ids, 98 From: from, 99 To: to, 100 }, nil 101 } 102 103 func (r *friendsConnectionResolver) Edges(ctx context.Context, obj *models.FriendsConnection) ([]*models.FriendsEdge, error) { 104 friends, err := r.resolveCharacters(ctx, obj.Ids) 105 if err != nil { 106 return nil, err 107 } 108 109 edges := make([]*models.FriendsEdge, obj.To-obj.From) 110 for i := range edges { 111 edges[i] = &models.FriendsEdge{ 112 Cursor: models.EncodeCursor(obj.From + i), 113 Node: friends[obj.From+i], 114 } 115 } 116 return edges, nil 117 } 118 119 func (r *friendsConnectionResolver) Friends(ctx context.Context, obj *models.FriendsConnection) ([]models.Character, error) { 120 return r.resolveCharacters(ctx, obj.Ids) 121 } 122 123 type humanResolver struct{ *Resolver } 124 125 func (r *humanResolver) Friends(ctx context.Context, obj *models.Human) ([]models.Character, error) { 126 return r.resolveCharacters(ctx, obj.FriendIds) 127 } 128 129 func (r *humanResolver) FriendsConnection(ctx context.Context, obj *models.Human, first *int, after *string) (*models.FriendsConnection, error) { 130 return r.resolveFriendConnection(ctx, obj.FriendIds, first, after) 131 } 132 133 func (r *humanResolver) Starships(ctx context.Context, obj *models.Human) ([]*models.Starship, error) { 134 var result []*models.Starship 135 for _, id := range obj.StarshipIds { 136 char, err := r.Query().Starship(ctx, id) 137 if err != nil { 138 return nil, err 139 } 140 if char != nil { 141 result = append(result, char) 142 } 143 } 144 return result, nil 145 } 146 147 type mutationResolver struct{ *Resolver } 148 149 func (r *mutationResolver) CreateReview(ctx context.Context, episode models.Episode, review models.Review) (*models.Review, error) { 150 review.Time = time.Now() 151 time.Sleep(1 * time.Second) 152 r.reviews[episode] = append(r.reviews[episode], &review) 153 return &review, nil 154 } 155 156 type queryResolver struct{ *Resolver } 157 158 func (r *queryResolver) Hero(ctx context.Context, episode *models.Episode) (models.Character, error) { 159 if *episode == models.EpisodeEmpire { 160 return r.humans["1000"], nil 161 } 162 return r.droid["2001"], nil 163 } 164 165 func (r *queryResolver) Reviews(ctx context.Context, episode models.Episode, since *time.Time) ([]*models.Review, error) { 166 if since == nil { 167 return r.reviews[episode], nil 168 } 169 170 var filtered []*models.Review 171 for _, rev := range r.reviews[episode] { 172 if rev.Time.After(*since) { 173 filtered = append(filtered, rev) 174 } 175 } 176 return filtered, nil 177 } 178 179 func (r *queryResolver) Search(ctx context.Context, text string) ([]models.SearchResult, error) { 180 var l []models.SearchResult 181 for _, h := range r.humans { 182 if strings.Contains(h.Name, text) { 183 l = append(l, h) 184 } 185 } 186 for _, d := range r.droid { 187 if strings.Contains(d.Name, text) { 188 l = append(l, d) 189 } 190 } 191 for _, s := range r.starships { 192 if strings.Contains(s.Name, text) { 193 l = append(l, s) 194 } 195 } 196 return l, nil 197 } 198 199 func (r *queryResolver) Character(ctx context.Context, id string) (models.Character, error) { 200 if h, ok := r.humans[id]; ok { 201 return &h, nil 202 } 203 if d, ok := r.droid[id]; ok { 204 return &d, nil 205 } 206 return nil, nil 207 } 208 209 func (r *queryResolver) Droid(ctx context.Context, id string) (*models.Droid, error) { 210 if d, ok := r.droid[id]; ok { 211 return &d, nil 212 } 213 return nil, nil 214 } 215 216 func (r *queryResolver) Human(ctx context.Context, id string) (*models.Human, error) { 217 if h, ok := r.humans[id]; ok { 218 return &h, nil 219 } 220 return nil, nil 221 } 222 223 func (r *queryResolver) Starship(ctx context.Context, id string) (*models.Starship, error) { 224 if s, ok := r.starships[id]; ok { 225 return &s, nil 226 } 227 return nil, nil 228 } 229 230 type starshipResolver struct{ *Resolver } 231 232 func (r *starshipResolver) Length(ctx context.Context, obj *models.Starship, unit *models.LengthUnit) (float64, error) { 233 switch *unit { 234 case models.LengthUnitMeter, "": 235 return obj.Length, nil 236 case models.LengthUnitFoot: 237 return obj.Length * 3.28084, nil 238 default: 239 return 0, errors.New("invalid unit") 240 } 241 } 242 243 func NewResolver() generated.Config { 244 r := Resolver{} 245 r.humans = map[string]models.Human{ 246 "1000": { 247 CharacterFields: models.CharacterFields{ 248 ID: "1000", 249 Name: "Luke Skywalker", 250 FriendIds: []string{"1002", "1003", "2000", "2001"}, 251 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 252 }, 253 HeightMeters: 1.72, 254 Mass: 77, 255 StarshipIds: []string{"3001", "3003"}, 256 }, 257 "1001": { 258 CharacterFields: models.CharacterFields{ 259 ID: "1001", 260 Name: "Darth Vader", 261 FriendIds: []string{"1004"}, 262 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 263 }, 264 HeightMeters: 2.02, 265 Mass: 136, 266 StarshipIds: []string{"3002"}, 267 }, 268 "1002": { 269 CharacterFields: models.CharacterFields{ 270 ID: "1002", 271 Name: "Han Solo", 272 FriendIds: []string{"1000", "1003", "2001"}, 273 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 274 }, 275 HeightMeters: 1.8, 276 Mass: 80, 277 StarshipIds: []string{"3000", "3003"}, 278 }, 279 "1003": { 280 CharacterFields: models.CharacterFields{ 281 ID: "1003", 282 Name: "Leia Organa", 283 FriendIds: []string{"1000", "1002", "2000", "2001"}, 284 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 285 }, 286 HeightMeters: 1.5, 287 Mass: 49, 288 }, 289 "1004": { 290 CharacterFields: models.CharacterFields{ 291 ID: "1004", 292 Name: "Wilhuff Tarkin", 293 FriendIds: []string{"1001"}, 294 AppearsIn: []models.Episode{models.EpisodeNewhope}, 295 }, 296 HeightMeters: 1.8, 297 Mass: 0, 298 }, 299 } 300 301 r.droid = map[string]models.Droid{ 302 "2000": { 303 CharacterFields: models.CharacterFields{ 304 ID: "2000", 305 Name: "C-3PO", 306 FriendIds: []string{"1000", "1002", "1003", "2001"}, 307 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 308 }, 309 PrimaryFunction: "Protocol", 310 }, 311 "2001": { 312 CharacterFields: models.CharacterFields{ 313 ID: "2001", 314 Name: "R2-D2", 315 FriendIds: []string{"1000", "1002", "1003"}, 316 AppearsIn: []models.Episode{models.EpisodeNewhope, models.EpisodeEmpire, models.EpisodeJedi}, 317 }, 318 PrimaryFunction: "Astromech", 319 }, 320 } 321 322 r.starships = map[string]models.Starship{ 323 "3000": { 324 ID: "3000", 325 Name: "Millennium Falcon", 326 History: [][]int{ 327 {1, 2}, 328 {4, 5}, 329 {1, 2}, 330 {3, 2}, 331 }, 332 Length: 34.37, 333 }, 334 "3001": { 335 ID: "3001", 336 Name: "X-Wing", 337 History: [][]int{ 338 {6, 4}, 339 {3, 2}, 340 {2, 3}, 341 {5, 1}, 342 }, 343 Length: 12.5, 344 }, 345 "3002": { 346 ID: "3002", 347 Name: "TIE Advanced x1", 348 History: [][]int{ 349 {3, 2}, 350 {7, 2}, 351 {6, 4}, 352 {3, 2}, 353 }, 354 Length: 9.2, 355 }, 356 "3003": { 357 ID: "3003", 358 Name: "Imperial shuttle", 359 History: [][]int{ 360 {1, 7}, 361 {3, 5}, 362 {5, 3}, 363 {7, 1}, 364 }, 365 Length: 20, 366 }, 367 } 368 369 r.reviews = map[models.Episode][]*models.Review{} 370 371 return generated.Config{ 372 Resolvers: &r, 373 } 374 }