bigbasealpha
Version:
Enterprise-Grade NoSQL Database System with Modular Logger & Offline HSM Security - Complete database platform with professional text-based logging, encryption, caching, indexing, JWT authentication, auto-generated REST API, real-time dashboard, and maste
688 lines (583 loc) • 21.1 kB
JavaScript
import { EventEmitter } from 'events';
import { promises as fs } from 'fs';
import { join } from 'path';
/**
* Database Connectors for BigBaseAlpha
* Provides connectivity to external databases (MySQL, PostgreSQL, MongoDB, etc.)
*/
export class DatabaseConnectors extends EventEmitter {
constructor(config) {
super();
this.config = {
enabled: config.connectors?.enabled || false,
connections: config.connectors?.connections || {},
autoReconnect: config.connectors?.autoReconnect !== false,
reconnectInterval: config.connectors?.reconnectInterval || 5000,
queryTimeout: config.connectors?.queryTimeout || 30000,
poolSize: config.connectors?.poolSize || 10,
...config.connectors
};
this.database = null;
this.connections = new Map();
this.connectionPools = new Map();
this.schemas = new Map();
this.isInitialized = false;
// Sync state
this.syncState = {
lastSync: null,
activeSyncs: new Set(),
failedSyncs: new Set(),
syncHistory: []
};
// Statistics
this.stats = {
totalConnections: 0,
activeConnections: 0,
queriesExecuted: 0,
dataTransferred: 0,
errors: 0,
syncOperations: 0
};
// Built-in drivers (simplified implementations)
this.drivers = new Map();
this._initializeDrivers();
}
async init() {
if (this.isInitialized) return;
console.log('🔗 Initializing Database Connectors...');
if (!this.config.enabled) {
console.log('⚠️ Database connectors are disabled in configuration');
return;
}
try {
// Initialize configured connections
for (const [name, config] of Object.entries(this.config.connections)) {
await this._createConnection(name, config);
}
this.isInitialized = true;
console.log(`✅ Database Connectors initialized with ${this.connections.size} connections`);
this.emit('connectorsInitialized', {
connections: this.connections.size,
drivers: Array.from(this.drivers.keys())
});
} catch (error) {
console.error('❌ Failed to initialize database connectors:', error.message);
throw error;
}
}
setDatabase(database) {
this.database = database;
}
_initializeDrivers() {
// MySQL Driver (Simplified)
this.drivers.set('mysql', {
name: 'MySQL',
connect: async (config) => {
console.log(`🔗 Simulating MySQL connection to ${config.host}:${config.port}`);
return {
type: 'mysql',
host: config.host,
port: config.port || 3306,
database: config.database,
connected: true,
connectionTime: Date.now()
};
},
query: async (connection, query, params = []) => {
console.log(`📊 MySQL Query: ${query.substring(0, 100)}...`);
// Simulate query execution
await new Promise(resolve => setTimeout(resolve, Math.random() * 100));
if (query.toLowerCase().includes('select')) {
return {
rows: [
{ id: 1, name: 'Sample User', email: 'user@example.com', created_at: new Date() },
{ id: 2, name: 'Another User', email: 'user2@example.com', created_at: new Date() }
],
rowCount: 2,
executionTime: Math.random() * 100
};
}
return { affectedRows: 1, insertId: Math.floor(Math.random() * 1000) };
},
disconnect: async (connection) => {
console.log('🔌 MySQL connection closed');
connection.connected = false;
}
});
// PostgreSQL Driver (Simplified)
this.drivers.set('postgresql', {
name: 'PostgreSQL',
connect: async (config) => {
console.log(`🔗 Simulating PostgreSQL connection to ${config.host}:${config.port}`);
return {
type: 'postgresql',
host: config.host,
port: config.port || 5432,
database: config.database,
connected: true,
connectionTime: Date.now()
};
},
query: async (connection, query, params = []) => {
console.log(`📊 PostgreSQL Query: ${query.substring(0, 100)}...`);
await new Promise(resolve => setTimeout(resolve, Math.random() * 100));
if (query.toLowerCase().includes('select')) {
return {
rows: [
{ id: 1, title: 'Sample Post', content: 'Lorem ipsum...', user_id: 1 },
{ id: 2, title: 'Another Post', content: 'More content...', user_id: 2 }
],
rowCount: 2,
executionTime: Math.random() * 100
};
}
return { rowCount: 1, insertId: Math.floor(Math.random() * 1000) };
},
disconnect: async (connection) => {
console.log('🔌 PostgreSQL connection closed');
connection.connected = false;
}
});
// MongoDB Driver (Simplified)
this.drivers.set('mongodb', {
name: 'MongoDB',
connect: async (config) => {
console.log(`🔗 Simulating MongoDB connection to ${config.host}:${config.port}`);
return {
type: 'mongodb',
host: config.host,
port: config.port || 27017,
database: config.database,
connected: true,
connectionTime: Date.now()
};
},
query: async (connection, operation, collection, query = {}) => {
console.log(`📊 MongoDB ${operation} on ${collection}:`, query);
await new Promise(resolve => setTimeout(resolve, Math.random() * 100));
if (operation === 'find') {
return {
documents: [
{ _id: '507f1f77bcf86cd799439011', name: 'Sample Doc', data: { value: 123 } },
{ _id: '507f1f77bcf86cd799439012', name: 'Another Doc', data: { value: 456 } }
],
count: 2,
executionTime: Math.random() * 100
};
}
return { acknowledged: true, insertedId: '507f1f77bcf86cd799439013' };
},
disconnect: async (connection) => {
console.log('🔌 MongoDB connection closed');
connection.connected = false;
}
});
// Redis Driver (Simplified)
this.drivers.set('redis', {
name: 'Redis',
connect: async (config) => {
console.log(`🔗 Simulating Redis connection to ${config.host}:${config.port}`);
return {
type: 'redis',
host: config.host,
port: config.port || 6379,
connected: true,
connectionTime: Date.now()
};
},
query: async (connection, command, key, value = null) => {
console.log(`📊 Redis ${command}: ${key}`);
await new Promise(resolve => setTimeout(resolve, Math.random() * 50));
if (command.toLowerCase() === 'get') {
return { value: `cached_value_${Math.random()}`, executionTime: Math.random() * 50 };
}
return { result: 'OK', executionTime: Math.random() * 50 };
},
disconnect: async (connection) => {
console.log('🔌 Redis connection closed');
connection.connected = false;
}
});
}
async _createConnection(name, config) {
const driver = this.drivers.get(config.type);
if (!driver) {
throw new Error(`Unsupported database type: ${config.type}`);
}
try {
const connection = await driver.connect(config);
this.connections.set(name, {
name,
config,
driver,
connection,
status: 'connected',
createdAt: Date.now(),
lastUsed: Date.now(),
queriesExecuted: 0,
errors: 0
});
this.stats.totalConnections++;
this.stats.activeConnections++;
console.log(`✅ Connected to ${config.type} database: ${name}`);
this.emit('connectionCreated', { name, type: config.type });
} catch (error) {
console.error(`❌ Failed to connect to ${name}:`, error.message);
throw error;
}
}
// Public API Methods
async createConnection(name, config) {
if (this.connections.has(name)) {
throw new Error(`Connection '${name}' already exists`);
}
await this._createConnection(name, config);
return this.getConnection(name);
}
async removeConnection(name) {
const conn = this.connections.get(name);
if (!conn) {
throw new Error(`Connection '${name}' not found`);
}
try {
await conn.driver.disconnect(conn.connection);
this.connections.delete(name);
this.stats.activeConnections--;
console.log(`🔌 Connection '${name}' removed`);
this.emit('connectionRemoved', { name });
return true;
} catch (error) {
console.error(`❌ Error removing connection '${name}':`, error.message);
throw error;
}
}
getConnection(name) {
const conn = this.connections.get(name);
if (!conn) {
throw new Error(`Connection '${name}' not found`);
}
return conn;
}
getConnections() {
return Array.from(this.connections.values()).map(conn => ({
name: conn.name,
type: conn.config.type,
status: conn.status,
host: conn.config.host,
database: conn.config.database,
createdAt: conn.createdAt,
lastUsed: conn.lastUsed,
queriesExecuted: conn.queriesExecuted,
errors: conn.errors
}));
}
async testConnection(name) {
const conn = this.connections.get(name);
if (!conn) {
throw new Error(`Connection '${name}' not found`);
}
try {
const startTime = Date.now();
// Execute a simple test query based on database type
let result;
switch (conn.config.type) {
case 'mysql':
case 'postgresql':
result = await conn.driver.query(conn.connection, 'SELECT 1 as test');
break;
case 'mongodb':
result = await conn.driver.query(conn.connection, 'ping', 'test');
break;
case 'redis':
result = await conn.driver.query(conn.connection, 'PING');
break;
default:
throw new Error(`Test not implemented for ${conn.config.type}`);
}
const responseTime = Date.now() - startTime;
conn.lastUsed = Date.now();
return {
success: true,
responseTime,
result,
timestamp: Date.now()
};
} catch (error) {
conn.errors++;
this.stats.errors++;
return {
success: false,
error: error.message,
timestamp: Date.now()
};
}
}
async executeQuery(connectionName, query, params = []) {
const conn = this.connections.get(connectionName);
if (!conn) {
throw new Error(`Connection '${connectionName}' not found`);
}
try {
const startTime = Date.now();
const result = await conn.driver.query(conn.connection, query, params);
const executionTime = Date.now() - startTime;
// Update statistics
conn.queriesExecuted++;
conn.lastUsed = Date.now();
this.stats.queriesExecuted++;
this.emit('queryExecuted', {
connection: connectionName,
query: query.substring(0, 100),
executionTime,
success: true
});
return {
success: true,
data: result,
executionTime,
timestamp: Date.now()
};
} catch (error) {
conn.errors++;
this.stats.errors++;
this.emit('queryExecuted', {
connection: connectionName,
query: query.substring(0, 100),
success: false,
error: error.message
});
throw error;
}
}
// Data Migration Methods
async importFromExternalDB(connectionName, sourceTable, targetCollection, options = {}) {
const conn = this.connections.get(connectionName);
if (!conn) {
throw new Error(`Connection '${connectionName}' not found`);
}
if (!this.database) {
throw new Error('BigBaseAlpha database not set');
}
try {
console.log(`📥 Starting import from ${connectionName}.${sourceTable} to ${targetCollection}`);
// Create target collection if it doesn't exist
try {
await this.database.createCollection(targetCollection);
} catch (error) {
if (!error.message.includes('already exists')) {
throw error;
}
}
let query;
let result;
// Build query based on database type
switch (conn.config.type) {
case 'mysql':
case 'postgresql':
query = `SELECT * FROM ${sourceTable}`;
if (options.limit) query += ` LIMIT ${options.limit}`;
result = await conn.driver.query(conn.connection, query);
break;
case 'mongodb':
result = await conn.driver.query(conn.connection, 'find', sourceTable, options.filter || {});
break;
default:
throw new Error(`Import not supported for ${conn.config.type}`);
}
const documents = result.rows || result.documents || [];
let importedCount = 0;
// Import documents to BigBaseAlpha
for (const doc of documents) {
try {
await this.database.insert(targetCollection, doc);
importedCount++;
} catch (error) {
console.warn(`⚠️ Failed to import document:`, error.message);
}
}
const importResult = {
success: true,
imported: importedCount,
total: documents.length,
collection: targetCollection,
source: `${connectionName}.${sourceTable}`,
timestamp: Date.now()
};
this.emit('importCompleted', importResult);
console.log(`✅ Import completed: ${importedCount}/${documents.length} documents`);
return importResult;
} catch (error) {
console.error(`❌ Import failed:`, error.message);
throw error;
}
}
async exportToExternalDB(connectionName, sourceCollection, targetTable, options = {}) {
const conn = this.connections.get(connectionName);
if (!conn) {
throw new Error(`Connection '${connectionName}' not found`);
}
if (!this.database) {
throw new Error('BigBaseAlpha database not set');
}
try {
console.log(`📤 Starting export from ${sourceCollection} to ${connectionName}.${targetTable}`);
// Get data from BigBaseAlpha
const documents = await this.database.find(sourceCollection, options.filter || {});
let exportedCount = 0;
for (const doc of documents) {
try {
let query;
switch (conn.config.type) {
case 'mysql':
case 'postgresql':
// Convert document to INSERT statement
const fields = Object.keys(doc).filter(k => k !== '_id');
const values = fields.map(f => `'${doc[f]}'`).join(', ');
query = `INSERT INTO ${targetTable} (${fields.join(', ')}) VALUES (${values})`;
await conn.driver.query(conn.connection, query);
break;
case 'mongodb':
await conn.driver.query(conn.connection, 'insertOne', targetTable, doc);
break;
default:
throw new Error(`Export not supported for ${conn.config.type}`);
}
exportedCount++;
} catch (error) {
console.warn(`⚠️ Failed to export document:`, error.message);
}
}
const exportResult = {
success: true,
exported: exportedCount,
total: documents.length,
source: sourceCollection,
target: `${connectionName}.${targetTable}`,
timestamp: Date.now()
};
this.emit('exportCompleted', exportResult);
console.log(`✅ Export completed: ${exportedCount}/${documents.length} documents`);
return exportResult;
} catch (error) {
console.error(`❌ Export failed:`, error.message);
throw error;
}
}
// Sync Operations
async syncWithExternalDB(connectionName, mappings, options = {}) {
const syncId = `sync_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
this.syncState.activeSyncs.add(syncId);
try {
console.log(`🔄 Starting bidirectional sync with ${connectionName}`);
const results = [];
for (const mapping of mappings) {
const { sourceTable, targetCollection, direction = 'import' } = mapping;
if (direction === 'import' || direction === 'both') {
const importResult = await this.importFromExternalDB(connectionName, sourceTable, targetCollection, options);
results.push({ type: 'import', ...importResult });
}
if (direction === 'export' || direction === 'both') {
const exportResult = await this.exportToExternalDB(connectionName, targetCollection, sourceTable, options);
results.push({ type: 'export', ...exportResult });
}
}
this.syncState.lastSync = Date.now();
this.syncState.syncHistory.push({
id: syncId,
connection: connectionName,
results,
timestamp: Date.now(),
success: true
});
this.stats.syncOperations++;
this.emit('syncCompleted', { syncId, results });
return { syncId, results, success: true };
} catch (error) {
this.syncState.failedSyncs.add(syncId);
console.error(`❌ Sync failed:`, error.message);
throw error;
} finally {
this.syncState.activeSyncs.delete(syncId);
}
}
// Schema Operations
async getExternalSchema(connectionName, table) {
const conn = this.connections.get(connectionName);
if (!conn) {
throw new Error(`Connection '${connectionName}' not found`);
}
try {
let schema;
switch (conn.config.type) {
case 'mysql':
schema = await conn.driver.query(conn.connection, `DESCRIBE ${table}`);
break;
case 'postgresql':
schema = await conn.driver.query(conn.connection,
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '${table}'`);
break;
case 'mongodb':
// MongoDB is schemaless, return sample document structure
schema = await conn.driver.query(conn.connection, 'findOne', table);
break;
default:
throw new Error(`Schema inspection not supported for ${conn.config.type}`);
}
this.schemas.set(`${connectionName}.${table}`, schema);
return schema;
} catch (error) {
console.error(`❌ Failed to get schema for ${connectionName}.${table}:`, error.message);
throw error;
}
}
// Statistics and Monitoring
getStats() {
return {
...this.stats,
connections: {
total: this.connections.size,
byType: this._getConnectionsByType(),
active: Array.from(this.connections.values()).filter(c => c.status === 'connected').length
},
sync: {
activeSyncs: this.syncState.activeSyncs.size,
lastSync: this.syncState.lastSync,
totalSyncs: this.stats.syncOperations,
failedSyncs: this.syncState.failedSyncs.size
},
drivers: Array.from(this.drivers.keys())
};
}
_getConnectionsByType() {
const byType = {};
for (const conn of this.connections.values()) {
byType[conn.config.type] = (byType[conn.config.type] || 0) + 1;
}
return byType;
}
getSupportedDrivers() {
return Array.from(this.drivers.keys()).map(key => ({
type: key,
name: this.drivers.get(key).name,
supported: true
}));
}
async shutdown() {
console.log('🔄 Shutting down Database Connectors...');
// Close all connections
for (const [name, conn] of this.connections) {
try {
await conn.driver.disconnect(conn.connection);
} catch (error) {
console.error(`Error closing connection ${name}:`, error.message);
}
}
// Clear data structures
this.connections.clear();
this.connectionPools.clear();
this.schemas.clear();
this.syncState.activeSyncs.clear();
console.log('✅ Database Connectors shutdown complete');
}
}
export default DatabaseConnectors;