diff --git a/docker-compose.yml b/docker-compose.yml index 66c5a057..a2754ef0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,14 +15,12 @@ services: env_file: - .env common-db: - container_name: common-db + container_name: common_db image: postgres environment: POSTGRES_USER: common_db POSTGRES_PASSWORD: common_db - PGDATA: /data/postgres volumes: - - ./data/db/common/:/data/postgres - ./init.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5432:5432" @@ -33,9 +31,8 @@ services: environment: POSTGRES_USER: tenant-1-db POSTGRES_PASSWORD: tenant-1-db - PGDATA: /data/postgres volumes: - - ./data/db/tenant-1:/data/postgres + - ./tenant_1_data.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5433:5432" restart: unless-stopped @@ -45,9 +42,8 @@ services: environment: POSTGRES_USER: tenant-2-db POSTGRES_PASSWORD: tenant-2-db - PGDATA: /data/postgres volumes: - - ./data/db/tenant-2:/data/postgres + - ./tenant_2_data.sql:/docker-entrypoint-initdb.d/init.sql ports: - "5434:5432" restart: unless-stopped diff --git a/init.sql b/init.sql index 61c7cf5d..6a3f36a0 100644 --- a/init.sql +++ b/init.sql @@ -13,4 +13,3 @@ CREATE TABLE tenants ( INSERT INTO tenants (slug, db_name, db_host, db_username, db_password, db_port) VALUES ('tenant1', 'tenant-1-db', 'tenant-1-db', 'tenant-1-db', 'tenant-1-db', 5433), ('tenant2', 'tenant-2-db', 'tenant-2-db', 'tenant-2-db', 'tenant-2-db', 5434); -view rawblock4.sql hosted with ❤ by GitHub diff --git a/src/index.js b/src/index.js index 0107ae4f..56f640ad 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,8 @@ import express from 'express'; import bodyParser from 'body-parser'; +import * as userService from './services/users'; +import { connectAllDb } from './infra/connectionManager'; +import * as connectionResolver from './middlewares/connectionResolver'; const PORT = 8080; @@ -15,3 +18,12 @@ app.get('/', (req, res) => { app.listen(PORT, () => { console.log(`Express server started at port: ${PORT}`); }); + +app.use(bodyParser.json()); + +connectAllDb(); + +app.use(connectionResolver.resolve); + +app.get('/users', userService.getAll); + diff --git a/src/infra/connectionManager.js b/src/infra/connectionManager.js new file mode 100644 index 00000000..247ed4a7 --- /dev/null +++ b/src/infra/connectionManager.js @@ -0,0 +1,53 @@ +import knex from 'knex'; + +import commonDBConnection from './commonDBConnection'; +import { getNamespace } from 'continuation-local-storage'; + +let connectionMap; + +export const connectAllDb = async () => { + let tenants; + try { + tenants = await commonDBConnection.select('*').from('tenants'); + } catch (e) { + console.log('error', e); + return; + } + connectionMap = + tenants + .map(tenant => { + return { + [tenant.slug]: knex(createConnectionConfig(tenant)) + } + }) + .reduce((prev, next) => { + return Object.assign({}, prev, next); + }, {}); +} + +const createConnectionConfig = (tenant) => { + return { + client: process.env.DB_CLIENT, + connection: { + host: tenant.db_host, + port: tenant.db_port, + user: tenant.db_username, + database: tenant.db_name, + password: tenant.db_password + }, + pool: {min: 2, max: 20} + }; +} + +export const getConnectionBySlug = (slug) => { + return connectionMap ? connectionMap[slug] : null; +} + +export const getConnection = () => { + const nameSpace = getNamespace('unique context'); + const conn = nameSpace.get('connection'); + if (!conn) { + throw 'Connection is not set for any tenant database.'; + } + return conn; +} diff --git a/src/middlewares/connectionResolver.js b/src/middlewares/connectionResolver.js new file mode 100644 index 00000000..49434885 --- /dev/null +++ b/src/middlewares/connectionResolver.js @@ -0,0 +1,19 @@ +import { createNamespace } from 'continuation-local-storage'; + +import { getConnectionBySlug } from '../infra/connectionManager'; + + +let nameSpace = createNamespace('unique context'); + + +export const resolve = (req, res, next) => { + const slug = req.query.slug; + if (!slug) { + res.json({ message: `Please provide tenant's slug to connect.` }); + return; + } + nameSpace.run(() => { + nameSpace.set('connection', getConnectionBySlug(slug)); + next(); + }); +} diff --git a/src/services/users.js b/src/services/users.js new file mode 100644 index 00000000..ccc7b7b7 --- /dev/null +++ b/src/services/users.js @@ -0,0 +1,5 @@ +import {getConnection} from '../infra/connectionManager'; + +export const getAll = async (req, res) => { + res.json({body: await getConnection().select('*').from('users')}); +} diff --git a/tenant_1_data.sql b/tenant_1_data.sql new file mode 100644 index 00000000..54217c77 --- /dev/null +++ b/tenant_1_data.sql @@ -0,0 +1,10 @@ +CREATE TABLE users( + id INT PRIMARY KEY, + first_name VARCHAR(255) NOT NULL, + last_name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + address VARCHAR(400) +); + +INSERT INTO users(id,first_name, last_name, email, address) VALUES + (1,'Kevin', 'Martins', 'kevinmmartins@gmail.com', 'BR'); diff --git a/tenant_2_data.sql b/tenant_2_data.sql new file mode 100644 index 00000000..33b84f48 --- /dev/null +++ b/tenant_2_data.sql @@ -0,0 +1,10 @@ +CREATE TABLE users( + id INT PRIMARY KEY, + first_name VARCHAR(255) NOT NULL, + last_name VARCHAR(255) NOT NULL, + email VARCHAR(255) NOT NULL, + address VARCHAR(400) +); + +INSERT INTO users(id,first_name, last_name, email, address) VALUES + (1,'Kauan', 'Martins', 'kauanmmartins@egmail.com', 'USA');