File
exclude
|
exclude: string[]
|
Type : string[]
|
Optional
|
syncFunc
|
syncFunc: string[]
|
Type : string[]
|
Optional
|
import { Logger } from "@nestjs/common";
export interface ApplyToAllOpts {
syncFunc?: string[],
exclude?: string[],
}
export const logError = (logger: Logger, name: string, error: any) =>
logger.error(`[${name}]: ${error.message}`, error.stack);
/**
* Decorator to wrap method with try catch
*
* @param serviceName {string} - name of class to for logger
* @param rethrow {boolean} - re-throw exception, default false
*
*/
export function CatchAndLogError(serviceName: string, rethrow = false) {
return (
target: any,
propertyKey: string,
propertyDescriptor: PropertyDescriptor
) => {
const originalMethod = propertyDescriptor.value;
propertyDescriptor.value = async function (...args: any[]) {
try {
return await originalMethod.apply(this, args);
} catch (error) {
const logger: Logger = new Logger(serviceName);
logError(logger, originalMethod?.name, error);
if (rethrow) throw error;
}
};
};
}
/**
* Decorator to apply decorator to all methods in class
*
* @param decorator {MethodDecorator} - decorator
* @param opts {ApplyToAllOpts} - options to exclude methods, and sync functions:
* exclude - array of strings with name of methods to exclude from apply
* syncFunc - array of strings with name of sync methods to correctly apply decorator to them, or in another case sync methods will return the Promise
*
*/
export const ApplyDecoratorToAll = (
decorator: MethodDecorator,
opts: ApplyToAllOpts,
) => {
return (target: any) => {
const descriptors = Object.getOwnPropertyDescriptors(target.prototype);
for (const [propName, descriptor] of Object.entries(descriptors)) {
const isMethod = descriptor.value instanceof Function &&
propName != 'constructor';
if (!isMethod) continue;
if (opts?.exclude?.includes(propName)) continue;
const originalMethod = descriptor.value;
// apply decorator
decorator(target, propName, descriptor)
// copy metadata
if (originalMethod != descriptor.value) {
const metadataKeys = Reflect.getMetadataKeys(originalMethod);
metadataKeys.map((key) => {
const value = Reflect.getMetadata(key, originalMethod);
Reflect.defineMetadata(key, value, descriptor.value);
});
}
// Do not define property if sync function, or will be returned as promise
if (opts?.syncFunc?.includes(propName)) continue;
Object.defineProperty(target.prototype, propName, descriptor);
}
};
};