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

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

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

type UserReader struct {
	userCtrl user.Controller // 这是我的用户服务,用于创建、获取和删除用户
}

func newUserReader(userCtrl user.Controller) UserReader {
	return UserReader{
		userCtrl: userCtrl,
	}
}

// GetUsers根据给定的键返回结果列表
func (reader UserReader) GetUsers(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
	output := make([]*dataloader.Result, len(keys))
	for i, key := range keys {
		userID := key.String()
        
        // 根据字符串userID获取用户列表
		result, err := reader.userCtrl.GetUsers(ctx, userID)
		output[i] = &dataloader.Result{Data: result, Error: err}
	}

	return output
}

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

type Loader struct {
	userLoader *dataloader.Loader
}

func newLoader(userCtrl user.Controller) Loader {
	userReader := newUserReader(userCtrl)
	return Loader{
        // 使用批处理函数创建新的用户加载器
		userLoader: dataloader.NewBatchedLoader(userReader.GetUsers),
	}
}

// UserLoader返回用户加载器
func (loader Loader) UserLoader() *dataloader.Loader {
	return loader.userLoader
}

// GetUser根据给定的参数返回一个用户
func (loader impl) GetUser(ctx context.Context, userID string) (model.User, error) {
	// FromCtx从上下文中获取加载器(如果存在),否则返回nil。
    ctxLoader := FromCtx(ctx)
    
    // Thunk是带有interface{}类型和错误的函数返回值
	thunk := ctxLoader.UserLoader().Load(ctx, dataloader.StringKey(userID))
	result, err := thunk()
	if err != nil {
		return nil, err
	}
	return result.(model.User), nil // 在这里转换数据类型!!!
}

最后,可以这样使用:

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:

type UserReader struct {
	userCtrl user.Controller // This is my user service for Create, Get, Delete user
}

func newUserReader(userCtrl user.Controller) UserReader {
	return UserReader{
		userCtrl: userCtrl,
	}
}

// GetUsers return a list of result by given keys
func (reader UserReader) GetUsers(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
	output := make([]*dataloader.Result, len(keys))
	for i, key := range keys {
		userID := key.String()
        
        // Get list of user by string userID
		result, err := reader.userCtrl.GetUsers(ctx, userID)
		output[i] = &dataloader.Result{Data: result, Error: err}
	}

	return output
}

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.

type Loader struct {
	userLoader *dataloader.Loader
}

func newLoader(userCtrl user.Controller) Loader {
	userReader := newUserReader(userCtrl)
	return Loader{
        // Create new user loader with batch function
		userLoader: dataloader.NewBatchedLoader(userReader.GetUsers),
	}
}

// UserLoader returns the user loader
func (loader Loader) UserLoader() *dataloader.Loader {
	return loader.userLoader
}

// GetUser return a user by given parameter
func (loader impl) GetUser(ctx context.Context, userID string) (model.User, error) {
	// FromCtx gets a Loader from context if it exists, else nil.
    ctxLoader := FromCtx(ctx)
    
    // Thunk is function return value with interface{} type and error
	thunk := ctxLoader.UserLoader().Load(ctx, dataloader.StringKey(userID))
	result, err := thunk()
	if err != nil {
		return nil, err
	}
	return result.(model.User), nil // Convert datatype here!!!
}

And finally, It can be use

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:

确定