@malagu/typeorm
Version:
76 lines (67 loc) • 2.85 kB
text/typescript
import { IsolationLevel } from 'typeorm/driver/types/IsolationLevel';
import { DEFAULT_CONNECTION_NAME } from '../../common';
import { EntityManager } from 'typeorm';
import { OrmContext } from '../context';
import { getConnection } from '../utils';
export enum Propagation {
Required, RequiresNew
}
export interface TransactionalOption {
name?: string;
isolation?: IsolationLevel;
propagation?: Propagation;
readOnly?: boolean;
}
export namespace TransactionalOption {
export function is(option: any): option is TransactionalOption {
return option && (option.name !== undefined || option.isolation !== undefined || option.readOnly !== undefined);
}
}
export interface TransactionalDecorator {
(nameOrTransactionalOption?: string | TransactionalOption): MethodDecorator;
}
export const Transactional = <TransactionalDecorator>function (nameOrTransactionalOption?: string | TransactionalOption): MethodDecorator {
const { name, isolation, propagation, readOnly } = getTransactionalOption(nameOrTransactionalOption);
return (target: Object, methodName: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
if (propagation === Propagation.Required) {
const em = OrmContext.getEntityManager(name);
if (em && em.queryRunner && (em.queryRunner.isTransactionActive || readOnly)) {
return originalMethod.apply(this, args);
}
}
const callback = async (entityManager: EntityManager) => {
OrmContext.pushEntityManager(name!, entityManager);
try {
return await originalMethod.apply(this, args);
} finally {
OrmContext.popEntityManager(name!);
}
};
const conn = await getConnection(name);
const manager = conn.manager;
if (readOnly) {
return callback(manager);
} else if (isolation) {
return manager.transaction(isolation, callback);
} else {
return manager.transaction(callback);
}
};
};
};
export function getTransactionalOption(nameOrTransactionalOption?: string | TransactionalOption) {
const defaultOption = {
name: DEFAULT_CONNECTION_NAME,
propagation: Propagation.Required,
readOnly: false
};
let option: TransactionalOption = defaultOption;
if (TransactionalOption.is(nameOrTransactionalOption)) {
option = { ...defaultOption, ...nameOrTransactionalOption };
} else if (nameOrTransactionalOption) {
option = { ...defaultOption, name: nameOrTransactionalOption };
}
return option;
}