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

Multiple @key directives not supported when type is extended #4739

Open
Tracked by #8296 ...
Micahnator opened this issue Sep 14, 2020 · 2 comments
Open
Tracked by #8296 ...

Multiple @key directives not supported when type is extended #4739

Micahnator opened this issue Sep 14, 2020 · 2 comments
Labels
core Related to codegen core/cli plugins

Comments

@Micahnator
Copy link

Describe the bug
When a graphql type definition has multiple @key directives (as in for Apollo Federation) AND that same type is extended elsewhere in the same schema being parsed by by the code generator, only the last directive is included in the output. I'm seeing this in both the schema-ast and typescript-resolvers plugin outputs.

To Reproduce
Steps to reproduce the behavior: Apply multiple @key directives to a type and elsewhere in the schema add fields to the type using the extend keyword. Use the schema-ast plugin to generate a parsed version of the schema and observe that only the last @key directive is in the output file. Make sure to configure both the 'federation' and 'includeDirectives' options configured to 'true'.

I've setup a codesandbox where this can be observed: https://codesandbox.io/s/zen-boyd-t8dls
Note: You can see all the directives successfully being included by commenting out the part of the schema that adds the 'phone' field to the User.

  1. My GraphQL schema:
type Query {
    user(id: ID!): User!
}

type User @key(fields: "id") @key(fields: "username") @key(fields: "email") {
    id: ID!
    username: String!
    email: String!
}

extend type User {
    phone: String!
}
  1. My GraphQL operations:
    N/A

  2. My codegen.yml config file:

# From the codesandbox linked above
schema: schema.graphql
documents: document.graphql
generates:
  types.ts:
    plugins:
      - typescript
      - typescript-resolvers
    config:
      federation: true
  output.graphql:
    plugins:
      - schema-ast
    config:
      includeDirectives: true
      federation: true

Expected behavior
The output should support having more than one key directive even when the type is extended elsewhere

Environment:

  • OS: Windows 10
  • @graphql-codegen/...: 1.17.8
  • NodeJS: 10.22.0

Additional context

@Micahnator
Copy link
Author

I'm peeling back the onion a little more and seeing another issue, though I don't fully understand it. If I tweak my individual schema files to not extend type User, the schema-ast that is generated seems correct. But the typescript-resolvers output is giving me trouble.

I get the following type definition for the __resolveReference resolver function:
__resolveReference?: ReferenceResolver<Maybe<ResolversTypes['User']>, { __typename: 'User' } & (GraphQLRecursivePick<ParentType, {"id":true}> | GraphQLRecursivePick<ParentType, {"username":true}>), ContextType>;
But for some reason Typescript intellisense only thinks the reference input variable has a property of __typename and it doesn't think either "id" or "username" exist.

It's looking like this particular quirk is a typescript issue, because the following simplified test behaves the same way:

// Intellisense only complains about property "d" in initial assignment
let test: { a: string } & ({ b: string } | { c: string }) = { a: "The", b: "United", c: "States", d: "of America" };
test.b = "hi"; // Intellisense thinks that only test.a exists here and complains

@rolandszoke
Copy link

rolandszoke commented Oct 15, 2021

Try the following __resolveReference resolver function:

  User: {
    __resolveReference: (reference, { dataSources }) => {
      if ('id' in reference) {
        return dataSources.db.getUserById({ id: reference.id });
      }
      if ('username' in reference) {
        return dataSources.db.getUserByUsername({ username: reference.username });
      }
      return dataSources.db.getUserByEmail({ email: reference.email });
    },
  },

This way Typescript should know that you are not referencing anything that should not be there, so it should not throw an error.

@charlypoly charlypoly added the core Related to codegen core/cli label Nov 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Related to codegen core/cli plugins
Projects
None yet
Development

No branches or pull requests

4 participants