multibridge
v1.1.0
Published
A multi-database connection framework with centralized configuration
Maintainers
Readme
MultiBridge
MultiBridge is a powerful multi-tenant database connection framework that supports PostgreSQL, MySQL, MongoDB, and Cassandra. It provides a unified interface for managing tenant-specific database connections with automatic routing, connection pooling, caching, and ORM integration.
✨ Features
Core Capabilities
- 🏢 Multi-tenant database connection management with automatic tenant routing
- 🗄️ Multi-database support: PostgreSQL, MySQL, MongoDB, and Cassandra
- 🔄 Connection pooling with configurable pool sizes
- 💾 LRU connection caching with TTL for optimal performance
- 🔒 Tenant context management using
AsyncLocalStorage - ⚡ Eager connection establishment for better performance
- 🔐 SQL injection prevention with automatic sanitization
- ⏱️ Query timeouts with configurable timeouts per database type
- 🔁 Automatic retry logic with exponential backoff
- 🚦 Rate limiting to prevent connection exhaustion
ORM Integration
- 🔌 Sequelize adapter for PostgreSQL and MySQL
- 🔌 TypeORM adapter for PostgreSQL, MySQL, and MongoDB
- 🔌 Mongoose adapter for MongoDB
- 🔌 Cassandra ORM-like adapter with CRUD helpers
Developer Experience
- 📝 TypeScript support with full type definitions
- 🎯 Custom error classes for better error handling
- 📊 Connection statistics API for monitoring
- 📚 Comprehensive documentation with examples
- 🛡️ Input validation for tenant identifiers
- 📋 Structured logging with Winston
📦 Installation
npm install multibridgeOptional ORM Dependencies
Install ORM packages as needed (they are peer dependencies):
# For Sequelize
npm install sequelize pg mysql2
# For TypeORM
npm install typeorm pg mysql2 mongodb
# For Mongoose
npm install mongoose
# Cassandra driver is included as a dependency🚀 Quick Start
1. Configuration
Create a .env file in your project root:
# Central Database Configuration (PostgreSQL)
CENTRAL_DB_HOST=localhost
CENTRAL_DB_PORT=5432
CENTRAL_DB_USER=admin
CENTRAL_DB_PASSWORD=password
CENTRAL_DB_NAME=central_db
CENTRAL_DB_TABLE=connections_config
# Logging
LOG_LEVEL=info
# Optional: Performance Tuning
CONNECTION_CACHE_MAX_SIZE=100
CONNECTION_CACHE_TTL_MS=3600000
POSTGRES_POOL_MAX=20
POSTGRES_POOL_MIN=5
MYSQL_POOL_MAX=10
QUERY_TIMEOUT_MS=300002. Basic Usage
import { runWithTenant, executeQuery, ConnectVo } from "multibridge";
const tenant: ConnectVo = {
appid: "myApp",
orgid: "org123",
appdbname: "tenant_db",
};
// Execute queries in tenant context
await runWithTenant(tenant, async () => {
// PostgreSQL/MySQL
const users = await executeQuery("SELECT * FROM users WHERE id = ?", [userId]);
// MongoDB
const user = await executeQuery({
collection: "users",
method: "findOne",
args: [{ email: "[email protected]" }],
});
// Cassandra
const data = await executeQuery(
"SELECT * FROM users WHERE user_id = ?",
[userId]
);
});3. ORM Integration
Sequelize
import { runWithTenant, getSequelizeInstance } from "multibridge";
import { Sequelize } from "sequelize";
await runWithTenant(tenant, async () => {
const sequelize = await getSequelizeInstance();
const User = sequelize.define("User", {
username: Sequelize.STRING,
email: Sequelize.STRING,
});
const users = await User.findAll();
});TypeORM
import { runWithTenant, getTypeORMDataSource } from "multibridge";
import { User } from "./entities/User";
await runWithTenant(tenant, async () => {
const dataSource = await getTypeORMDataSource({
entities: [User],
});
const userRepo = dataSource.getRepository(User);
const users = await userRepo.find();
});Mongoose
import { runWithTenant, getMongooseConnection } from "multibridge";
import { Schema } from "mongoose";
await runWithTenant(tenant, async () => {
const connection = await getMongooseConnection();
const User = connection.model("User", new Schema({
username: String,
email: String,
}));
const users = await User.find();
});Cassandra
import { runWithTenant, getCassandraClient, insert, select } from "multibridge";
await runWithTenant(tenant, async () => {
const client = await getCassandraClient();
// Insert
await insert(client, "users", {
user_id: "123",
username: "john",
email: "[email protected]",
});
// Select
const users = await select(client, "users", ["user_id", "username"], {
user_id: "123",
});
});📖 Documentation
For comprehensive examples and detailed usage patterns, see:
- EXAMPLE.md - Complete usage guide with controllers, services, ORM integration, and best practices
- CHANGELOG.md - Version history and migration guides
🔧 API Reference
Core Functions
runWithTenant(tenant, callback, options?)
Execute code within a tenant context.
await runWithTenant(tenant, async () => {
// Your code here
}, { lazyConnection: false }); // Default: false (eager connection)executeQuery(query, params?)
Execute a query in the current tenant context.
// SQL (PostgreSQL/MySQL)
await executeQuery("SELECT * FROM users WHERE id = ?", [userId]);
// MongoDB
await executeQuery({
collection: "users",
method: "findOne",
args: [{ email: "[email protected]" }],
});
// Cassandra
await executeQuery("SELECT * FROM users WHERE user_id = ?", [userId]);getConnection()
Get the current tenant's database connection.
const { connection, dbType, config } = await getConnection();getConnectionStats()
Get connection statistics for monitoring.
const stats = getConnectionStats();
console.log(stats.activeConnections);
console.log(stats.cachedConnections);ORM Adapters
Sequelize
getSequelizeInstance(options?)- Get Sequelize instancecloseSequelizeInstance(tenant?)- Close instance for tenantcloseAllSequelizeInstances()- Close all instances
TypeORM
getTypeORMDataSource(options?)- Get TypeORM DataSourcecloseTypeORMDataSource(tenant?)- Close DataSource for tenantcloseAllTypeORMDataSources()- Close all DataSources
Mongoose
getMongooseConnection(options?)- Get Mongoose connectioncloseMongooseConnection(tenant?)- Close connection for tenantcloseAllMongooseConnections()- Close all connections
Cassandra
getCassandraClient()- Get Cassandra clientexecuteCQL(query, params?)- Execute CQL querycreateTable(client, model)- Create table from modelinsert(client, table, data)- Insert dataselect(client, table, columns, where?)- Select dataupdate(client, table, data, where)- Update dataremove(client, table, where)- Delete datacloseCassandraClient(tenant?)- Close client for tenantcloseAllCassandraClients()- Close all clients
Error Handling
MultiBridge provides custom error classes:
import {
MultiBridgeError,
TenantContextError,
ConnectionError,
ConfigurationError,
ValidationError,
QueryError,
TimeoutError,
} from "multibridge";
try {
await runWithTenant(tenant, async () => {
await executeQuery("SELECT * FROM users");
});
} catch (error) {
if (error instanceof TenantContextError) {
// Handle tenant context errors
} else if (error instanceof ConnectionError) {
// Handle connection errors
} else if (error instanceof QueryError) {
// Handle query errors
} else if (error instanceof TimeoutError) {
// Handle timeout errors
}
}⚙️ Configuration Options
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| CENTRAL_DB_HOST | Central database host | localhost |
| CENTRAL_DB_PORT | Central database port | 5432 |
| CENTRAL_DB_USER | Central database user | - |
| CENTRAL_DB_PASSWORD | Central database password | - |
| CENTRAL_DB_NAME | Central database name | - |
| CENTRAL_DB_TABLE | Configuration table name | connections_config |
| LOG_LEVEL | Logging level | info |
| CONNECTION_CACHE_MAX_SIZE | Max cached connections | 100 |
| CONNECTION_CACHE_TTL_MS | Connection cache TTL | 3600000 (1 hour) |
| POSTGRES_POOL_MAX | PostgreSQL max pool size | 20 |
| POSTGRES_POOL_MIN | PostgreSQL min pool size | 5 |
| MYSQL_POOL_MAX | MySQL max pool size | 10 |
| QUERY_TIMEOUT_MS | Default query timeout | 30000 (30s) |
| CONNECTION_RETRY_ATTEMPTS | Retry attempts | 3 |
| CONNECTION_RETRY_DELAY_MS | Retry delay | 1000 (1s) |
| RATE_LIMIT_MAX_REQUESTS | Rate limit max requests | 10 |
| RATE_LIMIT_WINDOW_MS | Rate limit window | 1000 (1s) |
See EXAMPLE.md for complete configuration options.
🏗️ Architecture
Project Structure
src/
├── config/ # Configuration management
│ ├── dbConfig.ts # Central database configuration
│ └── envConfig.ts # Environment variable configuration
├── connections/ # Database connection management
│ ├── connectionManager.ts # Core connection manager
│ ├── postgres.ts # PostgreSQL connection
│ ├── mysql.ts # MySQL connection
│ ├── mongodb.ts # MongoDB connection
│ └── cassandra.ts # Cassandra connection
├── context/ # Tenant context management
│ └── tenantContext.ts
├── helpers/ # Database-specific helpers
│ ├── mongodbHelper.ts
│ └── cassandraHelper.ts
├── orm/ # ORM adapters
│ ├── sequelize.ts
│ ├── typeorm.ts
│ ├── mongoose.ts
│ └── cassandra.ts
├── utils/ # Utility functions
│ ├── executeQuery.ts
│ ├── errors.ts
│ ├── loggers.ts
│ ├── lruCache.ts
│ └── rateLimiter.ts
└── types/ # TypeScript type definitions
└── dbTypes.tsHow It Works
- Tenant Context:
runWithTenantestablishes a tenant context usingAsyncLocalStorage - Configuration Lookup: MultiBridge queries the central database to get tenant-specific connection details
- Connection Caching: Connections are cached using LRU cache with TTL
- Query Execution:
executeQueryautomatically routes queries to the correct tenant database - ORM Integration: ORM adapters use MultiBridge's connection management
🔒 Security
- ✅ SQL Injection Prevention: Automatic schema name sanitization
- ✅ CQL Injection Prevention: Identifier sanitization for Cassandra
- ✅ Input Validation: Tenant identifier validation
- ✅ Password Sanitization: Passwords are sanitized in logs
- ✅ Type Safety: Full TypeScript support for type safety
⚡ Performance
- 🚀 Connection Caching: LRU cache with configurable size and TTL
- 🚀 Configuration Caching: Central DB config caching
- 🚀 Connection Pooling: Configurable pool sizes
- 🚀 Lazy Validation: Connection validation only when needed
- 🚀 Race Condition Prevention: Promise-based locking
- 🚀 Rate Limiting: Prevents connection exhaustion
🧪 Example Project Structure
my-app/
├── src/
│ ├── controllers/
│ │ └── userController.ts
│ ├── services/
│ │ └── userService.ts
│ ├── models/
│ │ ├── sequelize/
│ │ │ └── User.ts
│ │ └── typeorm/
│ │ └── User.entity.ts
│ ├── routes/
│ │ └── userRoutes.ts
│ └── server.ts
├── .env
└── package.jsonSee EXAMPLE.md for complete examples.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with TypeScript for type safety
- Uses Winston for structured logging
- Supports popular ORMs: Sequelize, TypeORM, Mongoose
