UNPKG

@hemia/db-connector

Version:

Hemia Database Conector

583 lines (563 loc) 20.5 kB
import mongoose__default from 'mongoose'; export * from 'mongoose'; import { ValidationError, DatabaseError, AccessDeniedError, Sequelize } from 'sequelize'; export { DataTypes, Model as ModelSequelize, Op, QueryTypes, Sequelize, Transaction, fn } from 'sequelize'; var CoreSqlTypes; (function (CoreSqlTypes) { CoreSqlTypes["Number"] = "Number"; CoreSqlTypes["string"] = "string"; CoreSqlTypes["DateTime"] = "DateTime"; CoreSqlTypes["Decimal"] = "Decimal"; CoreSqlTypes["Boolean"] = "Boolean"; CoreSqlTypes["Float"] = "Float"; })(CoreSqlTypes || (CoreSqlTypes = {})); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; class NoSQLConnector { constructor() { this.config = {}; this.provider = ''; this.connection = null; } } var DBNoSQLType; (function (DBNoSQLType) { DBNoSQLType["MongoDB"] = "MongoDB"; DBNoSQLType["Cassandra"] = "Cassandra"; })(DBNoSQLType || (DBNoSQLType = {})); class MongoDBConnector extends NoSQLConnector { constructor(param) { super(); this.currentSession = null; this.config = param; this.provider = DBNoSQLType.MongoDB; this.mongooseConnection = mongoose__default.connection; } connect() { return __awaiter(this, void 0, void 0, function* () { try { if (this.mongooseConnection.readyState === 1) { return; } yield mongoose__default.connect(`mongodb://${this.config.host}:${this.config.port || 27017}`, { user: this.config.user, pass: this.config.password, dbName: this.config.database, authSource: this.config.authSource }); this.mongooseConnection = mongoose__default.connection; console.log('Connected to MongoDB'); } catch (error) { console.error('Error connecting to MongoDB:', error); throw error; } }); } disconnect() { return __awaiter(this, void 0, void 0, function* () { try { console.log('Disconnected from MongoDB'); yield this.mongooseConnection.close(); } catch (error) { console.error('Error disconnecting from MongoDB:', error); throw error; } }); } getConnection() { return this.mongooseConnection; } isConnected() { return this.mongooseConnection.readyState === 1; } state() { return this.mongooseConnection.readyState; } getCredentials() { return this.config; } getProvider() { return this.provider; } startSession() { return __awaiter(this, void 0, void 0, function* () { if (!this.currentSession) { this.currentSession = yield this.mongooseConnection.startSession(); this.currentSession.startTransaction(); } return this.currentSession; }); } commitTransaction() { return __awaiter(this, void 0, void 0, function* () { if (this.currentSession) { yield this.currentSession.commitTransaction(); this.currentSession.endSession(); this.currentSession = null; } }); } abortTransaction() { return __awaiter(this, void 0, void 0, function* () { if (this.currentSession) { yield this.currentSession.abortTransaction(); this.currentSession.endSession(); this.currentSession = null; } }); } withTransaction(transactionFn) { return __awaiter(this, void 0, void 0, function* () { const session = yield this.startSession(); try { const result = yield transactionFn(session); yield this.commitTransaction(); return result; } catch (error) { yield this.abortTransaction(); console.error('Transaction aborted:', error); throw error; } }); } create(model, data, session) { return __awaiter(this, void 0, void 0, function* () { try { const doc = new model(data); return yield doc.save({ session }); } catch (error) { console.error('Error al crear documento:', error); throw error; } }); } find(model, query, options) { return __awaiter(this, void 0, void 0, function* () { try { let queryBuilder = model.find(query); if (options === null || options === void 0 ? void 0 : options.limit) queryBuilder = queryBuilder.limit(options.limit); if (options === null || options === void 0 ? void 0 : options.skip) queryBuilder = queryBuilder.skip(options.skip); if (options === null || options === void 0 ? void 0 : options.sort) queryBuilder = queryBuilder.sort(options.sort); return yield queryBuilder; } catch (error) { console.error('Error al obtener documentos:', error); throw error; } }); } findOne(model, query) { return __awaiter(this, void 0, void 0, function* () { try { return yield model.findOne(query); } catch (error) { console.error('Error al obtener un documento:', error); throw error; } }); } findById(model, id) { return __awaiter(this, void 0, void 0, function* () { try { return yield model.findById(id); } catch (error) { console.error('Error al obtener un documento:', error); throw error; } }); } update(model, query, updateData, session) { return __awaiter(this, void 0, void 0, function* () { try { return yield model.findOneAndUpdate(query, updateData, { new: true, runValidators: false, session }); } catch (error) { console.error('Error al actualizar documento:', error); throw error; } }); } updateById(model, id, updateData, session) { return __awaiter(this, void 0, void 0, function* () { try { return yield model.findOneAndUpdate({ _id: id }, updateData, { new: true, runValidators: false, session }); } catch (error) { console.error('Error al actualizar documento:', error); throw error; } }); } delete(model, query, session) { return __awaiter(this, void 0, void 0, function* () { try { yield model.findOneAndDelete(query, { session }); return true; } catch (error) { console.error('Error al eliminar documento:', error); throw error; } }); } deleteById(model, id, session) { return __awaiter(this, void 0, void 0, function* () { try { yield model.findByIdAndDelete(id, { session }); return true; } catch (error) { console.error('Error al eliminar documento:', error); throw error; } }); } findAllFromMultipleModels(models, filter) { return __awaiter(this, void 0, void 0, function* () { try { const results = yield Promise.all(models.map((model) => model.find(filter).exec())); return results.flat(); } catch (error) { console.error('Error al buscar documentos en múltiples colecciones:', error); throw error; } }); } aggregate(model, pipeline, options) { return __awaiter(this, void 0, void 0, function* () { try { return yield model.aggregate(pipeline, options); } catch (error) { console.error('Error al buscar documentos la coleccion:', error); throw error; } }); } executeWithModel(model, operation, session) { return __awaiter(this, void 0, void 0, function* () { try { return yield operation(model, session); } catch (error) { console.error('Error en operación personalizada:', error); throw error; } }); } } class NoSQLConnectionManager { static getInstance(type, credentials) { switch (type) { case DBNoSQLType.MongoDB: return new MongoDBConnector(credentials); case DBNoSQLType.Cassandra: throw new Error(`Tipo de base de datos no soportado: ${type}`); default: throw new Error(`Tipo de base de datos no soportado: ${type}`); } } } class SqlConnector { } class DBError extends Error { constructor(code, message, meta) { super(message); if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } this.name = 'DatabaseError'; this.code = code; this.sqlState = meta === null || meta === void 0 ? void 0 : meta.sqlState; this.errno = meta === null || meta === void 0 ? void 0 : meta.errno; this.status = meta === null || meta === void 0 ? void 0 : meta.status; } } class MySQLConnectionError { constructor() { } static handleMysqlConnectionError(error) { if (error instanceof ValidationError) { throw new DBError('401', `Validation Error: [${error.message}]`); } else if (error instanceof DatabaseError) { throw new DBError('401', `Database Error: [${error.message}]`); } else if (error instanceof AccessDeniedError) { throw new DBError('403', `Forbidden: [${error.message}]`); } else { throw new DBError('400', `Unable to connect to the database, ${error}`); } } } class SequelizeSqlConnector extends SqlConnector { constructor(creds) { var _a, _b; super(); this.creds = creds; this.sequelize = new Sequelize(creds.database, creds.user || '', creds.password, { host: creds.host, port: creds.port, dialect: (_a = creds.dialect) !== null && _a !== void 0 ? _a : 'mysql', logging: (_b = creds.logging) !== null && _b !== void 0 ? _b : false, }); } connect() { return __awaiter(this, void 0, void 0, function* () { try { yield this.sequelize.authenticate(); } catch (error) { MySQLConnectionError.handleMysqlConnectionError(error); } }); } disconnect() { return __awaiter(this, void 0, void 0, function* () { yield this.sequelize.close(); }); } isConnected() { return __awaiter(this, void 0, void 0, function* () { try { yield this.sequelize.query('SELECT 1', { raw: true }); return true; } catch (error) { return false; } }); } getSequelize() { return this.sequelize; } getModel(name) { if (!this.sequelize.isDefined(name)) { throw new Error(`Modelo no definido: ${name}`); } return this.sequelize.model(name); } select(entity, options) { return __awaiter(this, void 0, void 0, function* () { try { const model = this.getModel(entity); const records = yield model.findAll(options); return records; } catch (error) { console.error(error); throw this.createDatabaseError(error); } }); } insert(entity, values, options) { return __awaiter(this, void 0, void 0, function* () { try { const model = this.getModel(entity); const instance = yield model.create(values, options); return instance; } catch (error) { console.error(error); throw this.createDatabaseError(error); } }); } update(entity, filter, data, options) { return __awaiter(this, void 0, void 0, function* () { try { const model = this.getModel(entity); const updateOpts = Object.assign(Object.assign({}, options), { where: filter }); const [count] = yield model.update(data, updateOpts); return count; } catch (error) { console.error(error); throw this.createDatabaseError(error); } }); } delete(entity, filter, options) { return __awaiter(this, void 0, void 0, function* () { try { const model = this.getModel(entity); const destroyOpts = Object.assign({ where: filter }, options); const deletedCount = yield model.destroy(destroyOpts); return deletedCount; } catch (error) { console.error(error); throw this.createDatabaseError(error); } }); } query(sql, options) { return __awaiter(this, void 0, void 0, function* () { try { const results = yield this.sequelize.query(sql, options); return results; } catch (error) { console.error(error); throw this.createDatabaseError(error); } }); } withTransaction(fn) { return __awaiter(this, void 0, void 0, function* () { const tx = yield this.sequelize.transaction(); try { const result = yield fn(tx); yield tx.commit(); return result; } catch (error) { console.error(error); yield tx.rollback(); throw this.createDatabaseError(error); } }); } createDatabaseError(err) { var _a, _b, _c; const SQLSTATE_CODE_MAP = { '42S02': 'DB_TABLE_NOT_FOUND', '42S22': 'DB_COLUMN_NOT_FOUND', '23000': 'DB_INTEGRITY_ERROR', }; const source = (_a = err.original) !== null && _a !== void 0 ? _a : err; const sqlState = source.sqlState; const errno = source.errno; const rawMsg = (_c = (_b = source.sqlMessage) !== null && _b !== void 0 ? _b : err.message) !== null && _c !== void 0 ? _c : String(err); let code; try { const parsed = JSON.parse(rawMsg); code = parsed.code || rawMsg; } catch (_d) { code = sqlState && SQLSTATE_CODE_MAP[sqlState] ? SQLSTATE_CODE_MAP[sqlState] : sqlState == '45000' ? rawMsg : 'DB_UNKNOWN_ERROR'; } const message = `DatabaseError [${code}] (SQLSTATE=${sqlState}, errno=${errno}): ${rawMsg}`; return new DBError(code, message, { sqlState, errno }); } } var DBSQLType; (function (DBSQLType) { DBSQLType["SQLServer"] = "SQLServer"; DBSQLType["MYSQL"] = "MYSQL"; })(DBSQLType || (DBSQLType = {})); class SQLConnectionManager { static getInstance(type, credentials) { switch (type) { case DBSQLType.MYSQL: return new SequelizeSqlConnector(credentials); default: throw new Error(`Tipo de base de datos no soportado: ${type}`); } } } class DBConnector { constructor() { this.connection = null; this.sqlConnection = null; this.credentials = null; this.dbType = null; } static getInstance() { if (!DBConnector.instance) { DBConnector.instance = new DBConnector(); } return DBConnector.instance; } createConnection(type, credentials) { return __awaiter(this, void 0, void 0, function* () { if (this.connection && this.dbType === type && JSON.stringify(this.credentials) === JSON.stringify(credentials)) { return this.sqlConnection; } if (this.connection) { yield this.closeConnection(); } if (Object.values(DBNoSQLType).includes(type)) { this.connection = NoSQLConnectionManager.getInstance(type, credentials); } else if (Object.values(DBSQLType).includes(type)) { this.connection = SQLConnectionManager.getInstance(type, credentials); } else { throw new Error(`Unsupported database type: ${type}`); } yield this.connection.connect(); this.credentials = credentials; this.dbType = type; return this.connection; }); } getConnection() { return this.connection; } closeConnection() { return __awaiter(this, void 0, void 0, function* () { if (this.connection) { yield this.connection.disconnect(); this.connection = null; this.credentials = null; this.dbType = null; } }); } getEngine(type, credentials) { try { if (Object.values(DBNoSQLType).includes(type)) { this.connection = NoSQLConnectionManager.getInstance(type, credentials); } else if (Object.values(DBSQLType).includes(type)) { this.connection = SQLConnectionManager.getInstance(type, credentials); } else { throw new Error(`Unsupported database type: ${type}`); } return this.connection; } catch (error) { throw error; } } } DBConnector.instance = null; export { CoreSqlTypes, DBConnector, DBError, DBNoSQLType, DBSQLType, MySQLConnectionError, NoSQLConnector, SqlConnector };