import { Query , DeleteManyResponse , UpdateManyResponse , DeepPartial , QueryService , Filter , AggregateQuery , AggregateResponse , FindByIdOptions , GetByIdOptions , UpdateOneOptions , DeleteOneOptions , } from '@nestjs-query/core' ; import lodashPick from 'lodash.pick' ; import { Model , ModelCtor } from 'sequelize-typescript' ; import { WhereOptions } from 'sequelize' ; import { NotFoundException } from '@nestjs/common' ; import { FilterQueryBuilder , AggregateBuilder } from '../query' ; import { RelationQueryService } from './relation-query.service' ; example QueryService InjectRepository export class SequelizeQueryService < Entity extends Model < Entity , Partial < Entity > > > extends RelationQueryService < Entity > implements QueryService < Entity , DeepPartial < Entity > , DeepPartial < Entity > > { readonly filterQueryBuilder : FilterQueryBuilder < Entity > ; constructor ( readonly model ) { super ( ) ; this . filterQueryBuilder = new FilterQueryBuilder < Entity > ( model ) ; } example param query async query ( query ) { return this . model . findAll < Entity > ( this . filterQueryBuilder . findOptions ( query ) ) ; } async aggregate ( filter , aggregate ) { const result = await this . model . findAll ( this . filterQueryBuilder . aggregateOptions ( { filter } , aggregate ) ) ; if ( ! result ) { return [ { } ] ; } return AggregateBuilder . convertToAggregateResponse ( result as unknown as Record < string , unknown > [ ] ) ; } async count ( filter ) { return this . model . count ( this . filterQueryBuilder . countOptions ( { filter } ) ) ; } example param id param opts async findById ( id , opts ? ) { const model = await this . model . findOne < Entity > ( this . filterQueryBuilder . findByIdOptions ( id , opts ?? { } ) ) ; if ( ! model ) { return undefined ; } return model ; } example param id param opts async getById ( id , opts ? ) { const entity = await this . findById ( id , opts ?? { } ) ; if ( ! entity ) { throw new NotFoundException ( `Unable to find ${ this . model . name } with id: ${ id }` ) ; } return entity ; } example param record async createOne ( record ) { await this . ensureEntityDoesNotExist ( record ) ; return this . model . create < Entity > ( this . getChangedValues ( record ) ) ; } example param records async createMany ( records ) { await Promise . all ( records . map ( ( r ) => this . ensureEntityDoesNotExist ( r ) ) ) ; return this . model . bulkCreate < Entity > ( records . map ( ( r ) => this . getChangedValues ( r ) ) ) ; } example param id param update param opts async updateOne ( id , update , opts ? ) { this . ensureIdIsNotPresent ( update ) ; const entity = await this . getById ( id , opts ) ; return entity . update ( this . getChangedValues ( update ) ) ; } example param update param filter async updateMany ( update , filter ) { this . ensureIdIsNotPresent ( update ) ; const [ count ] = await this . model . update ( this . getChangedValues ( update ) , this . filterQueryBuilder . updateOptions ( { filter } ) ) ; return { updatedCount : count } ; } example param id param opts async deleteOne ( id , opts ? ) { const entity = await this . getById ( id , opts ) ; await entity . destroy ( ) ; return entity ; } example param filter async deleteMany ( filter ) { const deletedCount = await this . model . destroy ( this . filterQueryBuilder . destroyOptions ( { filter } ) ) ; return { deletedCount : deletedCount || 0 } ; } private getChangedValues ( record ) { if ( record instanceof this . model ) { const recordEntity = record as unknown as Entity ; const raw = recordEntity . get ( { plain : true } ) ; const changed = recordEntity . changed ( ) ; if ( changed === false ) { return { } ; } return lodashPick ( raw , changed ) ; } return record ; } private async ensureEntityDoesNotExist ( e ) { const pks = this . primaryKeyValues ( e ) ; if ( Object . keys ( pks ) . length ) { const found = await this . model . findOne ( { where : pks } ) ; if ( found ) { throw new Error ( 'Entity already exists' ) ; } } } private ensureIdIsNotPresent ( e ) { if ( Object . keys ( this . primaryKeyValues ( e ) ) . length ) { throw new Error ( 'Id cannot be specified when updating' ) ; } } private primaryKeyValues ( e ) { const changed = this . getChangedValues ( e ) as Partial < Entity > ; return this . model . primaryKeyAttributes . reduce ( ( pks , pk ) => { const key = pk as keyof Entity ; if ( key in changed && changed [ key ] !== undefined ) { return { ... pks , [ pk ] : changed [ key ] } as WhereOptions ; } return pks ; } , { } as WhereOptions ) ; } }