roneli / fastgql

Blazing fast, instant realtime & extendable GraphQL APIs powered by gqlgen
https://www.fastgql.io/
MIT License
31 stars 4 forks source link

Is it a waste when we scan from db into struct? #23

Closed namnm closed 2 years ago

namnm commented 2 years ago

Can we modify/config gqlgen to just return interface{} instead?

var data []*model.User
if err := pgxscan.ScanAll(&data, rows); err != nil {
  return nil, err
}

Here from the example, we need to marshal the whole list of User struct, even if the request only ask for id/name. If this can just return interface{} then we dont need to marshal, only raw data from db it can be more optimal?

roneli commented 2 years ago

In theory yes, but because the SDL expects a User model the gqlgen signature must be of type []*model.User. I am not sure if changing the signature on the resolver end will work with gqlgen since its main appeal is the types rather than working with interface{}.

I can give it a small research and play with it, but I am not sure if this optimization is worthwhile. The idea around the resolver functions is that you can change it and regenerate and it will keep your original implementation so you manipulate the data more after you resolved it from the DB, and its much nicer to work with types rather than interface{}

namnm commented 2 years ago

@roneli I think we can ask for API change like:

opCtx := graphql.GetOperationContext(ctx)
opCtx.SetRawResponse(data) // data can be interface{} raw data from db without marshal waste
return nil, nil // no need to return data here as it has been set in raw response, the code will compile well

Then when execute the operation, it can check if it has raw response then use it to return json. With this API change, it still works if you need to marshal data

PS: I found a way to do that but may need to fork and change some lines in the gqlgen lib:

graphql.GetFieldContext(ctx).Result = data
roneli commented 2 years ago

That looks cool, although I am against a fork, since we need to update against upstream changes always and maintain it.

Another caveat which makes me prefer the typed version, is if you have children logical resolvers, it won't work since they would require a u *model.User for the child resolver.

namnm commented 2 years ago

Yeah you are right. Btw do you know the lib join-monster on nodejs? It has the same idea with your lib, which turns graphql field selection into sql query. I think we can learn some from it to apply to your lib