import { Query , DeleteManyResponse , UpdateManyResponse , DeepPartial , Class , QueryService , Filter , AggregateQuery , AggregateResponse , FindByIdOptions , GetByIdOptions , UpdateOneOptions , DeleteOneOptions , Filterable , } from '@nestjs-query/core' ; import { Repository , DeleteResult } from 'typeorm' ; import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity' ; import { MethodNotAllowedException , NotFoundException } from '@nestjs/common' ; import { FilterQueryBuilder , AggregateBuilder } from '../query' ; import { RelationQueryService } from './relation-query.service' ; export interface TypeOrmQueryServiceOpts < Entity > { useSoftDelete ? : boolean ; filterQueryBuilder ? : FilterQueryBuilder < Entity > ; } example QueryService InjectRepository export class TypeOrmQueryService < Entity > extends RelationQueryService < Entity > implements QueryService < Entity , DeepPartial < Entity > , DeepPartial < Entity > > { readonly filterQueryBuilder : FilterQueryBuilder < Entity > ; readonly useSoftDelete : boolean ; constructor ( readonly repo , opts ? ) { super ( ) ; this . filterQueryBuilder = opts ?. filterQueryBuilder ?? new FilterQueryBuilder < Entity > ( this . repo ) ; this . useSoftDelete = opts ?. useSoftDelete ?? false ; } get EntityClass ( ) : Class < Entity > { return this . repo . target as Class < Entity > ; } example param query async query ( query ) { return this . filterQueryBuilder . select ( query ) . getMany ( ) ; } async aggregate ( filter , aggregate ) { return AggregateBuilder . asyncConvertToAggregateResponse ( this . filterQueryBuilder . aggregate ( { filter } , aggregate ) . getRawMany < Record < string , unknown > > ( ) ) ; } async count ( filter ) { return this . filterQueryBuilder . select ( { filter } ) . getCount ( ) ; } example param id async findById ( id , opts ? ) { return this . filterQueryBuilder . selectById ( id , opts ?? { } ) . getOne ( ) ; } example param id async getById ( id , opts ? ) { const entity = await this . findById ( id , opts ) ; if ( ! entity ) { throw new NotFoundException ( `Unable to find ${ this . EntityClass . name } with id: ${ id }` ) ; } return entity ; } example param record async createOne ( record ) { const entity = await this . ensureIsEntityAndDoesNotExist ( record ) ; return this . repo . save ( entity ) ; } example param records async createMany ( records ) { const entities = await Promise . all ( records . map ( ( r ) => this . ensureIsEntityAndDoesNotExist ( r ) ) ) ; return this . repo . save ( entities ) ; } example param id param update param opts async updateOne ( id , update , opts ? ) { this . ensureIdIsNotPresent ( update ) ; const entity = await this . getById ( id , opts ) ; return this . repo . save ( this . repo . merge ( entity , update ) ) ; } example param update param filter async updateMany ( update , filter ) { this . ensureIdIsNotPresent ( update ) ; const updateResult = await this . filterQueryBuilder . update ( { filter } ) . set ( { ... ( update as QueryDeepPartialEntity < Entity > ) } ) . execute ( ) ; return { updatedCount : updateResult . affected || 0 } ; } example param id param filter async deleteOne ( id , opts ? ) { const entity = await this . getById ( id , opts ) ; if ( this . useSoftDelete ) { return this . repo . softRemove ( entity ) ; } return this . repo . remove ( entity ) ; } example param filter async deleteMany ( filter ) { let deleteResult ; if ( this . useSoftDelete ) { deleteResult = await this . filterQueryBuilder . softDelete ( { filter } ) . execute ( ) ; } else { deleteResult = await this . filterQueryBuilder . delete ( { filter } ) . execute ( ) ; } return { deletedCount : deleteResult . affected || 0 } ; } example param id param opts async restoreOne ( id , opts ? ) { this . ensureSoftDeleteEnabled ( ) ; await this . repo . restore ( id ) ; return this . getById ( id , opts ) ; } example param filter async restoreMany ( filter ) { this . ensureSoftDeleteEnabled ( ) ; const result = await this . filterQueryBuilder . softDelete ( { filter } ) . restore ( ) . execute ( ) ; return { updatedCount : result . affected || 0 } ; } private async ensureIsEntityAndDoesNotExist ( e ) { if ( ! ( e instanceof this . EntityClass ) ) { return this . ensureEntityDoesNotExist ( this . repo . create ( e ) ) ; } return this . ensureEntityDoesNotExist ( e ) ; } private async ensureEntityDoesNotExist ( e ) { if ( this . repo . hasId ( e ) ) { const found = await this . repo . findOne ( this . repo . getId ( e ) ) ; if ( found ) { throw new Error ( 'Entity already exists' ) ; } } return e ; } private ensureIdIsNotPresent ( e ) { if ( this . repo . hasId ( e as unknown as Entity ) ) { throw new Error ( 'Id cannot be specified when updating' ) ; } } private ensureSoftDeleteEnabled ( ) { if ( ! this . useSoftDelete ) { throw new MethodNotAllowedException ( `Restore not allowed for non soft deleted entity ${ this . EntityClass . name }.` ) ; } } }