UNPKG

adaptus2-orm

Version:

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

345 lines (285 loc) 12.9 kB
// index.js - Main ORM entry point const path = require('path'); const DatabaseManager = require('./src/core/DatabaseManager'); const QueryBuilder = require('./src/core/QueryBuilder'); const SchemaManager = require('./src/core/SchemaManager'); // Helper function to create response objects function createResponse(statusCode, message, error, data, source_action = '') { return { statusCode, message, error, data, source_action, toJSON() { return { statusCode: this.statusCode, message: this.message, error: this.error, data: this.data, source_action: this.source_action }; } }; } // Response factory with static methods const responseFactory = { success(data, message = 'Success', source_action = '') { return createResponse(200, message, '', data, source_action); }, error(message, error = '', source_action = '') { return createResponse(500, message, error, {}, source_action); }, custom(statusCode, message, error, data, source_action = '') { return createResponse(statusCode, message, error, data, source_action); } }; class ORM { constructor() { this.databaseManager = new DatabaseManager(); this.queryBuilder = new QueryBuilder(); this.schemaManager = new SchemaManager(this.databaseManager); this.connections = new Map(); } async getDbConnection(config) { try { const connectionKey = this._generateConnectionKey(config); if (!this.connections.has(connectionKey)) { const connection = await this.databaseManager.createConnection(config); this.connections.set(connectionKey, connection); // Set up connection error handling if (connection.on) { connection.on('error', (err) => { console.error(`Database connection error for ${config.type}:`, err); this.connections.delete(connectionKey); }); } } return this.connections.get(connectionKey); } catch (error) { console.error('Error getting database connection:', error); throw error; } } async create(config, table, params) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.create(connection, table, params); if (result.success) { return responseFactory.success(result.data, 'Record created successfully'); } return responseFactory.error('Failed to create record', result.error); } catch (error) { console.error('Create error:', error); return responseFactory.error('Error creating record', error); } } async read(config, table, params = {}) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.read(connection, table, params); if (result.success) { return responseFactory.success(result.data, 'Records retrieved successfully'); } return responseFactory.error('Failed to read records', result.error); } catch (error) { console.error('Read error:', error); return responseFactory.error('Error reading records', error); } } async update(config, table, params) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.update(connection, table, params); if (result.success) { return responseFactory.success(result.data, 'Record updated successfully'); } return responseFactory.error('Failed to update record', result.error); } catch (error) { console.error('Update error:', error); return responseFactory.error('Error updating record', error); } } async deleteRecord(config, table, params) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.delete(connection, table, params); if (result.success) { return responseFactory.success(result.data, 'Record deleted successfully'); } return responseFactory.error('Failed to delete record', result.error); } catch (error) { console.error('Delete error:', error); return responseFactory.error('Error deleting record', error); } } async exists(config, table, params) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.exists(connection, table, params); if (result.success) { return responseFactory.success(result.data, 'Existence check completed'); } return responseFactory.error('Failed to check existence', result.error); } catch (error) { console.error('Exists error:', error); return responseFactory.error('Error checking existence', error); } } async createTable(config, table, schema) { try { const connection = await this.getDbConnection(config); const result = await this.schemaManager.createTable(connection, config.type, table, schema); if (result.success) { return responseFactory.success(null, 'Table created successfully'); } return responseFactory.error('Failed to create table', result.error); } catch (error) { console.error('Create table error:', error); return responseFactory.error('Error creating table', error); } } async tableExists(config, table) { try { const connection = await this.getDbConnection(config); const result = await this.schemaManager.tableExists(connection, config.type, table); if (result.success) { return responseFactory.success(result.data, 'Table existence checked'); } return responseFactory.error('Failed to check table existence', result.error); } catch (error) { console.error('Table exists error:', error); return responseFactory.error('Error checking table existence', error); } } async query(config, queryString, params = []) { try { const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); const result = await adapter.query(connection, queryString, params); if (result.success) { return responseFactory.success(result.data, 'Query executed successfully'); } return responseFactory.error('Failed to execute query', result.error); } catch (error) { console.error('Query error:', error); return responseFactory.error('Error executing query', error); } } async initDatabase(config) { try { // Initialize the database connection const connection = await this.getDbConnection(config); const adapter = this.databaseManager.getAdapter(config.type); if (adapter.initDatabase) { const result = await adapter.initDatabase(connection, config); if (result.success) { return responseFactory.success(null, 'Database initialized successfully'); } return responseFactory.error('Failed to initialize database', result.error); } return responseFactory.success(null, 'Database connection established'); } catch (error) { console.error('Init database error:', error); return responseFactory.error('Error initializing database', error); } } async closeAllMysqlPools() { try { const mysqlConnections = Array.from(this.connections.entries()) .filter(([key]) => key.includes('mysql')); const results = []; for (const [key, connection] of mysqlConnections) { try { if (connection.pool && typeof connection.pool.end === 'function') { await connection.pool.end(); results.push({ key, success: true }); } else if (connection.close && typeof connection.close === 'function') { await connection.close(); results.push({ key, success: true }); } this.connections.delete(key); } catch (error) { results.push({ key, success: false, error: error.message }); } } return responseFactory.success(results, 'MySQL pools closed'); } catch (error) { console.error('Close MySQL pools error:', error); return responseFactory.error('Error closing MySQL pools', error); } } async extendContext(config) { try { const { globalContext, getContext } = require('./context'); // Initialize ORM methods in context const context = await getContext(); context.db = { getConnection: this.getDbConnection.bind(this), create: this.create.bind(this), read: this.read.bind(this), update: this.update.bind(this), delete: this.deleteRecord.bind(this), exists: this.exists.bind(this), createTable: this.createTable.bind(this), tableExists: this.tableExists.bind(this), query: this.query.bind(this), initDatabase: this.initDatabase.bind(this), closeAllMysqlPools: this.closeAllMysqlPools.bind(this) }; // Set up default configuration if (config) { context.db.config = config; } return responseFactory.success(context, 'Context extended successfully'); } catch (error) { console.error('Extend context error:', error); return responseFactory.error('Error extending context', error); } } _generateConnectionKey(config) { const { host, port, database, user, type } = config; return `${type}://${user}@${host}:${port}/${database}`; } // Clean up connections on process exit async cleanup() { try { for (const [key, connection] of this.connections) { try { if (connection.pool && typeof connection.pool.end === 'function') { await connection.pool.end(); } else if (connection.close && typeof connection.close === 'function') { await connection.close(); } else if (connection.destroy && typeof connection.destroy === 'function') { await connection.destroy(); } } catch (error) { console.error(`Error closing connection ${key}:`, error); } } this.connections.clear(); } catch (error) { console.error('Cleanup error:', error); } } } // Set up cleanup handlers const orm = new ORM(); process.on('exit', async () => { await orm.cleanup(); }); process.on('SIGINT', async () => { await orm.cleanup(); process.exit(0); }); process.on('uncaughtException', async (error) => { console.error('Uncaught exception:', error); await orm.cleanup(); process.exit(1); }); module.exports = new ORM();