UNPKG

@syntropylog/adapters

Version:
1,376 lines (1,370 loc) 58.3 kB
class PrismaSerializer { constructor() { this.name = 'prisma'; this.priority = 75; } canSerialize(data) { return (this.isPrismaQuery(data) || this.isPrismaError(data) || this.isPrismaClient(data)); } getComplexity(data) { if (this.isPrismaQuery(data)) { return this.assessQueryComplexity(data); } if (this.isPrismaError(data)) { return 'low'; } if (this.isPrismaClient(data)) { return 'low'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isPrismaQuery(data)) { result = this.serializeQuery(data); } else if (this.isPrismaError(data)) { result = this.serializeError(data); } else if (this.isPrismaClient(data)) { result = this.serializeClient(data); } else { throw new Error('Tipo de dato Prisma no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización Prisma', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isPrismaQuery(data) { return (data && typeof data === 'object' && typeof data.model === 'string' && typeof data.action === 'string'); } isPrismaError(data) { return (data && typeof data === 'object' && typeof data.code === 'string' && typeof data.message === 'string'); } isPrismaClient(data) { return (data && typeof data === 'object' && typeof data.$connect === 'function' && typeof data.$disconnect === 'function' && typeof data.$queryRaw === 'function'); } assessQueryComplexity(query) { let complexity = 0; // Basado en la acción if (query.action === 'findMany') complexity += 1; else if (query.action === 'findFirst') complexity += 1; else if (query.action === 'findUnique') complexity += 1; else if (query.action === 'create') complexity += 2; else if (query.action === 'update') complexity += 2; else if (query.action === 'updateMany') complexity += 3; else if (query.action === 'delete') complexity += 2; else if (query.action === 'deleteMany') complexity += 3; else if (query.action === 'upsert') complexity += 3; else if (query.action === 'aggregate') complexity += 4; else if (query.action === 'groupBy') complexity += 4; else if (query.action === 'count') complexity += 1; // Basado en argumentos complejos if (query.args) { if (query.args.include) complexity += 1; if (query.args.select) complexity += 1; if (query.args.where && typeof query.args.where === 'object') { const whereKeys = Object.keys(query.args.where); complexity += Math.min(whereKeys.length, 2); } if (query.args.orderBy) complexity += 1; if (query.args.take) complexity += 1; if (query.args.skip) complexity += 1; if (query.args.distinct) complexity += 1; } if (complexity >= 7) return 'high'; if (complexity >= 4) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'PrismaQuery', model: query.model, action: query.action, args: query.args, // Datos originales, sin sanitizar duration: query.duration, timestamp: query.timestamp, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'PrismaError', code: error.code, message: error.message, meta: error.meta, // Datos originales, sin sanitizar clientVersion: error.clientVersion, stack: error.stack }; } serializeClient(client) { return { type: 'PrismaClient', hasConnect: typeof client.$connect === 'function', hasDisconnect: typeof client.$disconnect === 'function', hasQueryRaw: typeof client.$queryRaw === 'function', hasExecuteRaw: typeof client.$executeRaw === 'function', hasTransaction: typeof client.$transaction === 'function', hasUse: typeof client.$use === 'function', hasOn: typeof client.$on === 'function' }; } } class TypeORMSerializer { constructor() { this.name = 'typeorm'; this.priority = 80; } canSerialize(data) { return (this.isTypeORMQuery(data) || this.isTypeORMError(data) || this.isTypeORMEntity(data) || this.isTypeORMRepository(data) || this.isTypeORMConnection(data)); } getComplexity(data) { if (this.isTypeORMQuery(data)) { return this.assessQueryComplexity(data); } if (this.isTypeORMError(data)) { return 'low'; } if (this.isTypeORMEntity(data)) { return this.assessEntityComplexity(data); } if (this.isTypeORMRepository(data)) { return 'medium'; } if (this.isTypeORMConnection(data)) { return 'low'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isTypeORMQuery(data)) { result = this.serializeQuery(data); } else if (this.isTypeORMError(data)) { result = this.serializeError(data); } else if (this.isTypeORMEntity(data)) { result = this.serializeEntity(data); } else if (this.isTypeORMRepository(data)) { result = this.serializeRepository(data); } else if (this.isTypeORMConnection(data)) { result = this.serializeConnection(data); } else { throw new Error('Tipo de dato TypeORM no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización TypeORM', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isTypeORMQuery(data) { return (data && typeof data === 'object' && typeof data.sql === 'string' && (data.parameters === undefined || Array.isArray(data.parameters))); } isTypeORMError(data) { return (data && typeof data === 'object' && typeof data.message === 'string' && (data.code === undefined || typeof data.code === 'string')); } isTypeORMEntity(data) { return (data && typeof data === 'object' && data.constructor && data.constructor.name && (data.constructor.name.includes('Entity') || data.constructor.name.includes('Model') || data.id !== undefined)); } isTypeORMRepository(data) { return (data && typeof data === 'object' && typeof data.find === 'function' && typeof data.findOne === 'function' && typeof data.save === 'function'); } isTypeORMConnection(data) { return (data && typeof data === 'object' && typeof data.isConnected === 'function' && typeof data.close === 'function'); } assessQueryComplexity(query) { let complexity = 0; // Basado en el tipo de query if (query.queryType === 'SELECT') complexity += 1; else if (query.queryType === 'INSERT') complexity += 2; else if (query.queryType === 'UPDATE') complexity += 3; else if (query.queryType === 'DELETE') complexity += 3; // Basado en joins if (query.joins && query.joins.length > 0) { complexity += query.joins.length * 2; } // Basado en la longitud del SQL if (query.sql.length > 500) complexity += 2; else if (query.sql.length > 200) complexity += 1; // Basado en parámetros if (query.parameters && query.parameters.length > 10) complexity += 2; else if (query.parameters && query.parameters.length > 5) complexity += 1; if (complexity >= 6) return 'high'; if (complexity >= 3) return 'medium'; return 'low'; } assessEntityComplexity(entity) { const keys = Object.keys(entity); if (keys.length > 20) return 'high'; if (keys.length > 10) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'TypeORMQuery', queryType: query.queryType || 'UNKNOWN', sql: query.sql, // SQL original, sin sanitizar parameters: query.parameters, // Parámetros originales, sin sanitizar table: query.table, alias: query.alias, joins: query.joins, // Datos originales, sin sanitizar where: query.where, // Datos originales, sin sanitizar orderBy: query.orderBy, limit: query.limit, offset: query.offset, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'TypeORMError', code: error.code, message: error.message, query: error.query, // SQL original, sin sanitizar parameters: error.parameters, // Parámetros originales, sin sanitizar table: error.table, constraint: error.constraint, detail: error.detail, hint: error.hint, position: error.position, internalPosition: error.internalPosition, internalQuery: error.internalQuery, // SQL original, sin sanitizar where: error.where, // SQL original, sin sanitizar schema: error.schema, column: error.column, dataType: error.dataType }; } serializeEntity(entity) { const serialized = { type: 'TypeORMEntity', entityName: entity.constructor?.name || 'UnknownEntity', id: entity.id, fields: {} }; // Serializar campos del entity (datos originales, sin sanitizar) for (const [key, value] of Object.entries(entity)) { if (key !== 'constructor' && typeof value !== 'function') { serialized.fields[key] = value; // Valor original, sin sanitizar } } return serialized; } serializeRepository(repo) { return { type: 'TypeORMRepository', repositoryName: repo.constructor?.name || 'UnknownRepository', target: repo.target?.name || 'UnknownTarget', metadata: repo.metadata ? { tableName: repo.metadata.tableName, columns: repo.metadata.columns?.map((col) => col.propertyName) || [], relations: repo.metadata.relations?.map((rel) => rel.propertyName) || [] } : undefined }; } serializeConnection(connection) { return { type: 'TypeORMConnection', name: connection.name || 'default', isConnected: connection.isConnected ? connection.isConnected() : undefined, driver: connection.driver?.constructor?.name || 'UnknownDriver', options: connection.options ? { type: connection.options.type, host: connection.options.host, port: connection.options.port, database: connection.options.database, username: connection.options.username // Usuario original, sin sanitizar } : undefined }; } } class MySQLSerializer { constructor() { this.name = 'mysql'; this.priority = 85; } canSerialize(data) { return (this.isMySQLQuery(data) || this.isMySQLError(data) || this.isMySQLConnection(data) || this.isMySQLPool(data)); } getComplexity(data) { if (this.isMySQLQuery(data)) { return this.assessQueryComplexity(data); } if (this.isMySQLError(data)) { return 'low'; } if (this.isMySQLConnection(data)) { return 'low'; } if (this.isMySQLPool(data)) { return 'medium'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isMySQLQuery(data)) { result = this.serializeQuery(data); } else if (this.isMySQLError(data)) { result = this.serializeError(data); } else if (this.isMySQLConnection(data)) { result = this.serializeConnection(data); } else if (this.isMySQLPool(data)) { result = this.serializePool(data); } else { throw new Error('Tipo de dato MySQL no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización MySQL', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isMySQLQuery(data) { return (data && typeof data === 'object' && typeof data.sql === 'string' && (data.values === undefined || Array.isArray(data.values))); } isMySQLError(data) { return (data && typeof data === 'object' && typeof data.code === 'string' && typeof data.errno === 'number' && typeof data.sqlMessage === 'string'); } isMySQLConnection(data) { return (data && typeof data === 'object' && typeof data.query === 'function' && typeof data.connect === 'function' && typeof data.end === 'function'); } isMySQLPool(data) { return (data && typeof data === 'object' && typeof data.getConnection === 'function' && typeof data.query === 'function' && typeof data.end === 'function'); } assessQueryComplexity(query) { let complexity = 0; const sql = query.sql.toLowerCase(); // Basado en el tipo de operación if (sql.includes('select') && !sql.includes('join')) complexity += 1; else if (sql.includes('insert')) complexity += 2; else if (sql.includes('update')) complexity += 3; else if (sql.includes('delete')) complexity += 3; else if (sql.includes('create') || sql.includes('alter') || sql.includes('drop')) { complexity += 4; // DDL operations } // Basado en joins if (sql.includes('join')) { const joinCount = (sql.match(/join/g) || []).length; complexity += joinCount * 2; } // Basado en subqueries if (sql.includes('(select') || sql.includes('( select')) { const subqueryCount = (sql.match(/\(select/g) || []).length; complexity += subqueryCount * 3; } // Basado en funciones complejas if (sql.includes('group_concat') || sql.includes('json_')) complexity += 2; if (sql.includes('window') || sql.includes('over(')) complexity += 3; // Basado en la longitud del SQL if (sql.length > 1000) complexity += 3; else if (sql.length > 500) complexity += 2; else if (sql.length > 200) complexity += 1; // Basado en parámetros if (query.values && query.values.length > 20) complexity += 2; else if (query.values && query.values.length > 10) complexity += 1; if (complexity >= 8) return 'high'; if (complexity >= 4) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'MySQLQuery', sql: query.sql, // SQL original, sin sanitizar values: query.values, // Valores originales, sin sanitizar timeout: query.timeout, connectionConfig: query.connectionConfig ? { host: query.connectionConfig.host, port: query.connectionConfig.port, database: query.connectionConfig.database, user: query.connectionConfig.user, password: query.connectionConfig.password // Contraseña original, sin sanitizar } : undefined, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'MySQLError', code: error.code, errno: error.errno, sqlMessage: error.sqlMessage, sqlState: error.sqlState, index: error.index, sql: error.sql, // SQL original, sin sanitizar fatal: error.fatal }; } serializeConnection(connection) { return { type: 'MySQLConnection', threadId: connection.threadId, state: connection.state, config: connection.config ? { host: connection.config.host, port: connection.config.port, database: connection.config.database, user: connection.config.user, password: connection.config.password // Contraseña original, sin sanitizar } : undefined, hasQuery: typeof connection.query === 'function', hasConnect: typeof connection.connect === 'function', hasEnd: typeof connection.end === 'function' }; } serializePool(pool) { return { type: 'MySQLPool', config: pool.config ? { host: pool.config.host, port: pool.config.port, database: pool.config.database, user: pool.config.user, password: pool.config.password, // Contraseña original, sin sanitizar connectionLimit: pool.config.connectionLimit, acquireTimeout: pool.config.acquireTimeout, timeout: pool.config.timeout } : undefined, hasGetConnection: typeof pool.getConnection === 'function', hasQuery: typeof pool.query === 'function', hasEnd: typeof pool.end === 'function' }; } } class PostgreSQLSerializer { constructor() { this.name = 'postgresql'; this.priority = 90; } canSerialize(data) { return (this.isPostgreSQLQuery(data) || this.isPostgreSQLError(data) || this.isPostgreSQLClient(data) || this.isPostgreSQLPool(data)); } getComplexity(data) { if (this.isPostgreSQLQuery(data)) { return this.assessQueryComplexity(data); } if (this.isPostgreSQLError(data)) { return 'low'; } if (this.isPostgreSQLClient(data)) { return 'low'; } if (this.isPostgreSQLPool(data)) { return 'medium'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isPostgreSQLQuery(data)) { result = this.serializeQuery(data); } else if (this.isPostgreSQLError(data)) { result = this.serializeError(data); } else if (this.isPostgreSQLClient(data)) { result = this.serializeClient(data); } else if (this.isPostgreSQLPool(data)) { result = this.serializePool(data); } else { throw new Error('Tipo de dato PostgreSQL no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización PostgreSQL', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isPostgreSQLQuery(data) { return (data && typeof data === 'object' && typeof data.text === 'string' && (data.values === undefined || Array.isArray(data.values))); } isPostgreSQLError(data) { return (data && typeof data === 'object' && typeof data.code === 'string' && typeof data.message === 'string'); } isPostgreSQLClient(data) { return (data && typeof data === 'object' && typeof data.query === 'function' && typeof data.connect === 'function' && typeof data.end === 'function'); } isPostgreSQLPool(data) { return (data && typeof data === 'object' && typeof data.connect === 'function' && typeof data.query === 'function' && typeof data.end === 'function'); } assessQueryComplexity(query) { let complexity = 0; const sql = query.text.toLowerCase(); // Basado en el tipo de operación if (sql.includes('select') && !sql.includes('join')) complexity += 1; else if (sql.includes('insert')) complexity += 2; else if (sql.includes('update')) complexity += 3; else if (sql.includes('delete')) complexity += 3; else if (sql.includes('create') || sql.includes('alter') || sql.includes('drop')) { complexity += 4; // DDL operations } // Basado en CTEs (Common Table Expressions) if (sql.includes('with')) { const cteCount = (sql.match(/with\s+\w+\s+as/gi) || []).length; complexity += cteCount * 3; } // Basado en window functions if (sql.includes('over(')) { const windowCount = (sql.match(/over\s*\(/gi) || []).length; complexity += windowCount * 2; } // Basado en joins if (sql.includes('join')) { const joinCount = (sql.match(/join/g) || []).length; complexity += joinCount * 2; } // Basado en subqueries if (sql.includes('(select') || sql.includes('( select')) { const subqueryCount = (sql.match(/\(select/g) || []).length; complexity += subqueryCount * 3; } // Basado en funciones complejas de PostgreSQL if (sql.includes('json_') || sql.includes('array_')) complexity += 2; if (sql.includes('regexp_') || sql.includes('similar to')) complexity += 2; if (sql.includes('full text') || sql.includes('ts_')) complexity += 3; // Basado en la longitud del SQL if (sql.length > 1000) complexity += 3; else if (sql.length > 500) complexity += 2; else if (sql.length > 200) complexity += 1; // Basado en parámetros if (query.values && query.values.length > 20) complexity += 2; else if (query.values && query.values.length > 10) complexity += 1; if (complexity >= 8) return 'high'; if (complexity >= 4) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'PostgreSQLQuery', text: query.text, // SQL original, sin sanitizar values: query.values, // Valores originales, sin sanitizar name: query.name, rowMode: query.rowMode, types: query.types, config: query.config ? { host: query.config.host, port: query.config.port, database: query.config.database, user: query.config.user, password: query.config.password // Contraseña original, sin sanitizar } : undefined, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'PostgreSQLError', code: error.code, message: error.message, detail: error.detail, hint: error.hint, position: error.position, internalPosition: error.internalPosition, internalQuery: error.internalQuery, // SQL original, sin sanitizar where: error.where, // SQL original, sin sanitizar schema: error.schema, table: error.table, column: error.column, dataType: error.dataType, constraint: error.constraint, file: error.file, line: error.line, routine: error.routine }; } serializeClient(client) { return { type: 'PostgreSQLClient', processID: client.processID, secretKey: client.secretKey, config: client.connectionParameters ? { host: client.connectionParameters.host, port: client.connectionParameters.port, database: client.connectionParameters.database, user: client.connectionParameters.user, password: client.connectionParameters.password // Contraseña original, sin sanitizar } : undefined, hasQuery: typeof client.query === 'function', hasConnect: typeof client.connect === 'function', hasEnd: typeof client.end === 'function' }; } serializePool(pool) { return { type: 'PostgreSQLPool', totalCount: pool.totalCount, idleCount: pool.idleCount, waitingCount: pool.waitingCount, config: pool.options ? { host: pool.options.host, port: pool.options.port, database: pool.options.database, user: pool.options.user, password: pool.options.password, // Contraseña original, sin sanitizar max: pool.options.max, idleTimeoutMillis: pool.options.idleTimeoutMillis, connectionTimeoutMillis: pool.options.connectionTimeoutMillis } : undefined, hasConnect: typeof pool.connect === 'function', hasQuery: typeof pool.query === 'function', hasEnd: typeof pool.end === 'function' }; } } class SQLServerSerializer { constructor() { this.name = 'sqlserver'; this.priority = 95; } canSerialize(data) { return (this.isSQLServerQuery(data) || this.isSQLServerError(data) || this.isSQLServerConnection(data) || this.isSQLServerPool(data)); } getComplexity(data) { if (this.isSQLServerQuery(data)) { return this.assessQueryComplexity(data); } if (this.isSQLServerError(data)) { return 'low'; } if (this.isSQLServerConnection(data)) { return 'low'; } if (this.isSQLServerPool(data)) { return 'medium'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isSQLServerQuery(data)) { result = this.serializeQuery(data); } else if (this.isSQLServerError(data)) { result = this.serializeError(data); } else if (this.isSQLServerConnection(data)) { result = this.serializeConnection(data); } else if (this.isSQLServerPool(data)) { result = this.serializePool(data); } else { throw new Error('Tipo de dato SQL Server no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización SQL Server', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isSQLServerQuery(data) { return (data && typeof data === 'object' && typeof data.query === 'string' && (data.parameters === undefined || Array.isArray(data.parameters))); } isSQLServerError(data) { return (data && typeof data === 'object' && typeof data.code === 'string' && typeof data.number === 'number' && typeof data.message === 'string'); } isSQLServerConnection(data) { return (data && typeof data === 'object' && typeof data.query === 'function' && typeof data.connect === 'function' && typeof data.close === 'function'); } isSQLServerPool(data) { return (data && typeof data === 'object' && typeof data.connect === 'function' && typeof data.query === 'function' && typeof data.close === 'function'); } assessQueryComplexity(query) { let complexity = 0; const sql = query.query.toLowerCase(); // Basado en el tipo de operación if (sql.includes('select') && !sql.includes('join')) complexity += 1; else if (sql.includes('insert')) complexity += 2; else if (sql.includes('update')) complexity += 3; else if (sql.includes('delete')) complexity += 3; else if (sql.includes('create') || sql.includes('alter') || sql.includes('drop')) { complexity += 4; // DDL operations } // Basado en stored procedures if (sql.includes('exec') || sql.includes('execute')) { complexity += 3; // Stored procedures son más complejas } // Basado en CTEs (Common Table Expressions) if (sql.includes('with')) { const cteCount = (sql.match(/with\s+\w+\s+as/gi) || []).length; complexity += cteCount * 3; } // Basado en window functions if (sql.includes('over(')) { const windowCount = (sql.match(/over\s*\(/gi) || []).length; complexity += windowCount * 2; } // Basado en joins if (sql.includes('join')) { const joinCount = (sql.match(/join/g) || []).length; complexity += joinCount * 2; } // Basado en subqueries if (sql.includes('(select') || sql.includes('( select')) { const subqueryCount = (sql.match(/\(select/g) || []).length; complexity += subqueryCount * 3; } // Basado en funciones específicas de SQL Server if (sql.includes('row_number()') || sql.includes('rank()') || sql.includes('dense_rank()')) { complexity += 2; } if (sql.includes('pivot') || sql.includes('unpivot')) complexity += 3; if (sql.includes('merge')) complexity += 3; if (sql.includes('apply')) complexity += 2; // Basado en la longitud del SQL if (sql.length > 1000) complexity += 3; else if (sql.length > 500) complexity += 2; else if (sql.length > 200) complexity += 1; // Basado en parámetros if (query.parameters && query.parameters.length > 20) complexity += 2; else if (query.parameters && query.parameters.length > 10) complexity += 1; if (complexity >= 8) return 'high'; if (complexity >= 4) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'SQLServerQuery', query: query.query, // SQL original, sin sanitizar parameters: query.parameters, // Parámetros originales, sin sanitizar options: query.options, config: query.config ? { server: query.config.server, database: query.config.database, user: query.config.user, password: query.config.password, // Contraseña original, sin sanitizar port: query.config.port } : undefined, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'SQLServerError', code: error.code, number: error.number, state: error.state, class: error.class, lineNumber: error.lineNumber, serverName: error.serverName, procName: error.procName, message: error.message, sql: error.sql // SQL original, sin sanitizar }; } serializeConnection(connection) { return { type: 'SQLServerConnection', config: connection.config ? { server: connection.config.server, database: connection.config.database, user: connection.config.user, password: connection.config.password, // Contraseña original, sin sanitizar port: connection.config.port, options: connection.config.options } : undefined, hasQuery: typeof connection.query === 'function', hasConnect: typeof connection.connect === 'function', hasClose: typeof connection.close === 'function' }; } serializePool(pool) { return { type: 'SQLServerPool', config: pool.config ? { server: pool.config.server, database: pool.config.database, user: pool.config.user, password: pool.config.password, // Contraseña original, sin sanitizar port: pool.config.port, pool: { max: pool.config.pool?.max, min: pool.config.pool?.min, idleTimeoutMillis: pool.config.pool?.idleTimeoutMillis } } : undefined, hasConnect: typeof pool.connect === 'function', hasQuery: typeof pool.query === 'function', hasClose: typeof pool.close === 'function' }; } } class OracleSerializer { constructor() { this.name = 'oracle'; this.priority = 100; } canSerialize(data) { return (this.isOracleQuery(data) || this.isOracleError(data) || this.isOracleConnection(data) || this.isOraclePool(data)); } getComplexity(data) { if (this.isOracleQuery(data)) { return this.assessQueryComplexity(data); } if (this.isOracleError(data)) { return 'low'; } if (this.isOracleConnection(data)) { return 'low'; } if (this.isOraclePool(data)) { return 'medium'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isOracleQuery(data)) { result = this.serializeQuery(data); } else if (this.isOracleError(data)) { result = this.serializeError(data); } else if (this.isOracleConnection(data)) { result = this.serializeConnection(data); } else if (this.isOraclePool(data)) { result = this.serializePool(data); } else { throw new Error('Tipo de dato Oracle no reconocido'); } const duration = Date.now() - startTime; // ✅ Verificar que la serialización respeta el timeout del contexto const timeout = context.timeout || 50; if (duration > timeout) { throw new Error(`Serialización lenta: ${duration}ms (máximo ${timeout}ms)`); } return { success: true, data: result, metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } catch (error) { const duration = Date.now() - startTime; return { success: false, error: error instanceof Error ? error.message : 'Error desconocido en serialización Oracle', metadata: { serializer: this.name, complexity: this.getComplexity(data), duration, timestamp: new Date().toISOString() } }; } } isOracleQuery(data) { return (data && typeof data === 'object' && typeof data.sql === 'string' && (data.bindParams === undefined || Array.isArray(data.bindParams))); } isOracleError(data) { return (data && typeof data === 'object' && typeof data.code === 'number' && typeof data.message === 'string'); } isOracleConnection(data) { return (data && typeof data === 'object' && typeof data.execute === 'function' && typeof data.commit === 'function' && typeof data.rollback === 'function'); } isOraclePool(data) { return (data && typeof data === 'object' && typeof data.getConnection === 'function' && typeof data.execute === 'function' && typeof data.close === 'function'); } assessQueryComplexity(query) { let complexity = 0; const sql = query.sql.toLowerCase(); // Basado en el tipo de operación if (sql.includes('select') && !sql.includes('join')) complexity += 1; else if (sql.includes('insert')) complexity += 2; else if (sql.includes('update')) complexity += 3; else if (sql.includes('delete')) complexity += 3; else if (sql.includes('create') || sql.includes('alter') || sql.includes('drop')) { complexity += 4; // DDL operations } // Basado en PL/SQL if (sql.includes('begin') || sql.includes('declare')) { complexity += 4; // PL/SQL blocks son complejos } // Basado en stored procedures if (sql.includes('call') || sql.includes('execute')) { complexity += 3; } // Basado en CTEs (Common Table Expressions) if (sql.includes('with')) { const cteCount = (sql.match(/with\s+\w+\s+as/gi) || []).length; complexity += cteCount * 3; } // Basado en window functions if (sql.includes('over(')) { const windowCount = (sql.match(/over\s*\(/gi) || []).length; complexity += windowCount * 2; } // Basado en joins if (sql.includes('join')) { const joinCount = (sql.match(/join/g) || []).length; complexity += joinCount * 2; } // Basado en subqueries if (sql.includes('(select') || sql.includes('( select')) { const subqueryCount = (sql.match(/\(select/g) || []).length; complexity += subqueryCount * 3; } // Basado en funciones específicas de Oracle if (sql.includes('connect by') || sql.includes('start with')) { complexity += 3; // Hierarchical queries } if (sql.includes('pivot') || sql.includes('unpivot')) complexity += 3; if (sql.includes('merge')) complexity += 3; if (sql.includes('model')) complexity += 4; // MODEL clause if (sql.includes('flashback')) complexity += 2; // Basado en la longitud del SQL if (sql.length > 1000) complexity += 3; else if (sql.length > 500) complexity += 2; else if (sql.length > 200) complexity += 1; // Basado en parámetros if (query.bindParams && query.bindParams.length > 20) complexity += 2; else if (query.bindParams && query.bindParams.length > 10) complexity += 1; if (complexity >= 8) return 'high'; if (complexity >= 4) return 'medium'; return 'low'; } serializeQuery(query) { return { type: 'OracleQuery', sql: query.sql, // SQL original, sin sanitizar bindParams: query.bindParams, // Parámetros originales, sin sanitizar options: query.options, config: query.config ? { host: query.config.host, port: query.config.port, serviceName: query.config.serviceName, user: query.config.user, password: query.config.password, // Contraseña original, sin sanitizar connectString: query.config.connectString // String de conexión original, sin sanitizar } : undefined, complexity: this.assessQueryComplexity(query) }; } serializeError(error) { return { type: 'OracleError', code: error.code, message: error.message, offset: error.offset, sql: error.sql, // SQL original, sin sanitizar cause: error.cause }; } serializeConnection(connection) { return { type: 'OracleConnection', oracleServerVersion: connection.oracleServerVersion, oracleServerVersionString: connection.oracleServerVersionString, config: connection.config ? { host: connection.config.host, port: connection.config.port, serviceName: connection.config.serviceName, user: connection.config.user, password: connection.config.password, // Contraseña original, sin sanitizar connectString: connection.config.connectString // String de conexión original, sin sanitizar } : undefined, hasExecute: typeof connection.execute === 'function', hasCommit: typeof connection.commit === 'function', hasRollback: typeof connection.rollback === 'function' }; } serializePool(pool) { return { type: 'OraclePool', poolMax: pool.poolMax, poolMin: pool.poolMin, poolIncrement: pool.poolIncrement, poolTimeout: pool.poolTimeout, config: pool.config ? { host: pool.config.host, port: pool.config.port, serviceName: pool.config.serviceName, user: pool.config.user, password: pool.config.password, // Contraseña original, sin sanitizar connectString: pool.config.connectString // String de conexión original, sin sanitizar } : undefined, hasGetConnection: typeof pool.getConnection === 'function', hasExecute: typeof pool.execute === 'function', hasClose: typeof pool.close === 'function' }; } } class MongoDBSerializer { constructor() { this.name = 'mongodb'; this.priority = 70; } canSerialize(data) { return (this.isMongoDBQuery(data) || this.isMongoDBAggregation(data) || this.isMongoDBError(data)); } getComplexity(data) { if (this.isMongoDBQuery(data)) { return this.assessQueryComplexity(data); } if (this.isMongoDBAggregation(data)) { return this.assessAggregationComplexity(data); } if (this.isMongoDBError(data)) { return 'low'; } return 'low'; } async serialize(data, context) { const startTime = Date.now(); try { let result; if (this.isMongoDBQuery(data)) { result = t