UNPKG

multibridge

Version:

A multi-database connection framework with centralized configuration

202 lines (201 loc) 9.44 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getConnection = getConnection; exports.closeConnection = closeConnection; exports.closeAllConnections = closeAllConnections; const dbConfig_1 = require("../config/dbConfig"); const tenantContext_1 = require("../context/tenantContext"); const postgres_1 = require("./postgres"); const mysql_1 = require("./mysql"); const mongodb_1 = require("./mongodb"); const cassandra_1 = require("./cassandra"); const loggers_1 = __importDefault(require("../utils/loggers")); const connectionCache = new Map(); function generateCacheKey(appid, orgid, appdbname) { return `${appid}-${orgid}-${appdbname}`; } function isSQLConnectionValid(connection) { return __awaiter(this, void 0, void 0, function* () { try { yield connection.query("SELECT 1"); return true; } catch (error) { return false; } }); } /** * Retrieves a tenant-specific connection. * Checks the cache for an existing connection and validates it. * If the cached connection is stale or missing, creates a new connection. */ function getConnection(tenant) { return __awaiter(this, void 0, void 0, function* () { const currentTenant = tenant || (0, tenantContext_1.getTenant)(); if (!currentTenant) { throw new Error("No tenant context available"); } const { appid, orgid, appdbname } = currentTenant; const cacheKey = generateCacheKey(appid, orgid, appdbname); // Check if a connection is cached if (connectionCache.has(cacheKey)) { const cached = connectionCache.get(cacheKey); if (cached.dbType === "postgres" || cached.dbType === "mysql") { // Check if the SQL connection is still healthy const valid = yield isSQLConnectionValid(cached.connection); if (valid) { loggers_1.default.info(`[MultiBridge] Reusing valid connection for ${cacheKey}`); return cached; } else { loggers_1.default.warn(`[MultiBridge] Cached SQL connection for ${cacheKey} is stale. Recreating connection.`); connectionCache.delete(cacheKey); } } else { // For MongoDB and Cassandra, we assume the connection is valid (you can add health checks as needed) loggers_1.default.info(`[MultiBridge] Reusing connection for ${cacheKey}`); return cached; } } // No valid cached connection; fetch configuration from central DB const dbConfig = yield (0, dbConfig_1.fetchDBConfig)(appid, orgid); if (!dbConfig) { throw new Error(`No configuration found for appid: ${appid}, orgid: ${orgid}`); } // Use tenant.appdbname if provided; otherwise, use the default schema from config const schema = appdbname || dbConfig.schema; let connection; const dbType = dbConfig.db_type; try { switch (dbType) { case "postgres": connection = yield (0, postgres_1.createPostgresConnection)({ host: dbConfig.host, port: dbConfig.port, username: dbConfig.username, password: dbConfig.password, database: dbConfig.database, schema, }); break; case "mysql": connection = yield (0, mysql_1.createMySQLConnection)({ host: dbConfig.host, port: dbConfig.port, username: dbConfig.username, password: dbConfig.password, database: dbConfig.database, schema, }); break; case "mongodb": connection = yield (0, mongodb_1.createMongoDBConnection)({ host: dbConfig.host, port: dbConfig.port, username: dbConfig.username, password: dbConfig.password, database: dbConfig.database, }); break; case "cassandra": connection = yield (0, cassandra_1.createCassandraConnection)({ host: dbConfig.host, port: dbConfig.port, username: dbConfig.username, password: dbConfig.password, database: dbConfig.database, dataCenter: dbConfig.data_center, }); break; default: throw new Error(`Unsupported database type: ${dbConfig.db_type}`); } } catch (error) { loggers_1.default.error(`Error creating connection for ${cacheKey}: ${error.message}`); throw error; } const ret = { connection, dbType, config: { schema } }; connectionCache.set(cacheKey, ret); loggers_1.default.info(`[MultiBridge] Created new connection for ${cacheKey}`); return ret; }); } function closeConnection(tenant) { return __awaiter(this, void 0, void 0, function* () { const currentTenant = tenant || (0, tenantContext_1.getTenant)(); if (!currentTenant) return; const cacheKey = generateCacheKey(currentTenant.appid, currentTenant.orgid, currentTenant.appdbname); if (connectionCache.has(cacheKey)) { const { connection, dbType } = connectionCache.get(cacheKey); if (connection) { try { if ((dbType === "postgres" || dbType === "mysql") && connection.end) { yield connection.end(); loggers_1.default.info(`[MultiBridge] SQL connection closed for ${cacheKey}`); } else if (dbType === "mongodb" && connection.close) { yield connection.close(); loggers_1.default.info(`[MultiBridge] MongoDB connection closed for ${cacheKey}`); } else if (dbType === "cassandra" && connection.shutdown) { yield connection.shutdown(); loggers_1.default.info(`[MultiBridge] Cassandra connection closed for ${cacheKey}`); } else { loggers_1.default.warn(`[MultiBridge] Unknown DB type or close method missing for ${cacheKey}`); } } catch (error) { loggers_1.default.error(`Error closing connection for ${cacheKey}: ${error.message}`); } } connectionCache.delete(cacheKey); } }); } function closeAllConnections() { return __awaiter(this, void 0, void 0, function* () { for (const [cacheKey, { connection, dbType }] of connectionCache.entries()) { if (connection) { try { if ((dbType === "postgres" || dbType === "mysql") && connection.end) { yield connection.end(); loggers_1.default.info(`[MultiBridge] SQL connection closed for ${cacheKey}`); } else if (dbType === "mongodb" && connection.close) { yield connection.close(); loggers_1.default.info(`[MultiBridge] MongoDB connection closed for ${cacheKey}`); } else if (dbType === "cassandra" && connection.shutdown) { yield connection.shutdown(); loggers_1.default.info(`[MultiBridge] Cassandra connection closed for ${cacheKey}`); } else { loggers_1.default.warn(`[MultiBridge] Unknown DB type or close method missing for ${cacheKey}`); } } catch (error) { loggers_1.default.error(`Error closing connection for ${cacheKey}: ${error.message}`); } } } connectionCache.clear(); loggers_1.default.info("[MultiBridge] All connections closed."); }); }