@syntropylog/adapters
Version:
External adapters for SyntropyLog framework
224 lines • 7.96 kB
JavaScript
export 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 = this.serializeQuery(data);
}
else if (this.isMongoDBAggregation(data)) {
result = this.serializeAggregation(data);
}
else if (this.isMongoDBError(data)) {
result = this.serializeError(data);
}
else {
throw new Error('Tipo de dato MongoDB 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 MongoDB',
metadata: {
serializer: this.name,
complexity: this.getComplexity(data),
duration,
timestamp: new Date().toISOString()
}
};
}
}
isMongoDBQuery(data) {
return data && (data.collection !== undefined ||
data.operation !== undefined ||
data.filter !== undefined ||
data.projection !== undefined ||
data.update !== undefined);
}
isMongoDBAggregation(data) {
return data && (data.pipeline !== undefined ||
data.stages !== undefined);
}
isMongoDBError(data) {
return data && (data.code !== undefined ||
data.codeName !== undefined ||
data.writeErrors !== undefined ||
data.writeConcernErrors !== undefined ||
(data.message && typeof data.message === 'string'));
}
assessQueryComplexity(query) {
let complexity = 0;
// Basado en la operación
if (query.operation === 'find')
complexity += 1;
else if (query.operation === 'findOne')
complexity += 1;
else if (query.operation === 'insertOne')
complexity += 2;
else if (query.operation === 'insertMany')
complexity += 3;
else if (query.operation === 'updateOne')
complexity += 2;
else if (query.operation === 'updateMany')
complexity += 3;
else if (query.operation === 'deleteOne')
complexity += 2;
else if (query.operation === 'deleteMany')
complexity += 3;
else if (query.operation === 'replaceOne')
complexity += 2;
else if (query.operation === 'bulkWrite')
complexity += 4;
// Basado en argumentos complejos
if (query.filter && typeof query.filter === 'object') {
const filterKeys = Object.keys(query.filter);
complexity += Math.min(filterKeys.length, 3);
}
if (query.projection)
complexity += 1;
if (query.sort)
complexity += 1;
if (query.limit)
complexity += 1;
if (query.skip)
complexity += 1;
if (query.update && typeof query.update === 'object') {
const updateKeys = Object.keys(query.update);
complexity += Math.min(updateKeys.length, 2);
}
if (complexity >= 6)
return 'high';
if (complexity >= 3)
return 'medium';
return 'low';
}
assessAggregationComplexity(aggregation) {
let complexity = 0;
if (aggregation.pipeline && Array.isArray(aggregation.pipeline)) {
complexity += aggregation.pipeline.length;
}
if (aggregation.stages && Array.isArray(aggregation.stages)) {
complexity += aggregation.stages.length;
}
if (complexity >= 8)
return 'high';
if (complexity >= 4)
return 'medium';
return 'low';
}
serializeQuery(data) {
return {
type: 'MongoDBQuery',
collection: data.collection,
operation: data.operation,
filter: data.filter, // Datos originales, sin sanitizar
projection: data.projection,
sort: data.sort,
update: data.update,
limit: data.limit,
skip: data.skip,
duration: data.duration,
documentsAffected: data.documentsAffected,
documentsReturned: data.documentsReturned,
complexity: this.assessQueryComplexity(data)
};
}
serializeAggregation(data) {
return {
type: 'MongoDBAggregation',
collection: data.collection,
pipeline: data.pipeline, // Datos originales, sin sanitizar
stages: data.stages,
duration: data.duration,
documentsReturned: data.documentsReturned,
complexity: this.assessAggregationComplexity(data)
};
}
serializeError(data) {
return {
type: 'MongoDBError',
code: data.code,
codeName: data.codeName,
message: data.message,
operation: data.operation,
collection: data.collection,
filter: data.filter, // Datos originales, sin sanitizar
pipeline: data.pipeline,
writeErrors: data.writeErrors,
writeConcernErrors: data.writeConcernErrors
};
}
sanitizePipeline(pipeline) {
if (!pipeline || !Array.isArray(pipeline))
return pipeline;
return pipeline.map(stage => {
if (typeof stage === 'object' && stage !== null) {
return this.sanitizeObject(stage);
}
return stage;
});
}
sanitizeObject(obj) {
if (typeof obj !== 'object' || obj === null)
return obj;
const result = Array.isArray(obj) ? [] : {};
const sensitiveFields = [
'password', 'token', 'secret', 'key', 'auth', 'credential',
'hash', 'salt', 'encryption', 'private', 'sensitive'
];
for (const [key, value] of Object.entries(obj)) {
const lowerKey = key.toLowerCase();
const isSensitive = sensitiveFields.some(field => lowerKey.includes(field));
if (isSensitive) {
result[key] = '[REDACTED]';
}
else if (typeof value === 'object' && value !== null) {
result[key] = this.sanitizeObject(value);
}
else {
result[key] = value;
}
}
return result;
}
}
//# sourceMappingURL=MongoDBSerializer.js.map