[1] 호출 전/후 로그 출력

// 데코레이터 함수 정의
function logMethod(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    // 새로운 메서드 정의
    descriptor.value = function (...args: any[]) {
        // 함수 호출 전 로깅
        console.log(`Calling method ${key} with arguments: ${JSON.stringify(args)}`);

        // 원본 메서드 호출
        const result = originalMethod.apply(this, args);

        // 함수 호출 후 로깅
        console.log(`Method ${key} returned: ${JSON.stringify(result)}`);

        return result;
    };

    return descriptor;
}

// 클래스 정의
class ExampleClass {
    // 멤버 함수에 데코레이터 적용
    @logMethod
    public exampleMethod(message: string): string {
        return `Received message: ${message}`;
    }
}

// 인스턴스 생성
const instance = new ExampleClass();

// 데코레이터에 의해 메서드 호출 시 로그 출력
const result = instance.exampleMethod('Hello, Decorators!');
console.log(result);

[2] 쿼리를 실행하는 서비스 함수 - 트랜잭션으로 래핑

public static Atomic (target: any, name: string, descriptor: PropertyDescriptor) {
    const originFunc  = descriptor.value;
    const wrappedFunc = async function (...args: any[]) {
        let ret: any = undefined;

        await QueryUtil.BeginTransaction();
        
        try {
            ret = await originFunc.apply(this, args);
            await QueryUtil.CommitTransaction();
        }
        catch (e: any) {
            await QueryUtil.RollbackTransaction();
            throw e;
        }

        return ret;
    }
    descriptor.value = wrappedFunc;
}