david-eos / dynamic-typegraphql-filter

GNU General Public License v3.0
7 stars 1 forks source link

All resolvers returns null when running with NestJS #1

Open ms4io opened 4 years ago

ms4io commented 4 years ago

Hi David

It is a very well done job! Congrats!

I created a NestJS project below and I am trying to run the dynamic approach you created.

https://github.com/RELATO/nestjs-mysql-rest-and-typegraphql.git

You can see the DynamicModule in app.module.ts


@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "mysql",
      host: process.env.DB_HOST,
      port: 3306,
      username: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: "ideas",
      entities: [__dirname + "/**/*.entity{.ts,.js}"],
      synchronize: true,
      logging: true,
    }),
    GraphQLModule.forRoot({
      playground: process.env.NODE_ENV !== "production",
      autoSchemaFile: "schema.gql",
      context: ({ req }) => ({ headers: req.headers }),
    }),
    IdeaModule,
    UserModule,
    CommentModule,
    DynamicModule,
  ],

Can you help, please ?

RELATO commented 4 years ago

Hi David

I really appreciate this dynamic approach!

Thank you for your help.

Destreyf commented 4 years ago

@ms4io I just ran into this as well, i actually am implementing this in a NestJS project myself, I tweaked it quite a bit to get it working, but here's the main thing i did.

import { BaseEntity, EntityManager, ObjectType } from 'typeorm';
import { GraphQLResolveInfo } from 'graphql';
import { GraphQLQueryTree } from '../utils/GraphQLQueryTree';
import { DynamicRepository } from '../utils/DynamicRepository';

import { QueryDto, QueryForIdDto } from '@captura/shared/dto/crud/query.dto';
import { Args, Info, Query, Resolver } from '@nestjs/graphql'; // Note i'm using Args/Info/Query/Resolver from nest.

export function createBaseResolver<T extends BaseEntity, X extends ClassType, Z extends ClassType>(
    suffix: string,
    pluralSuffix: string,
    entityClass: ObjectType<T>,
    entityArgsType: X,
    entityFilterArgsType: Z,
) {

    @Resolver({ isAbstract: true })
    abstract class BaseResolver {
        protected constructor(public manager: EntityManager) {
        }
        /**
         * QUERIES
         */

        @Query(() => entityClass, { name: `get${suffix}`, nullable: true })
        protected async get(
            // @Ctx() { conn }: Context, // We're not going to pass the "connection" in this way.
            @Args(() => entityArgsType) {}: typeof entityArgsType,
            @Info() info: GraphQLResolveInfo,
        ): Promise<T> {
            const conn = this.manager.connection; // We load the connection from the entity manager
            const tree = GraphQLQueryTree.createTree(info);
            console.log(tree.toObject());

            return await DynamicRepository.findOne<T>(conn, tree, entityClass);
        }

        @Query(() => [entityClass], { name: `getAll${pluralSuffix}`, nullable: true })
        protected async getAll(
            // @Ctx() { conn }: Context, // We're not going to pass the "connection" in this way.
            @Args(() => entityFilterArgsType) {}: typeof entityFilterArgsType,
            @Info() info: GraphQLResolveInfo,
        ): Promise<T[]> {
            const conn = this.manager.connection; // We load the connection from the entity manager
            const tree = GraphQLQueryTree.createTree(info);
            console.log(tree.toObject());
            return await DynamicRepository.find<T>(conn, tree, entityClass);
        }
    }

    return BaseResolver;
}

page.resolver.ts

import { Resolver } from '@nestjs/graphql';
import { Page } from "../entity/Page";
import { createBaseResolver } from "./BaseResolver";
import { PageArgs, PageFilterArgs } from "../arg/PageArgs";

const BasePageResolver = createBaseResolver("Page", "Pages", Page, PageArgs, PageFilterArgs);

@Resolver(Page)
export class PageResolver extends BasePageResolver {
    constructor(public readonly manager: EntityManager){
        super(manager);
    }
}

my use case is a little more detailed, but there 2 change. 1) Pass the entity manager in via the super call in the entity specific resolver so it's available to the underlying base class. 2) Use the entity manager instead of expecting a context object to be provided.