How to make gqlgen dataloader Loader.Load(key) return a function that returns an explicit data type instead of interface{}?

huangapple go评论109阅读模式
英文:

How to make gqlgen dataloader Loader.Load(key) return a function that returns an explicit data type instead of interface{}?

问题

我想使用graph-gophers/dataloader来实现一个用于批量获取用户的数据加载器。

我已经按照以下方式实现了它,但是我需要返回一个明确的数据类型,而不是interface{}

首先,我使用给定的dataloader.Keys通过函数GetUsers创建了UserReader

  1. type UserReader struct {
  2. userCtrl user.Controller // 这是我的用户服务,用于创建、获取和删除用户
  3. }
  4. func newUserReader(userCtrl user.Controller) UserReader {
  5. return UserReader{
  6. userCtrl: userCtrl,
  7. }
  8. }
  9. // GetUsers根据给定的键返回结果列表
  10. func (reader UserReader) GetUsers(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
  11. output := make([]*dataloader.Result, len(keys))
  12. for i, key := range keys {
  13. userID := key.String()
  14. // 根据字符串userID获取用户列表
  15. result, err := reader.userCtrl.GetUsers(ctx, userID)
  16. output[i] = &dataloader.Result{Data: result, Error: err}
  17. }
  18. return output
  19. }

然后,我使用函数GetUser创建了一个Loader,通过userID获取一个用户,它不会在单个请求中多次请求userCtrl的数据。

  1. type Loader struct {
  2. userLoader *dataloader.Loader
  3. }
  4. func newLoader(userCtrl user.Controller) Loader {
  5. userReader := newUserReader(userCtrl)
  6. return Loader{
  7. // 使用批处理函数创建新的用户加载器
  8. userLoader: dataloader.NewBatchedLoader(userReader.GetUsers),
  9. }
  10. }
  11. // UserLoader返回用户加载器
  12. func (loader Loader) UserLoader() *dataloader.Loader {
  13. return loader.userLoader
  14. }
  15. // GetUser根据给定的参数返回一个用户
  16. func (loader impl) GetUser(ctx context.Context, userID string) (model.User, error) {
  17. // FromCtx从上下文中获取加载器(如果存在),否则返回nil。
  18. ctxLoader := FromCtx(ctx)
  19. // Thunk是带有interface{}类型和错误的函数返回值
  20. thunk := ctxLoader.UserLoader().Load(ctx, dataloader.StringKey(userID))
  21. result, err := thunk()
  22. if err != nil {
  23. return nil, err
  24. }
  25. return result.(model.User), nil // 在这里转换数据类型!!!
  26. }

最后,可以这样使用:

  1. dataloader.FromCtx(ctx).GetUser(ctx, userID)

但是我希望userReader.getUsers返回一个包含model.user的对象,而不是interface{},因为我不想在Loader.getUser函数中进行数据类型转换。

有没有办法让dataloader.Result返回特定的数据类型,而不是interface{}

英文:

I want to use graph-gophers/dataloader to implement a dataloader for bulk-fetching users.

I have implemented it like below but I need to return an explicit data type, not an interface{}

Firstly, I create UserReader with function GetUsers by given dataloader.Keys:

  1. type UserReader struct {
  2. userCtrl user.Controller // This is my user service for Create, Get, Delete user
  3. }
  4. func newUserReader(userCtrl user.Controller) UserReader {
  5. return UserReader{
  6. userCtrl: userCtrl,
  7. }
  8. }
  9. // GetUsers return a list of result by given keys
  10. func (reader UserReader) GetUsers(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
  11. output := make([]*dataloader.Result, len(keys))
  12. for i, key := range keys {
  13. userID := key.String()
  14. // Get list of user by string userID
  15. result, err := reader.userCtrl.GetUsers(ctx, userID)
  16. output[i] = &dataloader.Result{Data: result, Error: err}
  17. }
  18. return output
  19. }

And then, I create a Loader with function GetUser to get a user by userID, it won't request data from userCtrl more than 1 time in a single request.

  1. type Loader struct {
  2. userLoader *dataloader.Loader
  3. }
  4. func newLoader(userCtrl user.Controller) Loader {
  5. userReader := newUserReader(userCtrl)
  6. return Loader{
  7. // Create new user loader with batch function
  8. userLoader: dataloader.NewBatchedLoader(userReader.GetUsers),
  9. }
  10. }
  11. // UserLoader returns the user loader
  12. func (loader Loader) UserLoader() *dataloader.Loader {
  13. return loader.userLoader
  14. }
  15. // GetUser return a user by given parameter
  16. func (loader impl) GetUser(ctx context.Context, userID string) (model.User, error) {
  17. // FromCtx gets a Loader from context if it exists, else nil.
  18. ctxLoader := FromCtx(ctx)
  19. // Thunk is function return value with interface{} type and error
  20. thunk := ctxLoader.UserLoader().Load(ctx, dataloader.StringKey(userID))
  21. result, err := thunk()
  22. if err != nil {
  23. return nil, err
  24. }
  25. return result.(model.User), nil // Convert datatype here!!!
  26. }

And finally, It can be use

  1. dataloader.FromCtx(ctx).GetUser(ctx, userID)

But I need userReader.getUsers to return an object containing model.user not interface{} because I don't want to convert the data type in the Loader.getUser function.

Is there a way to have dataloader.Result return a certain data type instead of the interface{}?

答案1

得分: 2

graph-gophers/dataloaderv7版本支持泛型。具体来说,BatchFunc签名已经改变,因此您可以指定结果类型。

英文:

The v7 version of graph-gophers/dataloader supports generics. Specifically, the BatchFunc signature has changed so you can specify the resulting type.

huangapple
  • 本文由 发表于 2022年8月22日 19:50:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/73444645.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定