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

GroupBy Argument Type required parameter follows an optional parameter #229

Open
lodeli-lulu opened this issue Jan 22, 2025 · 8 comments
Open
Labels
awaiting-feedback invalid This doesn't seem right question Further information is requested

Comments

@lodeli-lulu
Copy link

Hey,

the required property by follows the optional parameters where and orderBy, which results in an error on the generated typescript definition file from NestJs.

Example to reproduce:

// Prisma Schema
model User {
  id        Int        @id @default(autoincrement())
  email     String     @unique
  name      String?
  blogPosts BlogPost[]

  @@map("user")
}

model BlogPost {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now()) @map(name: "created_at")
  updatedAt DateTime @updatedAt @map(name: "updated_at")
  title     String
  content   String?
  published Boolean  @default(false)
  viewCount Int      @default(0) @map(name: "view_count")
  author    User?    @relation(fields: [authorId], references: [id])
  /// @HideField()
  authorId  Int?     @map(name: "author_id")

  @@map("blog_post")
}
// NestJs Query
@Query(() => [UserGroupBy])
  private async groupByUser(
    @Args() groupByArgs: UserGroupByArgs,
  ): Promise<UserGroupBy[]> {
    return this._user.groupBy(groupByArgs) as Promise<UserGroupBy[]>;
  }

You will get following error in generated typescript definitions file:

error TS1016: A required parameter cannot follow an optional parameter.

abstract groupByUser(where?: Nullable<UserWhereInput>, orderBy?: Nullable<UserOrderByWithAggregationInput[]>, by: UserScalarFieldEnum[], having?: Nullable<UserScalarWhereWithAggregatesInput>, take?: Nullable<number>, skip?: Nullable<number>, _count?: Nullable<UserCountAggregateInput>, _avg?: Nullable<UserAvgAggregateInput>, _sum?: Nullable<UserSumAggregateInput>, _min?: Nullable<UserMinAggregateInput>, _max?: Nullable<UserMaxAggregateInput>): UserGroupBy | Promise<UserGroupBy>;

My versions:

  • NestJs version: 11
  • Prisma version: 6
  • prisma-nestjs-graphql: 21.0.2
@unlight
Copy link
Owner

unlight commented Jan 23, 2025

Some generated graphql classes (input/output) may not be compatible with prisma types. You must adapt it.

@lodeli-lulu
Copy link
Author

It's not the problem, that some generated graphql classes are not compatible with prisma types.

The fields of the generated @ArgType for the groupBy method have an incorrect order. The required fields should be defined before the optional fields.

Current generated class:

@ArgsType()
export class UserGroupByArgs {
  @Field(() => UserWhereInput, { nullable: true })
  @Type(() => UserWhereInput)
  where?: InstanceType<typeof UserWhereInput>;
  @Field(() => [UserOrderByWithAggregationInput], { nullable: true })
  orderBy?: Array<UserOrderByWithAggregationInput>;
  @Field(() => [UserScalarFieldEnum], { nullable: false }) // <-- Required field after optional fields
  by!: Array<`${UserScalarFieldEnum}`>;
  @Field(() => UserScalarWhereWithAggregatesInput, { nullable: true })
  having?: InstanceType<typeof UserScalarWhereWithAggregatesInput>;
  @Field(() => Int, { nullable: true })
  take?: number;
  @Field(() => Int, { nullable: true })
  skip?: number;
  @Field(() => UserCountAggregateInput, { nullable: true })
  _count?: InstanceType<typeof UserCountAggregateInput>;
  @Field(() => UserAvgAggregateInput, { nullable: true })
  _avg?: InstanceType<typeof UserAvgAggregateInput>;
  @Field(() => UserSumAggregateInput, { nullable: true })
  _sum?: InstanceType<typeof UserSumAggregateInput>;
  @Field(() => UserMinAggregateInput, { nullable: true })
  _min?: InstanceType<typeof UserMinAggregateInput>;
  @Field(() => UserMaxAggregateInput, { nullable: true })
  _max?: InstanceType<typeof UserMaxAggregateInput>;
}

Class as it should be generated:

