'Decorator in Node - is it possible to iterate through class methods inside the constructor in order to override / apply a decorator to them
Up front I'm new to Node / Javascript an. What I am trying to do is to add a logging to my repository using a decorator function. Therefor I'm trying to iterate though each function from inside the constructor and override it with something like: "
Object.getOwnPropertyNames(Repository.prototype).forEach((func) => this.decorator(func));"
My problem is that "Object.getOwnPropertyNames" only returns the function names instead of the actual function. Is there a way to apply this decorator to each function?
"use strict"
const db = require("./Database/db_operations");
const logger = require("./utils/logger")
const {createTables} = require("./Database/db_operations");
const loggingTypes = require("./utils/logginTypes")
class Repository {
async saveTermin(Termin) {
}
async saveToDo(toDo) {
return await db.saveToDo(toDo);
}
async saveAppointment(Appointment) {
return await db.saveAppointment(Appointment);
}
async updateAppointment(Appointment) {
return await db.updateAppointment(Appointment);
}
async deleteAppointment(uuid) {
return await db.deleteAppointment(uuid);
}
async saveAppointmentParticipants(appointment) {
return await db.saveAppointmentParticipants(appointment);
}
async saveAppointmentFiles(appointment) {
return await db.saveAppointmentFiles(appointment)
}
async getAppointmentFiles(appointment) {
return await db.getAppointmentFiles(appointment)
}
async deleteToDo(todo) {
return await db.deleteToDo(todo)
}
}
// All functions will be mapped to there type to optimize logging. If a function is not mapped to its type,
// it will be automaticly assigned to the "unspecified type". Logging will still work, but depending on what
// arguments are given and what is returned, the output might not perfectly fit
const funcMapping = new Map();
// GET
funcMapping.set(Repository.prototype.getAppointmentFiles, loggingTypes.GET);
funcMapping.set(Repository.prototype.getAllDatas, loggingTypes.GET);
funcMapping.set(Repository.prototype.getAllToDos, loggingTypes.GET);
//SAVE
funcMapping.set(Repository.prototype.saveToDo, loggingTypes.SAVE);
funcMapping.set(Repository.prototype.saveAppointment, loggingTypes.SAVE);
funcMapping.set(Repository.prototype.saveAppointmentParticipants, loggingTypes.SAVE);
//DELETE
funcMapping.set(Repository.prototype.deleteAppointment, loggingTypes.DELETE);
funcMapping.set(Repository.prototype.deleteToDo, loggingTypes.DELETE);
Object.getOwnPropertyNames(Repository.prototype)
.forEach(name => {
const func = Repository.prototype[name];
// checking loggingTypes - if no type is assigned function will be assigned to "UNASSIGNED".
// console.log(funcMapping.has(func) +" "+ func.name)
if (!funcMapping.has(func)) {
funcMapping.set(func, loggingTypes.UNASSIGNED);
}
// function will only be wrapped if logging is enabled.
if (funcMapping.get(func)[1]) {
Repository.prototype[name] = async function (...args) {
// calls the original methode
const returnValue = await func.apply(this, args);
const argumentsInArray = Array.prototype.slice.call(args);
// Put any additional logic here and it will be applied -> magic
// Logging
db.writeLogging(logger(func, returnValue, funcMapping.get(func)[0]), args).then(() => {
console.log(`Function "${name}()" was successfully logged and saved to Database`)
}).catch(e => {
console.log(`Function "${name}()" could not be logged and saved to Database. ${func}`)
console.log(e)
})
return returnValue;
}
}
});
module.exports = new Repository();
const appointment_model = require('../models/Appointment');
const contact_model = require('../models/Contact');
const toDo_model = require('../models/ToDo');
const file_model = require('../models/File');
const loggingTypes = require("./logginTypes")
function log() {
// returns a function that returns an object. When this function is then called the object is returned
return function decorator(funcToLog, returnValue, funcType, ...args) {
// console.log("arguments in logger" + args);
// create prototype for object that later will be passed to database
const descriptor = function (user, change, changedAt) {
this.user = user; // some user id
this.change = change; //
this.changedAt = changedAt; // date when changes occoured
this.appointmentId = getUuid(appointment_model);
this.todoId = getUuid(toDo_model);
this.contactId = getUuid(contact_model);
this.fileId = getUuid(file_model);
};
// contains all logging Data about the function beeing called -> name of function, usedArguments and returnValue
function getChanges(func, funcType, returnValue, args) {
let changes = null;
switch (funcType) {
case loggingTypes.GET[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.SAVE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args}, // ?
newData: returnValue // could call function here
}
break;
case loggingTypes.UPDATE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.DELETE[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
break;
case loggingTypes.UNASSIGNED[0]:
changes = {
funcName: func.name, //
funcType: funcType, //
dataSetToChange: {...args},
newData: returnValue
}
}
return changes;
}
function getUuid(model_type) {
let uuid = null;
console.log(args)
for (let i = 0; i < args.length; i++) {
console.log(args[i])
if (args[i] instanceof model_type) {
uuid = parseInt(args[i].uuid);
}
return uuid;
}
}
return new descriptor("someUserId", JSON.stringify(getChanges(funcToLog, funcType, returnValue, args)), new Date())
}
}
module.exports = log();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
