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

Selection set for nested object with batchDelegateToSchema #4898

Open
Tracked by #5201 ...
justbaum30 opened this issue Dec 12, 2022 · 0 comments
Open
Tracked by #5201 ...

Selection set for nested object with batchDelegateToSchema #4898

justbaum30 opened this issue Dec 12, 2022 · 0 comments

Comments

@justbaum30
Copy link

justbaum30 commented Dec 12, 2022

Is your feature request related to a problem? Please describe.
Unable (or do not know how) to specify a selectionSet on a subschema when using batchDelegateToSchema (not sure about delegateToSchema yet). In my specific situation, I need to implement a custom valuesFromResults which requires a specific field to be present on the results, regardless if the client requested that field or not. I will provide an example below.

Describe the solution you'd like
On the selection set string, I was expecting to be able to select sub-objects without having to build the entire SelectionSetNode. If I did need to build the node, I was unable to find a straightforward way of dynamically building that in combination with what the client is requesting.

Describe alternatives you've considered
I looked into implementing selectionSet on batchDelegateToSchema, but it seemed pretty burdensome to have to build the full SelectionSetNode object (combining what is always required with what the client requested). It is possible there is a simple way of doing this that I was unable to locate.

Additional context

Code Sample showcasing this. Querying allPosts without requesting user.id should replicate the issue.

import { batchDelegateToSchema } from '@graphql-tools/batch-delegate';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { stitchSchemas } from '@graphql-tools/stitch';
import { OperationTypeNode } from 'graphql';

interface Post {
  id: string;
  text: string;
  userId: string;
  user: User;
}

interface User {
  id: string;
  email: string;
}

const postSchema = makeExecutableSchema({
  typeDefs: /* GraphQL */ `
    type Post {
      id: ID!
      text: String
      userId: ID!
    }

    type Query {
      allPosts: [Post]
    }
  `,
  resolvers: {
    Query: {
      allPosts() {
        return [
          {
            id: '1',
            text: 'my post 1',
            userId: 'userId1',
          },
          {
            id: '2',
            text: 'my post 2',
            userId: 'userId2',
          },
        ];
      },
    },
  },
});

const userSchema = makeExecutableSchema({
  typeDefs: /* GraphQL */ `
    type User {
      id: ID!
      email: String
    }

    type Query {
      usersByIds(ids: [ID!]!): [User]
    }
  `,
  resolvers: {
    Query: {
      usersByIds(_, args) {
        return args.ids
          .map((id: string) => {
            return {
              id: id,
              email: `${id}@email.com`,
            };
          })
          .reverse(); // Reversing so a valuesFromResults is required to implement
      },
    },
  },
});

// setup subschema config objects
const postsSubschema = { schema: postSchema };
const usersSubschema = { schema: userSchema };

export const experimentSchema = stitchSchemas({
  subschemas: [postsSubschema, usersSubschema],
  typeDefs: /* GraphQL */ `
    extend type Post {
      user: User!
    }
  `,
  resolvers: {
    Post: {
      user: {
        selectionSet: `{ userId }`, // Thought I could maybe write { userId user { id} } to force "id" to be requested
        resolve(post: Post, args, context, info) {
          return batchDelegateToSchema({
            schema: usersSubschema,
            operation: OperationTypeNode.QUERY,
            fieldName: 'usersByIds',
            key: post.userId,
            argsFromKeys: (ids) => ({ ids }),
            valuesFromResults(results: User[], keys) {
              return keys.map((key) =>
                results.find((result) => result.id === key) // "id" is required, regardless if client requests it
              );
            },
            context,
            info,
          });
        },
      },
    },
  },
});
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

1 participant