Skip to content

[Feature requests]Allow resolve function returns a custom deferred object in order to do decent query optimization. #1416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
JimChengLin opened this issue Jul 12, 2018 · 2 comments
Labels

Comments

@JimChengLin
Copy link

I have read #26 , #700 and #304 . It seems like there is no well-agreed way to combine GraphQL and database. GraphQL.js loses a certain amount of chances to do query optimization. Am I right? I have a simple proposal. In the resolve function, we can return a DeferredObject instead of a normal JS object or Promise. Only in the very last moment, the deferred object queries the DB. Does this make sense?

The special DeferredObjects links with each other. So the minimal query fields needed can be detected. GraphQL.js may finally call await someDeferredObject.excute() multiple times. Since we have ES6 getter and setter. I think it may be quite seamless to current code base.

@IvanGoncharov
Copy link
Member

@JimChengLin Problem is that graphql-js needs some runtime information in order to call correct resolvers. For example, if you use interfaces or unions than without knowing the actual type of every object you can't decide what resolvers you should call:

{
  hero {
    name
    ... on Human {
      homePlanet
    }
    ... on Droid {
      primaryFunction
    }
  }
}

Moreover, in the case of arrays, you need to know the exact size of array and type of every item.

Taking the above limitations into account I don't think we could achieve any significant speedup from using proxy objects.

@JimChengLin
Copy link
Author

JimChengLin commented Jul 16, 2018

@IvanGoncharov
The type can be known from some meta attributes. My proposal is simply "lazy-evaluation". When you really need it, you can still call await someDerferredObject.execute(). It wouldn't harm anything.

Example taking from https://github.com/iamshaunjp/graphql-playlist,

const BookType = new GraphQLObjectType({
    name: 'Book',
    fields: ( ) => ({
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        genre: { type: GraphQLString },
        author: {
            type: AuthorType,
            resolve(parent, args){
                console.log(parent);
                return _.find(authors, { id: parent.authorId });
            }
        }
    })
});

In the resolve function of AuthorType, why do we need to know everything of the parent? Ideally, if parent is a deferred object, we can chain deferred operators.

Someone may call return parent.some_defferred_operators(xxx) that produces another deferred object. You follow with me? In the last stage, the author of the deferred object library like me has a full view of what data is needed, then we can have a single very efficient SQL query.

I don't expect the transformation would be really difficult, cuz query is generally Read-Only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants