nestjs-query
nestjs-query copied to clipboard
Nested DTO Relations are not generated into GraphQL SDL
Describe the bug When using any of the Relations decorators on a nested DTO, the corresponding SDL is not generated.
Have you read the Contributing Guidelines?
Yes
To Reproduce Steps to reproduce the behavior:
- Create these two DTOs
- Add DTOs to a module
dtos: [ { DTOClass: RelationTestDTO, CreateDTOClass: CreateRelationTestDTO, UpdateDTOClass: UpdateRelationTestDTO }, ],
- Boot API and inspect Playground Docs
Expected behavior I should be able to add any of the Relations decorators onto a nested DTO and have those properties/fields added to the GraphQL Type
Screenshots
Desktop (please complete the following information):
- Node Verson:
14.8.0
- Nestjs-query Version:
0.23.0
- Nestjs-query/query-graphql:
^0.23.0
@conor-odro can you share what the module file look like for NestedDTO? I'm guessing something is missing in there.
Hey @doug-martin, thanks for getting back to me
Here is a copy of the RelationTest
module
import { NestjsQueryGraphQLModule } from '@nestjs-query/query-graphql';
import { NestjsQueryTypeOrmModule } from '@nestjs-query/query-typeorm';
import { Module } from '@nestjs/common';
import { RelationTestDTO, CreateRelationTestDTO, UpdateRelationTestDTO } from './application/dtos/RelationTest.dto';
import { RelationTestResolver } from './application/RelationTest.resolver';
import { RelationTestAssembler } from './assemblers/RelationTest.assembler';
import { RelationTestService } from './domain/services/RelationTest.service';
import { RelationTestEntity } from './repository/entities/RelationTest.entity';
const NestJsRelationTestModule = NestjsQueryTypeOrmModule.forFeature([RelationTestEntity]);
@Module({
imports: [
NestjsQueryGraphQLModule.forFeature({
imports: [NestJsRelationTestModule],
services: [RelationTestService],
resolvers: [],
assemblers: [RelationTestAssembler],
dtos: [
{ DTOClass: RelationTestDTO, CreateDTOClass: CreateRelationTestDTO, UpdateDTOClass: UpdateRelationTestDTO },
],
}),
NestJsRelationTestModule,
],
providers: [RelationTestService, RelationTestResolver],
exports: [RelationTestService, NestJsRelationTestModule],
})
export class RelationTestModule {}
Do you have a resolver for NestedDTO
? Internally we rely on the @ResolveField
resolver implementation to add the relations example from nest. If you use an auto generated resolver for NestedDTO
(you can turn off create, read, update, delete to disable any root queries or mutations if you just want it to be a relation) your relations should start showing up.
I hope this helps, if you have a resolver already defined for NestedDTO
if you could share that and the module I can take a look at those also.
Ahh ok that makes more sense! I've not got a resolver for NestedDTO
, only one for RelationTestDTO
.
I've attempted to use an auto-generated resolver by adding the following line to my RelationTestModule
but I seem to be getting Error: No fields found to create GraphQLFilter for NestedDTO
, even though I've definitely got an @Field
decorator on the field
property?
resolvers: [{ DTOClass: NestedDTO, EntityClass: NestedEntity }],
@conor-odro this is a known issue that I have not gotten around to fixing yet as most DTOs will have a @FilterableField
on them. If you just add the @FilterableField
instead of @Field
it should work as expected.
@doug-martin Ahh thank you, that seems to have helped!
After the above change I was getting the error Error: Nest can't resolve dependencies of the NestedDTOAutoResolver (?, pub_sub). Please make sure that the argument NestedEntityQueryService at index [0] is available in the NestjsQueryGraphQLModule context
, which I believe is due to the NestedEntity
not being added to the NestjsQueryTypeOrmModule.forFeature()
call?
I then ended up getting a new error RepositoryNotFoundError: No repository for "NestedEntity" was found.
, which I believe is simply due to not having the @Entity()
decorator on the NestedEntity
class. Once these changes were made I started seeing the relations appear in the GraphQL Playground.
However going down this route seems to require the NestedEntity
to actually have it's own database table, which is another stumbling block as we were planning on having the NestedEntity
actually be a JSONB column in the RelationTest table.
@Injectable()
@Entity('relationTest')
export class RelationTestEntity {
// Store our NestedEntity data in JSONB
@Column('jsonb', {
nullable: false,
default: {},
})
nested: NestedEntity;
}
I believe to achieve this I would have to create a custom resolver for the NestedDTO
and implement my own @FieldResolver
(s) which were responsible for handling CRUD operations on the JSONB column, is that correct?
@conor-odro I think a combination of RelationQueryService and NoOpQueryService could work for this and then you could just set your ServiceClass
option
Something like
import { InjectQueryService, QueryService, RelationQueryService, NoOpQueryService } from '@nestjs-query/core';
import { ARelationEntity } from './a-relation.entity';
import { BRelationEntity } from './b-relation.entity';
@Injectable()
export class NestedDTOService extends RelationQueryService<NestedDTO> {
constructor(
@InjectQueryService(ARelationEntity) aQueryService: QueryService<ARelationEntity>,
@InjectQueryService(BRelationEntity) bQueryService: QueryService<BRelationEntity>,
) {
// provide the NoOpQueryService which will throw a NotImplemented for any query, update, create, or delete invocations.
super(NoOpQueryService.getInstance(), {
aRelation: {
// provide the service that will be used to query the relation
service: aQueryService,
query(nestedDTO) {
// filter for all relations that belong to the todoItem and are completed
return { filter: { /*create your filter to fetch the right relations*/ } };
},
},
bRelation: {
// provide the service that will be used to query the relation
service: bQueryService,
query(nestedDTO) {
// filter for all relations that belong to the todoItem and are completed
return { filter: { /*create your filter to fetch the right relations*/ } };
},
},
});
}
}
@conor-odro this is a known issue that I have not gotten around to fixing yet as most DTOs will have a
@FilterableField
on them. If you just add the@FilterableField
instead of@Field
it should work as expected.
Hey, I have a similar problem and I can't really change the DTO as it is coming from another package that uses nestjs-graphql and typeorm but not nestjs-query :(. Any plans of making it possible to use such an class in ther dtos
array that potentially will have no @FilterableFields
defined?
@wowczarczyk I'm looking into this now, the main limitation will be aggregates
, filtering
and sorting
will not be available.
I think the only safe endpoints to enable would be createOne
, createMany
, deleteOne
, updateOne
, findOne
, and query
with just paging. In short endpoints that require filters would be disabled.
I haven't run into this use case before so any feedback would be appreciated.
My use case involves using DTO files from another module (that is not using nestjs-query) to satisfy the relations of DTOs from a module that uses nestjs-query.