graphql-nexus / nexus-plugin-prisma

Deprecated
MIT License
828 stars 118 forks source link

Forward minimal queries via photon`select` #300

Open Weakky opened 5 years ago

Weakky commented 5 years ago

Description

At the moment, nexus-prisma v2 still always fetches all the scalars by default on the generated resolvers, and then the relations on the children resolvers.

For performance reasons, we could now use the photon select API to only fetch what's in the incoming queries.

However, we need some concept like SDL-first used to have, called fragment resolvers (https://www.apollographql.com/docs/apollo-server/features/schema-stitching/#adding-resolvers-between-schemas) in order to make that working.

Fragment resolvers allowed to define the requirements of a resolver, making sure that even though a field was not fetched by the user, if a child resolver needed it, we'd still fetch it so that the data could properly be resolved.

Example

Given the following schema:

type Query {
  user: User
}

type User {
  id: ID!
  firstName: String!
  lastName: String!
}

And the following resolver for the fullName resolver:

(root) => root.firstName + " " + root.lastName

If a user only fetches fullName, we need to make sure that firstName and lastName are fetched anyway to fulfill the requirements of the fullName resolver.

Hints

We're currently thinking of a new feature in nexus to be able to collocate the backingTypes of a type or a field next to it. Please read the following issue to learn more about it: #302

While we're still not sure of the final api, it could look like:

objectType({
  name: 'SomeType',
  definition(t) {
    t.field('someField', {
      type: 'SomeType',
      backingType: '{ id: string, name: string }',
      resolver: root => root.id + " " + root.name
    })
  }
})

// Alternatively
objectType({
  name: 'SomeType',
  definition(t) {
    t.field('someField', {
      type: 'SomeType',
      resolver: root => root.id + " " + root.name
    })
    t.model.addBackingType('{ id: string, name: string }')
  }
})

That backingType API would be responsible for giving nexus more information about the root types TS typings, by additively adding/merging them to what nexus can already infer (currently, nexus infer root types by only taking the ones that have no resolver, assuming that if a field has no resolver, it means the parent is supposed to pass it down).

The point is, that backingType API could also be used to get information on the requirements of a field, thus allowing us to smartly fetch only the required fields.

jasonkuhrt commented 5 years ago

At the moment, nexus-prisma v2 still always fetches all the [...], and then the relations on the children resolvers.

What does that second part mean exactly?

The point is, that backingType API could also be used to get information on the requirements of a field, thus allowing us to smartly fetch only the required fields.

Trying to understand. Could you show for example how your given Example could be resolved by this?

In your example fullName field is derived from combination of firstName and lastName. As you say:

If a user only fetches fullName, we need to make sure that firstName and lastName are fetched anyway to fulfill the requirements of the fullName resolver.

Now, this dependency is only implied in the system, not captured for observation by other components like nexus-prisma. So, then, how is nexus-prisma to know that it must specifically include firstName lastName select to photon when fullName is included in GQL user query? How does nexus-prisma having access to a backing type provide a solution here?