nestjs-knex icon indicating copy to clipboard operation
nestjs-knex copied to clipboard

Multi tenant connections

Open Zyles opened this issue 2 years ago • 0 comments

Hi,

I use this module and it works great, but I am stuck on how to do multi tenant dynamic connections based on Scope.REQUEST.

I managed to make two connections using two KnexModule.forRootAsync but I am unsure how I can dynamically create the connection upon API request to connect to another DB.

I store all my tenant connection details in a master DB and connect to:

imports: [
    KnexModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        config: {
          client: configService.get('db_master.type'),
          useNullAsDefault: true,
          connection: {
            host: configService.get('db_master.host'),
            database: configService.get('db_master.database'),
            user: configService.get('db_master.username'),
            password: configService.get('db_master.password'),
            port: configService.get('db_master.port'),
            ssl: { rejectUnauthorized: false },
          },
          pool: {
            min: 0,
            max: 5,
            acquireTimeoutMillis: 60000,
            idleTimeoutMillis: 600000,
            afterCreate: (conn: any, done: any) => {
              conn.query('SELECT version();', (err: any, result: any) => {
                console.log('Connected to master database:', configService.get('db_master.database'))
                done()
              })
            },
          },
        },
      }),
      inject: [ConfigService],
    },
    'MASTER_CONNECTION'),
  ]

And in my TenantService I use:

export class TenantService {
  constructor(
    @InjectKnex('MASTER_CONNECTION') private readonly db: Knex,
  ) {}
...

With this connection I can go into the tenant table in the master DB and get the connection details to all tenants. Eventually I will load it into a Redis instance.

Now the problem when calling a Scope.REQUEST service I need to get the tenant ID either from header or resolve the user and create another dynamic connection.

So I need to create a TENANT_CONNECTION which can somehow be dynamic and use it in my "ProductService":

export class ProductService {
  constructor(
    @InjectKnex('TENANT_CONNECTION') private readonly db: Knex,
  ) {}
...

Any tips?

Thanks.

Zyles avatar Jun 10 '22 23:06 Zyles