UNPKG

adaptus2-orm

Version:

A multi-database ORM supporting MySQL, PostgreSQL, MongoDB, and Snowflake

239 lines (205 loc) 8.1 kB
// src/core/DatabaseManager.js const mysql = require('mysql2/promise'); const { Client } = require('pg'); const { MongoClient } = require('mongodb'); const snowflake = require('snowflake-sdk'); const MySQLAdapter = require('../adapters/MySQLAdapter'); const PostgreSQLAdapter = require('../adapters/PostgreSQLAdapter'); const MongoDBAdapter = require('../adapters/MongoDBAdapter'); const SnowflakeAdapter = require('../adapters/SnowflakeAdapter'); class DatabaseManager { constructor() { this.adapters = { mysql: new MySQLAdapter(), postgresql: new PostgreSQLAdapter(), mongodb: new MongoDBAdapter(), snowflake: new SnowflakeAdapter() }; this.pools = new Map(); } async createConnection(config) { const { type, ...connectionConfig } = config; if (!this.adapters[type]) { throw new Error(`Database type ${type} is not supported`); } // Check if connection pool already exists const poolKey = this._generatePoolKey(config); if (this.pools.has(poolKey)) { return this.pools.get(poolKey); } let connection; switch (type) { case 'mysql': connection = await this._createMySQLConnection(connectionConfig); break; case 'postgresql': connection = await this._createPostgreSQLConnection(connectionConfig); break; case 'mongodb': connection = await this._createMongoDBConnection(connectionConfig); break; case 'snowflake': connection = await this._createSnowflakeConnection(connectionConfig); break; default: throw new Error(`Unsupported database type: ${type}`); } this.pools.set(poolKey, connection); return connection; } async _createMySQLConnection(config) { try { const poolConfig = { host: config.host || 'localhost', port: config.port || 3306, user: config.user, password: config.password, database: config.database, waitForConnections: true, connectionLimit: config.connectionLimit || 10, queueLimit: 0, connectTimeout: config.connectTimeout || 60000, acquireTimeout: config.acquireTimeout || 60000, timeout: config.timeout || 60000, ...(config.ssl && { ssl: config.ssl }) }; const pool = mysql.createPool(poolConfig); // Test the connection const connection = await pool.getConnection(); await connection.ping(); connection.release(); return { pool, type: 'mysql' }; } catch (error) { console.error('MySQL connection error:', error); throw error; } } async _createPostgreSQLConnection(config) { try { const poolConfig = { host: config.host || 'localhost', port: config.port || 5432, user: config.user, password: config.password, database: config.database, max: config.max || 10, idleTimeoutMillis: config.idleTimeoutMillis || 30000, connectionTimeoutMillis: config.connectionTimeoutMillis || 60000, ...(config.ssl && { ssl: config.ssl }) }; const { Pool } = require('pg'); const pool = new Pool(poolConfig); // Test the connection const client = await pool.connect(); await client.query('SELECT NOW()'); client.release(); return { pool, type: 'postgresql' }; } catch (error) { console.error('PostgreSQL connection error:', error); throw error; } } async _createMongoDBConnection(config) { try { const uri = config.uri || `mongodb://${config.user}:${config.password}@${config.host}:${config.port || 27017}/${config.database}`; const clientOptions = { maxPoolSize: config.maxPoolSize || 10, minPoolSize: config.minPoolSize || 0, serverSelectionTimeoutMS: config.serverSelectionTimeoutMS || 30000, socketTimeoutMS: config.socketTimeoutMS || 30000, ...(config.ssl && { ssl: config.ssl }), ...(config.authSource && { authSource: config.authSource }) }; const client = new MongoClient(uri, clientOptions); await client.connect(); // Test the connection await client.db(config.database).admin().ping(); return { client, database: config.database, type: 'mongodb' }; } catch (error) { console.error('MongoDB connection error:', error); throw error; } } async _createSnowflakeConnection(config) { try { const connectionConfig = { account: config.account, username: config.user, password: config.password, warehouse: config.warehouse, database: config.database, schema: config.schema || 'PUBLIC', sessionParameters: { QUERY_TIMEOUT: config.queryTimeout || 120000, ...(config.sessionParameters || {}) }, streamResult: config.streamResult || false, complete: (err, connection) => { if (err) { throw err; } } }; const connection = snowflake.createConnection(connectionConfig); // Promisify the connect function await new Promise((resolve, reject) => { connection.connect((err, conn) => { if (err) { reject(err); } else { resolve(conn); } }); }); return { connection, type: 'snowflake' }; } catch (error) { console.error('Snowflake connection error:', error); throw error; } } getAdapter(type) { const adapter = this.adapters[type]; if (!adapter) { throw new Error(`Adapter for database type ${type} not found`); } return adapter; } _generatePoolKey(config) { const { host, port, database, user, type } = config; return `${type}://${user}@${host}:${port}/${database}`; } async closeConnection(poolKey) { const connection = this.pools.get(poolKey); if (!connection) { return; } try { switch (connection.type) { case 'mysql': await connection.pool.end(); break; case 'postgresql': await connection.pool.end(); break; case 'mongodb': await connection.client.close(); break; case 'snowflake': connection.connection.destroy(); break; } this.pools.delete(poolKey); } catch (error) { console.error(`Error closing connection for ${poolKey}:`, error); throw error; } } async closeAllConnections() { const promises = Array.from(this.pools.keys()).map(poolKey => this.closeConnection(poolKey) ); await Promise.allSettled(promises); this.pools.clear(); } } module.exports = DatabaseManager;