Skip to content

feature request: add option to output interface props of interfaces as partials for types with separated field resolvers #263

@BigsonLvrocha

Description

@BigsonLvrocha

Hello,

In graphql-yoga it is common to have a field in a type that is resolved with a separated function, so the main resolver will have to return the object with those fields missing for it to be fetched later, if queried. But the interfaces generated by gql2ts do not allow undefined in those fields.

I've been doing a workaround by defining the return of queries with Partial, but the problem is when those types are nested within another type, for instance, mutation response payload. I wished to use the generated interfaces as a helper in the resolvers return definition, but I can't assign Partial to INode type.

Example, in the snippet bellow, it is shown the resolvers for the type "Post", which has the field "Author" that can be fetched separately. I can define post query's return as Partial but I can't define the UserCreatePost mutation's return as IUserCreatePostPayload because I need to assign a full IPost object, making me having to define those types or just strip away the return type definition, which makes the library a bit pointless for this use case, it certainly makes IUserCreatePostPayload generation pointless

type Post implements Node {
  id: ID!
  _id: String!
  title: String!
  description: String
  authorId: String!
  author: User!
}

type Mutation {
  UserCreatePost(input: UserCreatePostInput!): UserCreatePostPayload
}

type Query {
  post(id: ID!): Post
  feed(first: Int, after: String, last: Int, before: String): PostConnection
}

input UserCreatePostInput {
  title: String!
  description: String
  clientMutationId: String
}

type UserCreatePostPayload {
  error: String
  post: Post
  clientMutationId: String
}
export const post2IPost: model2Node<Post, GQL.IPost> = (
  post: Post
): Partial<GQL.IPost> => ({
  _id: post._id,
  id: idToGraphqlId(post._id, idPrefix),
  title: post.title,
  description: post.description,
  authorId: post.authorId,
});

export const resolvers: ResolverMap = {
  Mutation: {
    UserCreatePost: async (
      _,
      {
        input: { description, clientMutationId, title }
      }: GQL.IUserCreatePostOnMutationArguments,
      { sequelize, userId }
    ) => {
      const PostModel = sequelize.models.Post as ModelCtor<Post>;
      const post = (await PostModel.create({
        description,
        title,
        authorId: userId
      })) as Post;
      return {
        error: null,
        post: post2IPost(post),
        clientMutationId: clientMutationId || null
      };
    }
  },
  Query: {
    post: async (
      _,
      { id: graphId }: GQL.IPostOnQueryArguments,
      { sequelize }
    ) => {
      const PostModel = sequelize.models.Post as ModelCtor<Post>;
      const id = graphqIdToId(graphId, "post");
      const postA = (await PostModel.findByPk(id)) as Post;
      if (!postA) {
        return null;
      }
      return post2IPost(postA);
    },
    feed
  },
  Post: {
    author: async (
      parent,
      _,
      { sequelize }
    ): Promise<Partial<GQL.IUser>> => {
      const UserModel = sequelize.models.User as ModelCtor<User>;
      const user = (await UserModel.findByPk(parent.authorId)) as User;
      return user2IUser(user);
    },
  }
};

So, my idea would be an option to output types like this:

interface IUserCreatePostPayload {
error: string | null;
post: IPost | null;
clientMutationId: string | null;
}

With an optional "shallow" type like this

interface IShallowUserCreatePostPayload {
error: string | null;
post: IPost | null | Partial<IPost>;
clientMutationId: string | null;
}

They could be named as shallow interfaces and be generated side by side with the others so it won't break other ppl's code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions