nexus icon indicating copy to clipboard operation
nexus copied to clipboard

How to skip resolvers if fields are already there?

Open ysfaran opened this issue 2 years ago • 2 comments

I'm using nexus with prisma and was mainly orienting myself on this guide to get things done more quickly.

I will use the same example as 1:n relation section to demonstrate my question:

const User = objectType({
  name: 'User',
  definition(t) {
    t.nonNull.int('id')
    t.nonNull.string('name')
    t.nonNull.list.nonNull.field('posts', {
      type: 'Post',
      resolve: (parent, _, context) => {
        return context.prisma.user.findUnique({
          where: { id: parent.id }
        }).posts()
      }
    })
  },
})

const Post = objectType({
  name: 'Post',
  definition(t) {
    t.nonNull.int('id')
    t.nonNull.string('bio')
    t.nonNull.field('author', {
      type: 'User',
      resolve: (parent, _, context) => {
        return context.prisma.post.findUnique({
          where: { id: parent.id }
        }).author()
      }
    })
  },
})

At the beginning that example looked all fine to me, until I got to the point of deleting items from the database. For deletion of the user my first idea would be this:

const Mutation = objectType({
  name: "Mutation",
  definition(t) {
    t.field("deleteUser", {
      type: User,
      args: {
        where: arg({ type: nonNull(UserWhereUniqueInput) }),
      },
      resolve(parent, args, context) {
        // assuming that prisma cascade deletion is enabled, so all posts would also be deleted
        return context.prisma.user.delete({
           where: args.where,
           include: {
              posts: true
           }
         })
      }
    })
})

If you would call this mutation and want to get all ids of the deleted posts:

mutation {
  deleteUser(where: ...) {
    posts {
      id
    }
  }
}

it would always run into an error.

The User objectType would try to fetch its posts from the database and that would obviously result in an error since the user and its posts already got deleted. This is all happening although the resolve function of the mutation returns the deleted user and posts.

After this error I realized that everytime I want to retrieve a type after a query or mutation the type's resolve function would be triggered causing a database call every time, without me having any control about it.

So is there any way to skip a resolve and just take the value of the field if it's already there? What are alternatives?
(I'm not sure if this is even a nexus or graphql issue in general)

Any advice is greatly appreciated!

ysfaran avatar Sep 05 '21 03:09 ysfaran

I don't think its possible, it is probably how database work. Database will return deleted user only and not its relations.

nenadfilipovic avatar Oct 29 '21 14:10 nenadfilipovic

t.nonNull.list.nonNull.field('posts', {
      type: 'Post',
      resolve: (parent, _, context) => {
        return parent.posts || context.prisma.user.findUnique({
          where: { id: parent.id }
        }).posts()
      }
    })

PatrykWalach avatar Dec 08 '21 20:12 PatrykWalach