graphql-compose / graphql-compose-mongoose

Mongoose model converter to GraphQL types with resolvers for graphql-compose https://github.com/nodkz/graphql-compose
MIT License
708 stars 94 forks source link

graphql-compose-mongoose with serverless environment missing mongooseResolvers #362

Open sajadghawami opened 3 years ago

sajadghawami commented 3 years ago

Hey,

i am trying to integrate graphql-compose-mongoose with a serverless framework, in my case nextjs.

I was getting the following error:

Error: You try to generate GraphQL Type with name from mongoose model but this type already exists in SchemaComposer. Please choose another type name "composeWithMongoose(model, { name: 'NewTypeName' })", or reuse existed type "schemaComposer.getOTC('TypeName')", or remove type from SchemaComposer before calling composeWithMongoose method "schemaComposer.delete('TypeName')".

So i created the following helper function that will look for the previously created ObjectType or add it to the schemaComposer:

const createObjectTC = <T extends {}>({
  model,
  customizationOptions = {},
}: {
  model: Model<Document<any, any, any>, {}, {}>;
  customizationOptions: any;
}) => {
  let ModelTC = null;

  try {
    ModelTC = schemaComposer.getOTC(model.modelName)
  } catch {
    ModelTC = composeMongoose(model, customizationOptions);
  }

  return ModelTC;
};

I would use it like this:

...

export const UserTC = createObjectTC({
  model: User,
  customizationOptions: {},
});

The problem seems to be that schemaComposer.getOTC(model.modelName) will not get the mongooseResolvers.

So this will throw a type error, and not work:

serSchemaComposer.Query.addFields({
  userSignUp: UserTC.mongooseResolvers.findById(), 
});

The error:

Property 'mongooseResolvers' does not exist on type 'ObjectTypeComposer<any, any> | (ObjectTypeComposer<Document<any, any, any>, any> & { mongooseResolvers: GenerateResolverType<Document<any, any, any>, any>; })'.
  Property 'mongooseResolvers' does not exist on type 'ObjectTypeComposer<any, any>'. 

Is there any function than will do the same as getOTC but also add the mongooseResolvers?

Thank you.

canac commented 3 years ago

I've used graphql-compose-mongoose in a serverless environment before (Apollo Server running in Netlify), so I know that it can be done. Mind sharing some more of your code?

The reason you're getting the Property 'mongooseResolvers' does not exist on type ... error is that TypeScript doesn't know that your OTC has the extra mongooseResolvers property on it. The graphql-compose package defines the types for object type composers, but composeMongoose returns an OTC with an extra mongooseResolvers property. So when you call schemaComposer.getOTC(model.modelName), TypeScript has no way of knowing that the return value actually has that extra field. The mongooseResolvers field should still be there on the raw JavaScript object, but since it's not defined on the TypeScript type, TS won't let you access it. Probably the easiest way around this is with a cast. Does replacing schemaComposer.getOTC(model.modelName) with schemaComposer.getOTC(model.modelName) as ObjectTypeComposer<Document<any, any, any>, any> & { mongooseResolvers: GenerateResolverType<Document<any, any, any>, any>; } fix that error?

sajadghawami commented 3 years ago

hey @canac ,

thank you for the quick reply! You are right, the cast is working fine.

Thank you :)