0

I am a bit stuck in developing my GraphQL Api Server, using Sequelize and Typescript. My problem is related to a typing and concept issue. I have defined my Sequelize models according to the db tables and their relationships. I am using these models in GraphQL resolvers, like here:

Query: {
    part: (_, { id }, { models }) => models.Part.findByPk(id),
    parts: (_, __, { models }) => models.Part.findAll(),
},
Part: {
    subparts: async (parent, _, { models }) => {
      const parentPart = await models.Part.findByPk(parent.id, { include: { model: models.Part, as: 'children' } });
      if (parentPart) {
        return parentPart.getChildren();
      }
      return [];
}

The doubt I have is related to the type that the first argument of the field subparts resolver. According to the resolvers types I have generated through graphQL code generator parent should have the same type I have defined in the schema, but this is not true, it has the model type, because a model instance is what the parent resolver returns.

UPDATE: I am attaching here my codegen.yml, following a very valuable comment. I have a defined a mapper for the type Part and this is what I supposed to be the type of the parent resolver argument.

schema: ./src/**/*.typedefs.ts
generates: 
    ./src/types/graphql.generated.ts:
        plugins:
            - typescript
            - typescript-resolvers
        config:
            noSchemaStitching: true
            useIndexSignature: true
            contextType: ../context#MyContext
            mappers:
                Part: ../part/part.types#IPart
                MacroProduct: ../macro-product/macroProduct.types#IMacroProduct

This is the type I am using as Part mapper:

export interface IPart {
  id: number;
  name: string;
  thumb?: string;
  subparts?: [IPart];
  parentId?: number;
}

I thought it should have been the type of the parent arg but I am using the find method provided by Sequelize in the Query resolvers, so maybe this affects the parent type too.

What am I understanding and / or doing wrong?

Thank you very much to everyone that will spend her / his time to help me.

delca85
  • 1,176
  • 2
  • 10
  • 17
  • nope, it's not as easy at it looks like ...ts sxxx ... parent type is more return/schema type, for sure not model type because it can contain pre/overfetched child props ... and can be extended to pass values to child resolvers – xadm Sep 07 '20 at 21:04
  • thanks @xadm, I am understanding it is really a mess using sequelize, graphql and ts. I prefer to not use sequelize-typescript but I am writing a ton or types by myself. – delca85 Sep 07 '20 at 22:03
  • not all elements should be strictly typed ... at start ... you should know first how it can be used ... even now some basic react typings are still wrong [and limiting], badly assumed/coded, not resolved for years .... in your case ... returned types can be used as parent for other resolver...model? with children? – xadm Sep 07 '20 at 22:27
  • 1
    Do you mind sharing your codegen yaml config file? I think the first argument should be the parent type as defined in the schema as you mentioned, unless you are using a mapper for the `Part` type in the config file – quantdaddy Sep 08 '20 at 05:57
  • @quantdaddy I have added my codegen and the mapper I use for the `Part` type. Thank you for your help! – delca85 Sep 08 '20 at 06:39
  • 1
    Honestly this is strange. Does `models.Part.findByPk(id)` satisfy the IPart interface? If it does, what's the need to load subparts again because parent can resolve subparts already? Also, I'd use DataLoader rather than accessing models directly to avoid N+1 problem. – quantdaddy Sep 08 '20 at 15:34
  • `models.Part.findByPk(id)` does not satisfy the `IPart` interface, because this satisfies the `Part` model instance, not the plain js. I have to load `subparts` again because this field is the result of a join between two tables. I am going to check if this is a use case for `DataLoader`. – delca85 Sep 08 '20 at 20:39
  • @quantdaddy I fixed my code and make the `find` methods of sequelize returns `IPart` compliant object. Anyway, I am not sure I am using sequelize in the right way, combined with TS and GraphQL. – delca85 Sep 08 '20 at 21:12
  • 1
    This is a perfect use case for data loader. I don't worry too much about making multiple queries if they are fast. I'd suggest investing some time in learning Dataloader. It's a must for graphql resolvers. Also I personally make sequelize queries independent of the mappers. Sooner or later you may need to make raw queries and things would get difficult. – quantdaddy Sep 09 '20 at 01:02
  • @quantdaddy thanks a lot! I am going to study data loader as soon as I can. I have just question: what do you mean with "making sequelize queries independent from the mappers"? I have changed my code in `findByPk` and `findAll` and now they run in `raw` mode, so I am able to return object `IPart` compliant. Is this wrong? – delca85 Sep 09 '20 at 06:49
  • 1
    What I meant was you don't have to use the Model that sequelize queries return as a mapper because a model contains main fields and method that are not needed for further resolution. – quantdaddy Sep 09 '20 at 16:02
  • 1
    Ok, so I got it! Thank you very much @quantdaddy, you have been so helpful! I am studying data loader just now. – delca85 Sep 09 '20 at 20:08

0 Answers0