TriPSs / nestjs-query

Easy CRUD for GraphQL.
https://tripss.github.io/nestjs-query/
MIT License
159 stars 43 forks source link

how to best import modules to leverage custom services? #206

Closed coupster74 closed 6 months ago

coupster74 commented 11 months ago

Might be a newby question, but I've been fighting with this for a while and didn't see any documentation on the best approach, or if it is even possible.

I have two modules, action, which represents and entity, and clean up which performs clean up functions (like merging a related dimension) for many entities, including action.

In action, I wanted to use soft deletes, so I implemented an ActionService and ActionResolver which extends the CRUDResolver as below:

export class ActionResolver extends CRUDResolver(Action) {
...

with the following module definition:

@Module({
  providers: [ActionResolver, GraphQLClientService],
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      // import the NestjsQueryTypeOrmModule to register the entity with typeorm
      // and provide a QueryService
      imports: [
        NestjsQueryTypeOrmModule.forFeature([Action]),
      ],
      services: [ActionService],
      // describe the resolvers you want to expose
      resolvers: [
        {
          DTOClass: Action,
          EntityClass: Action,
          ServiceClass: ActionService,
          enableAggregate: true,
          enableSubscriptions: true,
          enableTotalCount: true,
        },
      ],
    }),
  ],
})
export class ActionModule {}

In the clean up module, I have been importing the dynamic .forFeature as show below.

@Module({
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      imports: [
        ...
        NestjsQueryTypeOrmModule.forFeature([Action]),
        ... (plus many other .forFeatures)
      ],
    }),
  ],
  providers: [CleanUpResolver],
})
export class CleanUpModule {}

and was importing into the resolver via:

constructor(
@InjectQueryService(Action)
    readonly actionService: QueryService<Action>, 
    ...(plus many other similar statements))

with my custom ActionService, this causes an issue where there are multiple DeleteResponse types for Action:

Error: Schema must contain uniquely named types but contains multiple types named "ActionDeleteResponse". 

I'm assuming this is because both my ActionModule and now the CleanUpModule are both declaring the same types for Action and that the best approach to resolve this is to import the ActionModule into the CleanUpModule so that the ActionService is still usable? Or is this a defect? It's interesting it isn't complaining about other types (but perhaps this is just the first one)?

I can't seem to explicitly export ActionService from the ActionModule, nor does below work in CleanUpModule

    @Inject()
    readonly actionService: ActionService,

as it results in:

Nest can't resolve dependencies of the CleanUpResolver (..., ?, ...). Please make sure that the argument dependency at index [8] is available in the CleanUpModule context.

Potential solutions:
- Is CleanUpModule a valid NestJS module?
- If dependency is a provider, is it part of the current CleanUpModule?
- If dependency is exported from a separate @Module, is that module imported within CleanUpModule?
  @Module({
    imports: [ /* the Module containing dependency */ ]
  }) 
TriPSs commented 11 months ago

I have bit of trouble understanding, but noticed the following: When extending the CrudResolver you should not use the same one with resolvers inside the module, but use dtos instead, see here for more info

Also note that when doing NestjsQueryTypeOrmModule.forFeature you can provide multiple entities at once:

NestjsQueryTypeOrmModule.forFeature([entityOne, entityTwo])