multibridge
Version:
A multi-database connection framework with centralized configuration
159 lines (158 loc) • 5.95 kB
JavaScript
;
/**
* TypeORM adapter for MultiBridge
* Supports: PostgreSQL, MySQL, MongoDB, Cassandra
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTypeORMDataSource = getTypeORMDataSource;
exports.closeTypeORMDataSource = closeTypeORMDataSource;
exports.closeAllTypeORMDataSources = closeAllTypeORMDataSources;
const typeorm_1 = require("typeorm");
const base_1 = require("./base");
const loggers_1 = __importDefault(require("../utils/loggers"));
const errors_1 = require("../utils/errors");
// Cache for TypeORM DataSource instances per tenant
const typeormDataSources = new Map();
/**
* Get or create a TypeORM DataSource for the current tenant
*
* @param options - TypeORM DataSource options (entities, migrations, etc.)
* @returns TypeORM DataSource instance configured for the current tenant
*
* @example
* ```typescript
* await runWithTenant(tenant, async () => {
* const dataSource = await getTypeORMDataSource({
* entities: [User, Order],
* });
* const userRepo = dataSource.getRepository(User);
* await userRepo.find();
* });
* ```
*/
async function getTypeORMDataSource(options) {
const { tenant, connectionData, dbType } = await (0, base_1.getTenantConnection)();
// Validate database type
(0, base_1.validateORMSupport)(dbType, ["postgres", "mysql", "mongodb", "cassandra"]);
const cacheKey = `${tenant.appid}-${tenant.orgid}-${tenant.appdbname}`;
// Check cache
const cached = typeormDataSources.get(cacheKey);
if (cached && cached.isInitialized) {
loggers_1.default.debug(`Reusing cached TypeORM DataSource for ${cacheKey}`);
return cached;
}
// Get database configuration for connection details
const { dbConfig } = await (0, base_1.getTenantDBConfig)();
// Build DataSource options based on database type
let dataSourceOptions;
if (dbType === "postgres") {
const schema = connectionData.config?.schema || tenant.appdbname;
dataSourceOptions = {
type: "postgres",
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: dbConfig.database,
schema: schema,
extra: {
...options?.extra,
},
synchronize: false, // Never auto-sync in production
logging: options?.logging || false,
...options,
};
}
else if (dbType === "mysql") {
const database = tenant.appdbname;
dataSourceOptions = {
type: "mysql",
host: dbConfig.host,
port: dbConfig.port,
username: dbConfig.username,
password: dbConfig.password,
database: database,
extra: {
...options?.extra,
},
synchronize: false,
logging: options?.logging || false,
...options,
};
}
else if (dbType === "mongodb") {
const database = tenant.appdbname;
// Build MongoDB connection string
let mongoUrl;
if (dbConfig.host.endsWith(".mongodb.net")) {
// MongoDB Atlas (Cluster) using SRV
mongoUrl = `mongodb+srv://${dbConfig.username}:${dbConfig.password}@${dbConfig.host}/${database}?authSource=admin`;
}
else {
// Self-hosted MongoDB (Local/Remote)
mongoUrl = `mongodb://${dbConfig.username}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/${database}?authSource=admin`;
}
dataSourceOptions = {
type: "mongodb",
url: mongoUrl,
database: database,
synchronize: false,
logging: options?.logging || false,
...options,
};
}
else if (dbType === "cassandra") {
// TypeORM doesn't natively support Cassandra
// This would require a custom driver
throw new errors_1.ConnectionError("TypeORM does not natively support Cassandra. Consider using the Cassandra driver directly or a Cassandra-specific ORM.", { dbType });
}
else {
throw new errors_1.ConnectionError(`Unsupported database type for TypeORM: ${dbType}`, {
dbType,
});
}
// Create and initialize DataSource
const dataSource = new typeorm_1.DataSource(dataSourceOptions);
if (!dataSource.isInitialized) {
await dataSource.initialize();
}
// Cache the instance
typeormDataSources.set(cacheKey, dataSource);
loggers_1.default.info(`Created TypeORM DataSource for ${cacheKey}`, {
dbType,
schema: connectionData.config?.schema,
});
return dataSource;
}
/**
* Close TypeORM DataSource for a specific tenant
*/
async function closeTypeORMDataSource(tenant) {
if (!tenant) {
const { tenant: currentTenant } = await (0, base_1.getTenantConnection)();
tenant = currentTenant;
}
const cacheKey = `${tenant.appid}-${tenant.orgid}-${tenant.appdbname}`;
const dataSource = typeormDataSources.get(cacheKey);
if (dataSource && dataSource.isInitialized) {
await dataSource.destroy();
typeormDataSources.delete(cacheKey);
loggers_1.default.debug(`Closed TypeORM DataSource for ${cacheKey}`);
}
}
/**
* Close all TypeORM DataSources
*/
async function closeAllTypeORMDataSources() {
const closePromises = Array.from(typeormDataSources.values())
.filter((ds) => ds.isInitialized)
.map((ds) => ds.destroy().catch((error) => {
loggers_1.default.warn(`Error closing TypeORM DataSource: ${error.message}`);
}));
await Promise.all(closePromises);
typeormDataSources.clear();
loggers_1.default.info("All TypeORM DataSources closed");
}