vektah / dataloaden

go generate based DataLoader
MIT License
528 stars 79 forks source link

How to order slice of pointers using gqlgen and dataloaden if some keys are NULL? #49

Open frederikhors opened 4 years ago

frederikhors commented 4 years ago

I have these entities:

type Player struct {
    ID        int
    CreatedAt time.Time
    City      City
    CityID    int
    Team      *Team
    TeamID    *int
    Score     int
}
type Player {
  id: ID!
  createdAt: Time!
  City: City!
  Team: Team
  Score: Int!
}

As you can see:

  1. City is mandatory

  2. Team (and TeamID in Golang struct) is NOT mandatory, so I'm using a pointer type (*)

What I don't understand now is how to use dataloaden (a GraphQL dataloader).

Here the generated code for CityById loader, generated with: go run github.com/vektah/dataloaden CityByIdLoader int *my_project/entities.City:

CityById: CityByIdLoader{
  maxBatch: 100,
  wait:     1 * time.Millisecond,
  fetch: func(keys []int) ([]*entities.City, []error) {
    cities, err := myRepo.CitiesByKeys(keys)
    // directly ordered in DB based on keys` order: it works
    return cities, []error{err}
  },
},

What about []*int for TeamID?

Here's the generated code for TeamById loader, generated with: go run github.com/vektah/dataloaden TeamByIdLoader *int *my_project/entities.Team:

TeamById: TeamByIdLoader{
  maxBatch: 100,
  wait:     1 * time.Millisecond,
  fetch: func(keys []int) ([]*entities.Team, []error) {
    teams, err := myRepo.TeamsByKeys(keys)
    // I cannot order in DB because of `NULL` keys, right?
    // How to order these results?
    return teams, []error{err}
  },
},

I don't understand how to re-order teams by keys if I cannot do it in DB because of NULL values in keys.

MaxInertia commented 4 years ago

@frederikhors If I understand correctly, the simplest solution would be to only use the TeamByIdLoader when Player.teamID is defined.

So your player resolver for the field Team would look like this:

func (r *playerResolver) Team(ctx context.Context, obj *entities.Player) (*entities.Team, error) {
    if obj == nil || obj.TeamID == nil {
        return nil, nil
    }
    return dataloader.For(ctx).TeamById.Load(obj.TeamID)
}