graphql-compose / graphql-compose-mongoose

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

Type 'Cat' is not assignable to type 'Document<any, any, any>' #424

Open alexneo2003 opened 1 year ago

alexneo2003 commented 1 year ago

Latest version installed package.json

    "@nestjs/apollo": "^10.1.7",
    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/graphql": "^10.1.7",
    "@nestjs/mongoose": "^9.2.1",
    "@nestjs/platform-express": "^9.0.0",
    "apollo-server-express": "^3.11.1",
    "graphql": "^16.6.0",
    "graphql-compose": "9.0.10",
    "graphql-compose-mongoose": "9.7.2",
    "mongoose": "6.8.3",

Following instructions and try using graphql-compose-mongoose in NestJS project

import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { schemaComposer } from 'graphql-compose';
import { composeMongoose } from 'graphql-compose-mongoose';
import mongoose from 'mongoose';

@Schema({ timestamps: true })
@ObjectType()
export class Cat {
  @Prop()
  @Field(() => String)
  name: string;

  @Prop()
  @Field(() => Int)
  age: number;

  @Prop()
  @Field(() => String)
  breed: string;
}

const schema = SchemaFactory.createForClass(Cat);

const CatModel = mongoose.model('Cat', schema);
const CatTC = composeMongoose(CatModel, {});

schemaComposer.Query.addFields({
  catById: CatTC.mongooseResolvers.findById(),
});

export const CatSchema = schemaComposer.buildSchema();

But got error at const CatTC = composeMongoose(CatModel, {});

Argument of type 'Model<Cat, {}, {}, {}, Schema<Cat, Model<Cat, any, any, any, any>, {}, {}, {}, {}, DefaultSchemaOptions, Cat>>' is not assignable to parameter of type 'Model<Document<any, any, any>, {}, {}, {}, any>'.
  The types returned by 'castObject(...)' are incompatible between these types.
    Type 'Cat' is not assignable to type 'Document<any, any, any>'.ts(2345)

~~I can pass any generic const CatModel = mongoose.model<any>('Cat', schema); but still having problem NestJS saying~~

[Nest] 11348  - 15.01.2023, 20:05:21   ERROR [ExceptionHandler] The 2nd parameter to `mongoose.model()` should be a schema or a POJO
Error: The 2nd parameter to `mongoose.model()` should be a schema or a POJO

Schema injected in nestjs at module file

cat.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Cat, CatSchema } from './cat.model';
import { CatService } from './cat.service';
import { CatResolver } from './cat.resolver';

@Module({
  imports: [MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }])],
  providers: [CatService, CatResolver],
})
export class CatModule {}

Another way - cloning example and seen you using any heneric too export const Category = model<any>('Category', CategorySchema); If i remove it i got error

Argument of type 'Model<unknown, {}, {}>' is not assignable to parameter of type 'Model<Document<any, any, any>, {}, {}>'.
  Types of property 'find' are incompatible.
    Type '{ (callback?: Callback<(Document<any, any, unknown> & { _id: unknown; })[]>): Query<(Document<any, any, unknown> & { _id: unknown; })[], Document<any, any, unknown> & { _id: unknown; }, {}, unknown>; (filter: FilterQuery<...>, callback?: Callback<...>): Query<...>; (filter: FilterQuery<...>, projection?: any, option...' is not assignable to type '{ (callback?: Callback<(Document<any, any, any> & { _id: any; })[]>): Query<(Document<any, any, any> & { _id: any; })[], Document<any, any, any> & { ...; }, {}, Document<...>>; (filter: FilterQuery<...>, callback?: Callback<...>): Query<...>; (filter: FilterQuery<...>, projection?: any, options?: QueryOptions, callb...'.
      Types of parameters 'callback' and 'callback' are incompatible.
        Types of parameters 'result' and 'result' are incompatible.
          Type 'unknown[]' is not assignable to type 'Document<any, any, any>[]'.
            Type 'unknown' is not assignable to type 'Document<any, any, any>'.ts(2345)

If update packages to latest version - got same error as in my own project

Based on the above, there are two questions:

  1. How using package without generic?
  2. How integrate with NestJS?
alexneo2003 commented 1 year ago

I found ansver on my 2 question compose schema


export const UserSchema = SchemaFactory.createForClass(User);

const UserModel = mongoose.model<any>('User', UserSchema);
const UserTC = composeMongoose(UserModel, {});

schemaComposer.Query.addFields({
  userById: UserTC.mongooseResolvers.findById(),
  getUser: UserTC.mongooseResolvers.findOne(),
  getAllUsers: UserTC.mongooseResolvers.findMany(),
});

schemaComposer.Mutation.addFields({
  updateUser: UserTC.mongooseResolvers.updateOne(),
  removeUser: UserTC.mongooseResolvers.removeOne(),
});

const composeSchema = schemaComposer.buildSchema();

writeFileSync(join(process.cwd(), `/src/gql-schema/${User.name}.graphql`), printSchema(composeSchema));

connect compose schemas files to NestJS server

@Module({
  imports: [
    MongooseModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        uri: process.env.MONGO_URI || configService.get('MONGO_URI'),
        useNewUrlParser: true,
        useUnifiedTopology: true,
      }),
      inject: [ConfigService],
    }),
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
-     autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
+     typePaths: ['./**/*.graphql'],
    }),
    UserModule,
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

but i steel have first question

tatejones commented 8 months ago

Did you get any resolution for your first question?

graphql-compose-mongoose : 9.8.0 mongoose: 7.6.4

The basic code from the site fails TS.

import { composeMongoose } from "graphql-compose-mongoose"
import mongoose from "mongoose"

const LanguagesSchema = new mongoose.Schema({
    language: String,
    skill: {
        type: String,
        enum: ["basic", "fluent", "native"],
    },
})

const UserSchema = new mongoose.Schema({
    name: String, // standard types
    age: {
        type: Number,
        index: true,
    },
    ln: {
        type: [LanguagesSchema], // you may include other schemas (here included as array of embedded documents)
        default: [],
        alias: "languages", // in schema `ln` will be named as `languages`
    },
    contacts: {
        // another mongoose way for providing embedded documents
        email: String,
        phones: [String], // array of strings
    },
    gender: {
        // enum field with values
        type: String,
        enum: ["male", "female"],
    },
    someMixed: {
        type: mongoose.Schema.Types.Mixed,
        description: "Can be any mixed type, that will be treated as JSON GraphQL Scalar Type",
    },
})
const User = mongoose.model("User", UserSchema)

const customizationOptions = {} // left it empty for simplicity, described below
const UserTC = composeMongoose(**User**, customizationOptions) <=====

Argument of type 'Model<{ ln: DocumentArray<{ language?: string | undefined; skill?: "basic" | "fluent" | "native" | undefined; }>; name?: string | undefined; age?: number | undefined; contacts?: { ...; } | undefined; gender?: "male" | ... 1 more ... | undefined; someMixed?: any; }, ... 4 more ..., Schema<...>>' is not assignable to parameter of type 'Model<Document<any, any, any>, {}, {}, {}, Document<unknown, {}, Document<any, any, any>> & Document<any, any, any> & { _id: ObjectId; }, any>'. The types returned by 'castObject(...)' are incompatible between these types. Type '{ ln: DocumentArray<{ language?: string | undefined; skill?: "basic" | "fluent" | "native" | undefined; }>; name?: string | undefined; age?: number | undefined; contacts?: { ...; } | undefined; gender?: "male" | ... 1 more ... | undefined; someMixed?: any; }' is not assignable to type 'Document<any, any, any>'.ts(2345)

image