prisma-labs/graphqlgen

generated subscription types don't make sense

samuela opened this issue · 3 comments

Description

I have a schema with

...
type Subscription {
  buildEvents(buildId: ID!): BuildMessage
}

graphqlgen generates

export namespace SubscriptionResolvers {
  export const defaultResolvers = {};

  export interface ArgsBuildEvents {
    buildId: string;
  }

  export type BuildEventsResolver = {
    subscribe: (
      parent: undefined,
      args: ArgsBuildEvents,
      ctx: IContext,
      info: GraphQLResolveInfo
    ) =>
      | AsyncIterator<BuildMessage | null>
      | Promise<AsyncIterator<BuildMessage | null>>;
    resolve?: (
      parent: undefined,
      args: ArgsBuildEvents,
      ctx: IContext,
      info: GraphQLResolveInfo
    ) => BuildMessage | null | Promise<BuildMessage | null>;
  };

  export interface Type {
    buildEvents: {
      subscribe: (
        parent: undefined,
        args: ArgsBuildEvents,
        ctx: IContext,
        info: GraphQLResolveInfo
      ) =>
        | AsyncIterator<BuildMessage | null>
        | Promise<AsyncIterator<BuildMessage | null>>;
      resolve?: (
        parent: undefined,
        args: ArgsBuildEvents,
        ctx: IContext,
        info: GraphQLResolveInfo
      ) => BuildMessage | null | Promise<BuildMessage | null>;
    };
  }
}

Note that parent is typed as undefined for the resolve method. This is problematic because writing

export const Subscription: SubscriptionResolvers.Type = {
  ...SubscriptionResolvers.defaultResolvers,

  buildEvents: {
    subscribe: (_, { buildId }, ctx) =>
      ctx.db.$subscribe.buildMessage({
        mutation_in: ["CREATED", "UPDATED"],
        node: { build: { id: buildId } },
      }).node(),
  },
};

compiles fine but every output event is just emitted as null:

{
  "data": {
    "buildEvents": null
  }
}

Using

  buildEvents: {
    subscribe: (_, { buildId }, ctx) =>
      ctx.db.$subscribe.buildMessage({
        mutation_in: ["CREATED", "UPDATED"],
        node: { build: { id: buildId } },
      }).node(),

    resolve: (parent: any) => parent,
  },

instead works as expected but requires typing parent as any since the generated type is undefined.

Steps to reproduce

Provided above.

Expected results

Honestly I'm not even sure what the type should be. I can't really find documentation for it anywhere. The example code here: https://github.com/prisma/prisma-examples/blob/master/typescript-graphql-subscriptions/src/resolvers/Subscription.ts doesn't provide any types on the resolve method.

On a side note: Where is the documentation on all the different options when implementing subscriptions resolvers? Why does the resolver method even do and why is it required? Where is this implemented?

Actual results

What was described.

Versions

  • graphqlgen: 0.4.0
  • OS name and version: macOS 10.14

Would the solution be just generating the type for parent as BuildMessage?

@affanshahid That seems like it would make sense, but I have no way of knowing for sure. Could it also accept null or undefined? I dunno...

From my understanding the types are partially correct. What would need to change is the following:

  • the values returned by the AsyncIterator returned by subscribe can be of type BuildMessage|Payload (Payload being an arbitrary type)
  • if the value mentioned above is of type Payload, then resolve is mandatory
  • resolve's parent argument has to be of the same type as the value returned from the AsyncIterator mentioned above

Here are Apollo docs.