doug-martin / nestjs-query

Easy CRUD for GraphQL.
https://doug-martin.github.io/nestjs-query
MIT License
822 stars 142 forks source link

Assembler's convertAsyncToEntity is not used #376

Open petyunchik opened 4 years ago

petyunchik commented 4 years ago

There is convertAsyncToEntity method declared in Assembler class, but it's not in use anywhere. Would be very useful to make it work similar way as convertAsyncToDTO to perform async transformations.

And thank you for the library!

doug-martin commented 4 years ago

@petyunchik I'm not sure I understand the comment. You can use it if you inject the assembler.

petyunchik commented 4 years ago

@doug-martin Sorry, I mean that AssemblerQueryService is not calling Assembler's convertAsyncToEntity method anywhere. Even if some async logic will be added to convertAsyncToEntity it wouldn't be executed by default AssemblerQueryService.

Fatxx commented 3 years ago

By default, the auto-generated resolver executes convertToDto, if you need to handle async operations on the assembler we need to override the resolver in order to call the convertAsyncToDto which is a bit redundant in my perspective. Why not always call convertAsyncToDto?

This is not ideal, now I have 2 services (MongooseQueryService, AssemblerQueryService), 1 assembler, and 1 custom resolver just to convert a string to another string with an async operation?!

My code:

export class CompaniesService extends AssemblerQueryService<CompanyDTO, Company> {
  constructor(
    readonly assembler: CompaniesAssembler,
    @Inject(CompaniesQueryService) readonly service: CompaniesQueryService,
  ) {
    super(assembler, service);
  }

  async findById(id: string): Promise<CompanyDTO> {
    const company = await this.service.findById(id)
    return this.assembler.convertAsyncToDTO(Promise.resolve(company))
  }
}
@Assembler(CompanyDTO, Company)
export class CompaniesAssembler extends ClassTransformerAssembler<CompanyDTO, Company> {
  constructor(
    @Inject(S3Service) private readonly s3: S3Service
  ) {
    super();
  }

  async convertAsyncToDTO(entity: Promise<Company>): Promise<CompanyDTO> {
    console.log('here???')
    const company = await entity
    const dto = super.convertToDTO(company)

    if (company.logo) {
      dto.logo = await this.s3.getObjectSignedUrl(company?.logo)
    }

    return dto
  }

  async convertAsyncToDTOs(entities: Promise<Company[]>): Promise<CompanyDTO[]> {
    const companies = await entities
    const dtos = await Promise.all(
      companies.map(async company => this.convertAsyncToDTO(Promise.resolve(company)))
    )
    return dtos
  }
}
import { Inject } from '@nestjs/common';
import { Resolver, Query, Args, ArgsType, ObjectType, Mutation, Field, InputType, ResolveField, Parent, ID } from '@nestjs/graphql';
import { CheckPolicies } from '../casl/check-policies.decorator';
import { CompaniesQueryService } from './companies.queryService';
import { CompaniesService } from './companies.service';
import { CompanyDTO } from './dto/company.dto';

@Resolver(() => CompanyDTO)
export class CompanyResolver {
  constructor(
    @Inject(CompaniesQueryService) private readonly queryService: CompaniesQueryService,
    @Inject(CompaniesService) private readonly service: CompaniesService
  ) {}

  @Query(() => CompanyDTO)
  async company(@Args('id', { type: () => ID }) id: string): Promise<CompanyDTO> {
    return this.service.findById(id)
  }
}
const modules = [
  NestjsQueryGraphQLModule.forFeature({
    assemblers: [CompaniesAssembler],
    imports: [
      NestjsQueryMongooseModule.forFeature([
        { document: Company, name: Company.name, schema: CompanySchema },
      ]),
    ],
    services: [CompaniesService, CompaniesQueryService],
    resolvers: [
      {
        ServiceClass: CompaniesService,
        AssemblerClass: CompaniesAssembler,
        DTOClass: CompanyDTO,
        EntityClass: Company,
        CreateDTOClass: CompanyInputDTO,
        create: { decorators: [CheckPolicies(CreateCompanyPolicyHandler)] },
        read: { decorators: [CheckPolicies(ReadCompanyPolicyHandler)] },
        update: { decorators: [CheckPolicies(UpdateCompanyPolicyHandler)] },
        delete: { decorators: [CheckPolicies(DeleteCompanyPolicyHandler)] },
        pagingStrategy: PagingStrategies.OFFSET
      }
    ],
  }),
]
@Module({
  providers: [CompanyResolver],
  imports: modules,
  exports: modules
})
export class CompaniesModule { }
Fatxx commented 3 years ago

@doug-martin

awHamer commented 3 years ago

Same issue like @Fatxx described, I just need to create s3 signed url :(

awHamer commented 3 years ago

@Fatxx How did you managed DI to work in Assembler? Looks like it's impossible, since the class creates by the custom factory https://github.com/doug-martin/nestjs-query/blob/master/packages/core/src/assemblers/assembler.factory.ts