Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: prisma typed select #347

Merged
merged 5 commits into from
Jun 22, 2023
Merged

feat: prisma typed select #347

merged 5 commits into from
Jun 22, 2023

Conversation

magrinj
Copy link
Member

@magrinj magrinj commented Jun 21, 2023

This PR removes some relation resolvers using PrismaSelect from PalJS.
The PrismaSelect class is able to extract fields required from GraphQLResolveInfo.
This one is working fine, but one problem of this library is the lack of type support prisma-tools/#260.

Because Prisma doesn't export a map that makes a relation between model name and select interfaces, I've added a script that generates this type mapping.
This one is called each time we regenerate the Prisma client.

The API in place uses a decorator to extract select from GraphQLResolveInfo.
This decorator calls PrismaSelect under the hood.

  1. Basic way to use it
@UseGuards(JwtAuthGuard)a
@Resolver(() => Pipeline)
export class PipelineResolver {
  constructor(private readonly pipelineService: PipelineService) {}

  @Query(() => [Pipeline])
  @UseGuards(AbilityGuard)
  @CheckAbilities(ReadPipelineAbilityHandler)
  async findManyPipeline(
    @Args() args: FindManyPipelineArgs,
    @UserAbility() ability: AppAbility,
    @PrismaSelector({ modelName: 'Pipeline' }) // <-- New PrismaSelector decorator to use
    prismaSelect: PrismaSelect<'Pipeline'>, // <-- Fully typed PrismaSelect
  ): Promise<Partial<Pipeline>[]> {
    return this.pipelineService.findMany({
      ...args,
      where: {
        ...args.where,
        AND: [accessibleBy(ability).Pipeline],
      },
      select: prismaSelect.value,
    });
  }
}

In the above example, we simply extract the select from the prismaSelect class using value.

  1. Use it with pagination
@UseGuards(JwtAuthGuard)
@Resolver(() => Pipeline)
export class PipelineResolver {
  constructor(private readonly pipelineService: PipelineService) {}

  @Query(() => PaginatedPipeline)
  @UseGuards(AbilityGuard)
  @CheckAbilities(ReadPipelineAbilityHandler)
  async findManyPipeline(
    @Args() args: FindManyPipelineArgs,
    @UserAbility() ability: AppAbility,
    @PrismaSelector({ modelName: 'Pipeline' }) // <-- New PrismaSelector decorator to use
    prismaSelect: PrismaSelect<'Pipeline'>, // <-- Fully typed PrismaSelect
  ): Promise<PaginatedPipeline> {
    return findManyCursorConnection(
      async (findManyArgs) => {
        const results = await this.pipelineService.findMany({
          ...findManyArgs,
          select: prismaSelect.valueOf('edges.node'),
          where: whereInput,
          orderBy,
        });

        return results;
      },
      () => this.pipelineService.count(where),
      connectionArgs,
    );
  }
}

Here, because we're using pagination, we need to let PrismaSelect know from where the select needs to be extracted with valueOf.
valueOf can also be used with a second argument specifying a modelName like this: valueOf('edges.node', 'PipelineStage'). That way, we're extracting the select of PipelineStage only, which is a relation of Pipeline.

@magrinj magrinj linked an issue Jun 21, 2023 that may be closed by this pull request
@magrinj magrinj requested a review from charlesBochet June 22, 2023 07:37
@magrinj magrinj marked this pull request as ready for review June 22, 2023 07:38
@magrinj magrinj requested a review from lucasbordeau June 22, 2023 07:43
@magrinj magrinj changed the title feat: wip prisma gql select feat: prisma typed select Jun 22, 2023
@magrinj magrinj merged commit ca283a2 into main Jun 22, 2023
@magrinj magrinj deleted the prisma-gql-select branch June 22, 2023 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Timebox] Put in place Pal.js on NestJS
2 participants