How to handle NestJS Dependency Injection when extending a class for a service? How to handle NestJS Dependency Injection when extending a class for a service? mongoose mongoose

How to handle NestJS Dependency Injection when extending a class for a service?


You can solve this by using a factory approach, try this:

Interface to determine the "shape" of your services:

export interface IDatabaseService {    findOne(id: string): Promise<Cat>;    count(): Promise<number>;    testClass(): void;}

The BaseService must implement that interface:

export class BaseService implements IDatabaseService {    constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {}    async findOne(id: string): Promise<Cat> {        return await this.catModel.findOne({_id: id});    }    async count(): Promise<number> {        return await this.catModel.countDocuments();    }    testClass() {        console.log('BASE SERVICE CLASS USED');    }}

The dynamic services are not injected so they do not use the @Injectable() decorator:

export class OtherService extends BaseService {    constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {        super(catModel);    }    testClass() {        console.log('OTHER SERVICE CLASS USED');    }}export class AnotherService extends BaseService {    constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {        super(catModel);    }    testClass() {        console.log('ANOTHER SERVICE CLASS USED');    }}

The factory class is the thing that gets injected:

@Injectable()export class DatabaseServiceFactory {    constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {}    createService(name: string) : IDatabaseService {        switch(name) {            case 'other': return new OtherService(this.catModel);            case 'another': return new AnotherService(this.catModel);            default: throw new Error(`No service has been implemented for the name "${name}"`);        }    }}
export const catProviders = [    {        provide: 'CatModelToken',        useFactory: (connection: Connection) => connection.model('CAT', CatSchema),        inject: ['DbConnectionToken'],    },    {        provide: 'BaseService',        useFactory: (ConfigService: ConfigService, connection: Connection, dbFactory: DatabaseServiceFactory) => {            const options = ConfigService.get('SERVICE_TYPE');            let model = connection.model('CAT', CatSchema);            //return new BaseService(model).createService(options);            return dbFactory.createService(options);        },        inject: [            ConfigService,            'CatModelToken',            'DbConnectionToken',            DatabaseServiceFactory        ],    }];