@ArgsType()
export class UserGroupByArgs {
  @Field(() => [UserScalarFieldEnum], { nullable: false }) // <-- Required field at first
  by!: Array<`${UserScalarFieldEnum}`>;
  @Field(() => UserWhereInput, { nullable: true })
  @Type(() => UserWhereInput)
  where?: InstanceType<typeof UserWhereInput>;
  @Field(() => [UserOrderByWithAggregationInput], { nullable: true })
  orderBy?: Array<UserOrderByWithAggregationInput>;
  @Field(() => UserScalarWhereWithAggregatesInput, { nullable: true })
  having?: InstanceType<typeof UserScalarWhereWithAggregatesInput>;
  @Field(() => Int, { nullable: true })
  take?: number;
  @Field(() => Int, { nullable: true })
  skip?: number;
  @Field(() => UserCountAggregateInput, { nullable: true })
  _count?: InstanceType<typeof UserCountAggregateInput>;
  @Field(() => UserAvgAggregateInput, { nullable: true })
  _avg?: InstanceType<typeof UserAvgAggregateInput>;
  @Field(() => UserSumAggregateInput, { nullable: true })
  _sum?: InstanceType<typeof UserSumAggregateInput>;
  @Field(() => UserMinAggregateInput, { nullable: true })
  _min?: InstanceType<typeof UserMinAggregateInput>;
  @Field(() => UserMaxAggregateInput, { nullable: true })
  _max?: InstanceType<typeof UserMaxAggregateInput>;
}

@unlight
Copy link
Owner

unlight commented Jan 24, 2025

Weird. 😕

@unlight
Copy link
Owner

unlight commented Jan 25, 2025

Like I suspected, order of fields in class doesnt matter.

Image

Some types may not be compatible, in your case with schema above generated UserGroupByArgs is compatible with prisma user.groupBy argument.

import { Prisma } from '@prisma/client';

  @Query(() => [UserGroupBy])
  async groupByUser(
    @Args() groupByArgs: UserGroupByArgs,
  ): Promise<UserGroupBy[]> {
    const userGroupByArgs: Prisma.UserGroupByArgs = groupByArgs; // no errors 

    return prisma.user.groupBy(userGroupByArgs);
  }

@unlight
Copy link
Owner

unlight commented Jan 25, 2025

Tested on graphql query

query {
  groupByUser(
    orderBy: [{ name: asc }]
    by: [id, name]
  ) 
  {
    id
    name
  }
}
userGroupByArgs = {
  orderBy: [ { name: 'asc' } ],
  by: [ 'id', 'name' ]
}

@unlight unlight added question Further information is requested awaiting-feedback invalid This doesn't seem right labels Jan 25, 2025
@lodeli-lulu
Copy link
Author

I created a minimal reproduction project. You can find it here.

I noticed that I used that the definitions property to configure the GraphQLModule, but it is not necessary in code-first approach. The error error TS1016: A required parameter cannot follow an optional parameter. occurred in this generated definitions file.

However, I get still an error on the groupBy function:

@Query(() => [UserGroupBy])
  async groupByUser(
    @Args() groupByArgs: UserGroupByArgs,
  ): Promise<UserGroupBy[]> {
    const userGroupByArgs: Prisma.UserGroupByArgs = groupByArgs;

    // TODO: Does not work without @ts-ignore
    return this._prisma.user.groupBy(userGroupByArgs);
  }

You can search for TODO in my example project.

@unlight
Copy link
Owner

unlight commented Jan 27, 2025

Looks like you are facing this issue prisma/prisma#17297

@unlight
Copy link
Owner

unlight commented Jan 27, 2025

I see different error:

Type of property 'AND' circularly references itself in mapped type '{ [K in keyof { AND?: BlogPostScalarWhereWithAggregatesInput | BlogPostScalarWhereWithAggregatesInput[]; ... 9 more ...; authorId?: number | IntNullableWithAggregatesFilter<...>; }]: Or<...> extends 1 ? { ...; }[K] extends infer TK ? GetHavingFields<...> : never : {} extends FieldPaths<...> ? never : K; }'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting-feedback invalid This doesn't seem right question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants