扩展服务类时如何处理NestJS依赖注入?

时间:2018-12-14 09:32:09

标签: mongoose dependency-injection subclass extends nestjs

我正在尝试根据我的ConfigService的值提供其他服务。

我遇到的问题是,在执行诸如findOne()(结果为null)或countDocuments()(结果)之类的查询方法时,注入的猫鼬模型不返回任何值。是0)。

我的服务类定义如下:

export class BaseService {
  constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {}

  createService(option: string) {
    if (option === 'OTHER') {
      return new OtherService(this.catModel);
    } else if (option === 'ANOTHER') {
      return new AnotherService(this.catModel);
    } else {
      return new BaseService(this.catModel);
    }
  }

  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');
  }
}

@Injectable()
export class OtherService extends BaseService {
  constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {
    super(catModel);
  }

   testClass() {
    console.log('OTHER SERVICE CLASS USED');
  }
}

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

这使我可以从提供商那里获得正确的服务(testClass()打印出预期的字符串)。我的提供商看起来像这样:

export const catProviders = [
  {
    provide: 'CatModelToken',
    useFactory: (connection: Connection) => connection.model('CAT', CatSchema),
    inject: ['DbConnectionToken'],
  },
  {
    provide: 'BaseService',
    useFactory: (ConfigService: ConfigService, connection: Connection) => {
      const options = ConfigService.get('SERVICE_TYPE');
      let model = connection.model('CAT', CatSchema);
      return new BaseService(model).createService(options);
  },
  inject: [ConfigService, 'CatModelToken', 'DbConnectionToken'],
  }
];

所以我的问题分为两个部分:

  • 是否有更好的方法来处理正确的类,并且 避免必须为鞋底创建一个BaseService实例 呼叫createService()的目的?
  • 将猫鼬模型注入到新创建的服务中的正确方法是什么?

我也不能使用文档中的useClass示例,因为我需要能够注入ConfigService

1 个答案:

答案 0 :(得分:-1)

您可以使用工厂方法解决此问题,请尝试以下操作:

确定服务“形状”的界面:

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

BaseService必须实现该接口:

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');
    }
}

动态服务未注入,因此它们不使用@Injectable()装饰器:

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');
    }
}

工厂类是被注入的东西:

@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
        ],
    }
];