15

I have TypeScript application and I'm using Inversify for IoC.

I have a connection class:

'use strict'; import { injectable } from 'inversify'; import { createConnection, Connection } from "typeorm"; import { Photo, PhotoMetadata, Author, Album } from '../index'; @injectable() class DBConnectionManager { public createPGConnection(): Promise<Connection> { return createConnection({ driver: { type: "postgres", host: "host", port: 5432, username: "username", password: "password", database: "username" }, entities: [ Photo, PhotoMetadata, Author, Album ], autoSchemaSync: true, }); } } export { DBConnectionManager }; 

After I created my connection I want to bind a connection into my container:

kernel.bind<Connection>('DefaultConnection').toConstantValue(getConnectionManager().get()); 

and then I want to inject it into another class:

import { injectable, inject } from 'inversify'; import { Connection, FindOptions } from "typeorm"; import { IGenericRepository, ObjectType } from '../index'; @injectable() class GenericRepository<T> implements IGenericRepository<T> { private connection: Connection; private type: ObjectType<T>; constructor( @inject('DefaultConnection') connection: Connection) { this.connection = connection; } 

So in my container configuration how can I bind DefaultConnection that needs to wait for CreateConnection I can do with async and wait but I'm wonder if there is a cleaner way to achive this in inversify

2 Answers 2

23

Inversify 2.0 includes support for asynchronous factories (AKA Providers)

A provider allows you can to declare a provider as follows:

container.bind<<DbClient>("DbClient").to(DbClientClass); container.bind<interfaces.Provider<DbClient>>("Provider<DbClient>") .toProvider<DbClient>((context) => { return () => { return new Promise<DbClient>((resolve, reject) => { // Create instance let dbClient = context.container.get<DbClient>("DbClient"); // Open DB connection dbClient.initialize("//connection_string") .then(() => { resolve(dbClient); }) .catch((e: Error) => { reject(e); }); }); }; }); 

Then you can inject and consume the provider. The only problem is that it requires two-step initialization: the constructor injection and the async getDb() method.

class UserRepository { private _db: DbClient; private _dbProvider: Provider<DbClient>; // STEP 1 // Inject a provider of DbClient to the constructor public constructor( @inject("Provider<DbClient>") provider: Provider<DbClient> ) { this._dbProvider = provider; } // STEP 2 // Get a DB instance using a provider // Returns a cached DB instance if it has already been created private async getDb() { if (this._db) return this._db; this._db = await this._dbProvider(); return Promise.resolve(this._db); } public async getUser(): Promise<Users[]>{ let db = await this.getDb(); return db.collections.user.get({}); } public async deletetUser(id: number): Promise<boolean>{ let db = await this.getDb(); return db.collections.user.delete({ id: id }); } } 

We are working on a new feature to simplify the injection of asynchronous values. This feature will be included in inversify 3.0:

class UserRepository { // STEP 1 public constructor( @inject("Provider<DbClient>") private provider: Provider<DbClient> ) {} public async getUser(): Promise<Users[]>{ // STEP 2: (No initialization method is required) let db = await this.provider.someFancyNameForProvideValue; return db.collections.user.get({}); } } 
Sign up to request clarification or add additional context in comments.

1 Comment

Is the one phase initialization already implemented? I cannot find any documentation on how to use it
0

Just create connection at application startup and bind already connected instance, usually you don't really need to defer connection.

1 Comment

This would work if your application runs continuously, and the assumption is that all initialization/dependency building is done before the first request comes in. In the case if you are trying to deploy to Serverless Framework, your application doesn't get initialized until the request comes in. This means you will run into timing/race condition. In my case, the IoC container isn't finished setting up and therefore the application ran into runtime error because the dependencies are building while processing the request.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.