Skip to content

Instantly share code, notes, and snippets.

@miyu4u
Last active January 23, 2020 13:24
Show Gist options
  • Save miyu4u/ebbe59e4ed173280ab14d26169242150 to your computer and use it in GitHub Desktop.
Save miyu4u/ebbe59e4ed173280ab14d26169242150 to your computer and use it in GitHub Desktop.
NestJs TypeOrm create MultiTenant Connection at runtime Example (Multiple DB, Multiple Schema)

NestJs TypeOrm MultiTenant Connection Example

This is implement Example of This stackoverflow Answers

How Things

TypeOrm basic config in NestJs is singleton. but, For using MultiTenancy database structure, It's Scope should be REQUEST or TRANSIENT.

Reference : https://docs.nestjs.com/fundamentals/injection-scopes https://docs.nestjs.com/fundamentals/custom-providers#factory-providers-usefactory

When user come to Controller, controller and service instance is made. then service find 'injected' 'CONNECTION'

'CONNECTION' is provided globally from tenancy module, connectionFactory make connection for condition, and passing it to service.

If you know Better way to using multi Tenancy Database structure at Nestjs, Please tell me!

import { Controller, Scope } from '@nestjs/common';
import { Crud } from '@nestjsx/crud';
import { Heros } from '../entity/heros.entity';
import { HerosService } from './heros.service';
@Crud({
model: {
type: Heros
}
})
@Controller({
path:'heros',
scope: Scope.REQUEST,
})
export class HerosController {
constructor(public service: HerosService) {}
}
import { Module } from '@nestjs/common';
import { HerosService } from './heros.service';
import { HerosController } from './heros.controller';
@Module({
providers: [HerosService],
controllers: [HerosController]
})
export class HerosModule {}
import { Injectable, Inject, Scope } from '@nestjs/common';
import {TypeOrmCrudService} from '@nestjsx/crud-typeorm';
import { Heros } from '../entity/heros.entity';
import { Connection } from 'typeorm';
@Injectable({
scope:Scope.REQUEST
})
export class HerosService extends TypeOrmCrudService<Heros>{
constructor(@Inject('CONNECTION') connection: Connection) {
const repo = connection.getRepository(Heros);
super(repo);
}
}
import { Scope, Global, Module } from '@nestjs/common';
import { getConnection, createConnection, ConnectionOptions, getConnectionOptions} from 'typeorm';
import { REQUEST, ModulesContainer } from '@nestjs/core';
import { Request } from 'express';
import 'lodash';
import _ = require('lodash');
const optionFactory = (database: string, schema: string): ConnectionOptions => {
const name = `${database}_${schema}`;
const port = database == 'subdb01' ? 32769 : 32771
return {
name,
type: 'mysql',
host: '',
port,
username: 'root',
password: 'password',
database: schema,
entities: ['dist/**/*.entity{.ts,.js}'],
synchronize: false,
};
};
const connector = async (options:ConnectionOptions) => {
let connection;
try {
connection = await getConnection(options.name);
} catch (error) {
connection = await createConnection(options);
}
return connection;
};
const connectionFactory = {
provide: 'CONNECTION',
scop: Scope.REQUEST,
useFactory: async (req: Request) => {
const db = _.sample(['subdb01','subdb02']);
const schema = _.sample(['data1','data2']);
const options = optionFactory(db,schema)
return await connector(options);
},
inject: [REQUEST],
};
@Global()
@Module({
providers: [connectionFactory],
exports: ['CONNECTION'],
})
export class TenancyModule {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment