Skip to content
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

Prisma connection resolves nodes even when querying only totalCount #989

Closed
julioxavierr opened this issue Aug 18, 2023 · 7 comments
Closed

Comments

@julioxavierr
Copy link
Contributor

The Prisma plugin enables using a prismaConnection with a totalCount function for loading the total count for the connection. This works great and is useful for containing all info for a relation within the same connection.

However, I recently noticed that even when only querying the totalCount for the connection, it still executes the resolver that fetches the edges. And I was wondering if it was possible to avoid that and only execute the totalCount resolver.

Following, there is an example based on my current code and an example query. Looking forward to get others thoughts and also open to contribute with a PR.

builder.prismaObjectField("Account", "measures", (t) =>
  t.prismaConnection({
    type: Measure,
    cursor: "id",
    totalCount: async (source, args) => {
      console.log("🚀 Executed totalCount resolver")
      return prismaClient.measures.count();
    },
    resolve: async (query, source, args) => {
      console.log("🚀 Executed connection resolver")
      return prismaClient.measures.findMany({
        orderBy: { date: { sort: "desc", nulls: "last" } },
        ...query,
      });
    },
  }),
);
query {
   account(id: "some-id") {
      measures {
         totalCount # should only execute this resolver
      }
   }
}
@hayes
Copy link
Owner

hayes commented Aug 21, 2023

this is a bit tricky, as there are many potential ways that optimizing this could inadvertently break things. A simple example would be adding additional fields or auth checks to the connection object. Similarly if you have a nodes field on the context object, or request anything in pageInfo. In either case, you end up calling functions that get passed the connection results. I think it would be reasonable to special case the situation where totalCount is the only thing selected, but if any other field is selected, the resolver will likely be expecting the full connection result object as the parent value.

Definitely open to a PR for this. This would likely just be implemented by checking for what fields are selected using the info argument, and if the sub-selection is only totalCount just returning early with an empty object or something.

@hayes
Copy link
Owner

hayes commented Sep 22, 2023

thanks for fixing this!

@julioxavierr
Copy link
Contributor Author

@hayes I just noticed that this introduced a regression for a specific use case

  • A connection is queried differently at the same time, using the field directly in the type and using a fragment that has a union (does not happen if the fragment does not use a union)
query AppQuery {
  user {
    files {
      totalCount
    }
    ...App_node
  }
}

fragment App_node on Node {
  ... on User {
    id
    files {
      edges {
        node {
          name
          size
        }
      }
    }
  }
}

@hayes
Copy link
Owner

hayes commented Oct 3, 2023

this is an interesting combination of things I think.

I think this was more of a case of uncovering/worsening a previous bug. I suspect that these fragments on an abstract type never worked correctly, but would work previously for 1 of 2 reasons:

  • the selection from totalCount would select the relation properly
  • the relation was marked as not selected, because it was never included, and it would automatically try to load it via a separate query

either way, the query would resolve correctly (but maybe not efficiently). Now we are probably incorrectly marking the relation as loaded, causing the query to fail. Should be fixable, but will take some debugging
*

@julioxavierr
Copy link
Contributor Author

julioxavierr commented Oct 3, 2023

@hayes shall we reopen this or create a new issue for it?

@hayes
Copy link
Owner

hayes commented Oct 3, 2023

Probably should be a new issue

@hayes
Copy link
Owner

hayes commented Oct 3, 2023

There are a few places throughout the query mapping like https://github.com/hayes/pothos/blob/main/packages/plugin-prisma/src/util/map-query.ts#L171 where we check that the fragment for the expected type. I think this breaks cases where you use a fragment for an abstract type, and then select the concrete type inside.

I think the check for only total count looks at info.fieldNodes[0] and probably needs to account for all nodes instead

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

No branches or pull requests

2 participants