Skip to content

tpdewolf/nestjs-typegraphql-prisma-example

Repository files navigation

Description

This project is an example of how to use the typegraphql-prisma generator with Nest.js. The example includes a SQLite database. But it can obviously also be used with any database that Prisma supports.

Installation

$ yarn

Running the app

# development
$ yarn start

# watch mode
$ yarn dev

# production mode
$ yarn start:prod

TypegraphQL Prisma

TypegraphQL Prisma is an awesome library by Michael Lytek. It generates the model, input and argument classes and resolvers based on your prisma schema. As described in the docs it does not support NestJS GraphQL above version 7 because the decorators differ slightly from TypegraphQL. Therefore I've patched the library with patch-package to change the decorators the work with NestJS GraphQL 7.

  • import package from type-graphql to @nestjs/graphql
  • @Ctx decorator to @Context
  • @FieldResolver decorator to @ResolveField
  • @Root decorator to @Parent

That's all that was needed to make it work with NestJS. The patch is automatically applied after install with the postinstall npm script.

Generating the code

Run the prisma cli to generate the code

$ npx prisma generate

This will create the prisma client, but also a @generated folder in node_modules that includes all input classes, model classes and resolvers based on your schema.

You can now import the resolvers into your module from the @generated/type-graphql folder.

import {
  PostCrudResolver,
  PostRelationsResolver,
} from '@generated/type-graphql';
import { Module } from '@nestjs/common';

@Module({
  providers: [PostCrudResolver, PostRelationsResolver],
})
export class PostModule {}

Customizing the resolvers

Often you would like to customize the resolvers or input and model classes. The project includes a hygen generator to generate a resolver, module, service and model.

To generate the code run the following command

$ npx hygen module create <name>

Then add the module imports property in your AppModule

Example model

The model extends the model from @generated/type-graphql. To add a property to the GraphQL schema, simply add it to the model. To remove a property use the OmitType or PickType helper provided by NestJS.

import {
  Post as GeneratedPost,
  PostCreateInput as GeneratedPostCreateInput,
} from '@generated/type-graphql';
import { InputType, OmitType, PartialType, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class PostModel extends GeneratedPost {}

@InputType()
export class PostCreateInput extends OmitType(
  GeneratedPostCreateInput,
  [] as const,
) {}

@InputType()
export class PostUpdateInput extends PartialType(PostCreateInput) {}

The generator doesnt add the relations to the model automatically. To add the comments relation to the Post simply add it to the PostModel

@ObjectType()
export class PostModel extends GeneratedPost {
  @Field(() => [CommentModel])
  comments: CommandModal[];
}

Example resolver

The resolver includes all basic crud operations. The @SelectArgs decorator utilizes the PrismaSelect class from Pal.js. It extracts the fields from the grapqhl query. They are added to arguments of the prisma client. This also works for relations. The relations are only queried when the fields for the relation is requested in the GraphQL query.

import {
  FindUniquePostArgs,
  FindManyPostArgs,
  PostWhereUniqueInput,
} from '@generated/type-graphql';
import { Args, Mutation, Query, Resolver, Context } from '@nestjs/graphql';
import merge from 'lodash.merge';

import { SelectArgs } from '@/graphql/select-args.decorator';
import { AppContext } from '@/types/context';

import { PostModel, PostCreateInput, PostUpdateInput } from './post.model';
import { PostService } from './post.service';

@Resolver(() => PostModel)
export class PostResolver {
  constructor(private readonly postService: PostService) {}

  @Query(() => PostModel, { nullable: true })
  async post(
    @Args() args: FindUniquePostArgs,
    @Context() ctx: AppContext,
    @SelectArgs() select,
  ) {
    const { prisma } = ctx;

    return prisma.post.findFirst(merge(args, select));
  }

  @Query(() => [PostModel])
  async posts(
    @Context() ctx: AppContext,
    @Args() args: FindManyPostArgs,
    @SelectArgs() select,
  ) {
    const { prisma } = ctx;

    return prisma.post.findMany(merge(args, select));
  }

  @Mutation(() => PostModel)
  async createPost(
    @Context() ctx: AppContext,
    @Args('data') data: PostCreateInput,
    @SelectArgs() select,
  ) {
    const { prisma } = ctx;

    return prisma.post.create(
      merge(select, {
        data,
      }),
    );
  }

  @Mutation(() => PostModel, { nullable: true })
  async updatePost(
    @Context() ctx: AppContext,
    @SelectArgs() select,
    @Args('where') where: PostWhereUniqueInput,
    @Args('data') data: PostUpdateInput,
  ) {
    const { prisma } = ctx;

    return prisma.post.update(
      merge(select, {
        where,
        data,
      }),
    );
  }

  @Mutation(() => PostModel, { nullable: true })
  async deletePost(
    @Context() ctx: AppContext,
    @Args('where') where: PostWhereUniqueInput,
    @SelectArgs() select,
  ) {
    const { prisma } = ctx;

    return prisma.post.delete(
      merge(select, {
        where,
      }),
    );
  }
}

Test

# unit tests
$ yarn test

# e2e tests
$ yarn test:e2e

# test coverage
$ yarn test:cov

Support

Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.

About

An example of how to use typegraphql-prisma with NestJS and @nestjs/graphql ^7

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published