MichalLytek / MichalLytek/typegraphql-prisma
Error in Autogenerated Resolver for Many-to-Many Relations
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 918
- Forks
- 130
- PR merge metrics
- No merged PRs in 30d
Description
Issue Description
There seems to be a bug in the generation of automatic resolvers for many-to-many relationships.
Details:
- I haven't verified if this issue is specific to MongoDB or if it also occurs with relational databases.
- The problem arises specifically with many-to-many relationships. One-to-many relationships work fine.
Example:
Given the following schema:
model Ready {
id String @id @map("_id")
destinazioneId String?
destinazione Standstills? @relation("ReadyToDestinazione", fields: [destinazioneId], references: [id])
intermedi ReadyIntermedi[] @relation("ReadyToIntermedi")
partenzaId String
partenza Standstills? @relation("ReadyToPartenza", fields: [partenzaId], references: [id])
}
model Standstills {
id String @id @map("_id")
indirizzo String
readyPartenza Ready[] @relation("ReadyToPartenza")
readyDestinazione Ready[] @relation("ReadyToDestinazione")
readyIntermediStandstill ReadyIntermedi[] @relation("IntermediToStandstill")
}
model ReadyIntermedi {
id String @id @map("_id")
readyId String
ready Ready @relation("ReadyToIntermedi", fields: [readyId], references: [id])
standstillId String
standstill Standstills @relation("IntermediToStandstill", fields: [standstillId], references: [id])
order Int // To maintain the order of intermediaries
@@unique([readyId, standstillId])
}
If I query:
query Readies($take: Int) {
readies(take: $take) {
id
partenza {
indirizzo
}
intermedi {
order
readyId
standstillId
}
}
}
It works fine with the correct relation on partenza.
However, if I modify the query and add:
standstill {
indirizzo
}
at intermedi and obtain this query:
query Readies($take: Int) {
readies(take: $take) {
id
partenza {
indirizzo
}
intermedi {
order
readyId
standstillId
standstill {
indirizzo
}
}
}
}
I get the following error:
"code": "INTERNAL_SERVER_ERROR",
"stacktrace": [
"NotFoundError: No ReadyIntermedi found",
]
Analysis
In the generated TypeScript resolvers, I found:
@TypeGraphQL.Resolver(_of => ReadyIntermedi)
export class ReadyIntermediRelationsResolver {
@TypeGraphQL.FieldResolver(_type => Ready, {
nullable: false
})
async ready(@TypeGraphQL.Root() readyIntermedi: ReadyIntermedi, @TypeGraphQL.Ctx() ctx: any, @TypeGraphQL.Info() info: GraphQLResolveInfo): Promise<Ready> {
const { _count } = transformInfoIntoPrismaArgs(info);
return getPrismaFromContext(ctx).readyIntermedi.findUniqueOrThrow({
where: {
id: readyIntermedi.id,
},
}).ready({
...(_count && transformCountFieldIntoSelectRelationsCount(_count)),
});
}
@TypeGraphQL.FieldResolver(_type => Standstills, {
nullable: false
})
async standstill(@TypeGraphQL.Root() readyIntermedi: ReadyIntermedi, @TypeGraphQL.Ctx() ctx: any, @TypeGraphQL.Info() info: GraphQLResolveInfo): Promise<Standstills> {
const { _count } = transformInfoIntoPrismaArgs(info);
return getPrismaFromContext(ctx).readyIntermedi.findUniqueOrThrow({
where: {
id: readyIntermedi.id,
},
}).standstill({
...(_count && transformCountFieldIntoSelectRelationsCount(_count)),
});
}
}
This is incorrect. The correct resolvers should be:
@TypeGraphQL.Resolver(_of => ReadyIntermedi)
export class ReadyIntermediRelationsResolver {
@TypeGraphQL.FieldResolver(_type => Ready, {
nullable: false
})
async ready(
@TypeGraphQL.Root() readyIntermedi: ReadyIntermedi,
@TypeGraphQL.Ctx() ctx: any,
@TypeGraphQL.Info() info: GraphQLResolveInfo
): Promise<Ready> {
const { _count } = transformInfoIntoPrismaArgs(info);
return getPrismaFromContext(ctx).ready.findUniqueOrThrow({
where: {
id: readyIntermedi.readyId, // Correct access via readyId
},
...(_count && transformCountFieldIntoSelectRelationsCount(_count)),
});
}
@TypeGraphQL.FieldResolver(_type => Standstills, {
nullable: false
})
async standstill(
@TypeGraphQL.Root() readyIntermedi: ReadyIntermedi,
@TypeGraphQL.Ctx() ctx: any,
@TypeGraphQL.Info() info: GraphQLResolveInfo
): Promise<Standstills> {
const { _count } = transformInfoIntoPrismaArgs(info);
return getPrismaFromContext(ctx).standstills.findUniqueOrThrow({
where: {
id: readyIntermedi.standstillId, // Correct access via standstillId
},
...(_count && transformCountFieldIntoSelectRelationsCount(_count)),
});
}
}
Environment & setup
- OS: Windows
- Database: MongoDB v7.0.9
- Node.js version: v20.10.0
Prisma Version
{
"dependencies": {
"@prisma/client": "^5.18.0",
},
"devDependencies": {
"@types/node": "^20.12.10",
"prisma": "^5.18.0",
"typegraphql-prisma": "^0.28.0",
"typescript": "^5.4.5"
}
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The payload does not name a repository source file or test; start by locating the generator entry point for relation field resolvers and the generated ReadyIntermediRelationsResolver shown in the report. Reproduce the nested standstill query with the supplied Prisma schema and MongoDB setup. Done means the generated resolver handles the relation through the intermediary foreign-key fields and the query no longer raises NotFoundError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, mongodb, typescript
- Domain
- api, backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100