ardatan / ardatan/graphql-tools

Selection set for nested object with batchDelegateToSchema

Open
#4,898 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
5.4k
Forks
830
Avg merge
10h 59m
Merged PRs (30d)
45

Description

**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.
```typescript
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,
});
},
},
},
},
});

```

Contributor guide

Open the contributing guide

Research direction

Start with batchDelegateToSchema and the Post.user resolver shown in the example; compare how selectionSet and valuesFromResults are handled. Determine how a nested selection-set string could combine required fields with the client selection. Done should ensure User.id is present for valuesFromResults while preserving the requested User fields and correctly mapping the reversed usersByIds results.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.