@mwcp/kmore
Version:
midway component for knex, supports declarative transaction and OpenTelemetry
97 lines • 4.32 kB
JavaScript
import assert from 'node:assert';
import { deepmerge } from '@mwcp/share';
import { genError } from '@waiting/shared-core';
import { PropagationType } from 'kmore';
import { initRowLockOptions } from '../lib/config.js';
import { genCallerKey } from '../lib/propagation/trx-status.helper.js';
import { ConfigKey, Msg } from '../lib/types.js';
export async function genDecoratorExecutorOptionsAsync(optionsBase, optionsExt) {
const { mergedDecoratorParam } = optionsBase;
assert(optionsExt.propagationConfig, Msg.propagationConfigIsUndefined);
const initArgs = {
dbSourceName: void 0,
propagationType: PropagationType.REQUIRED,
rowLockOptions: {
...initRowLockOptions,
},
};
assert(optionsExt.trxStatusSvc, 'genDecoratorExecutorOptionsAsync() optionsExt.trxStatusSvc is undefined');
const args = deepmerge.all([
initArgs,
mergedDecoratorParam ?? {},
]);
const ret = {
...optionsBase,
...optionsExt,
mergedDecoratorParam: args,
};
const { dbSourceName } = args;
if (!dbSourceName) {
const dbInstanceCount = ret.trxStatusSvc.getDbInstanceCount();
assert(dbInstanceCount <= 1, 'genDecoratorExecutorOptionsAsync(): dbSourceName is undefined, but multiple dbSources found');
}
return ret;
}
export async function before(options) {
const { instanceName, mergedDecoratorParam, methodName, trxStatusSvc, } = options;
assert(mergedDecoratorParam?.rowLockOptions, 'mergedDecoratorParam.rowLockOptions is undefined');
const type = mergedDecoratorParam.propagationType;
assert(type, 'propagationType is undefined');
const { readRowLockLevel, writeRowLockLevel } = mergedDecoratorParam.rowLockOptions;
assert(readRowLockLevel, 'readRowLockLevel is undefined');
assert(writeRowLockLevel, 'writeRowLockLevel is undefined');
const className = instanceName;
assert(className, 'instance.constructor.name is undefined');
const opts = {
dbSourceName: mergedDecoratorParam.dbSourceName, // can be undefined if only one dbSource
scope: options.scope,
type,
className,
funcName: methodName,
readRowLockLevel,
writeRowLockLevel,
};
assert(opts.type, 'opts.type propagationType is undefined');
assert(opts.readRowLockLevel, 'opts.readRowLockLevel is undefined');
assert(opts.writeRowLockLevel, 'opts.writeRowLockLevel is undefined');
let callerKey = void 0;
try {
callerKey = trxStatusSvc.registerPropagation(opts);
options.callerKey = callerKey;
}
catch (ex) {
// console.error(msg, ex)
const error = genError({ error: ex, altMessage: Msg.registerPropagationFailed });
const key = genCallerKey(opts.className, opts.funcName);
options.callerKey = key;
options.error = error;
throw error;
}
assert(callerKey, `[@mwcp/${ConfigKey.namespace}] generate callerKey failed`);
}
export async function afterReturn(options) {
const { trxStatusSvc, callerKey, mergedDecoratorParam } = options;
if (!callerKey) {
return;
}
assert(!options.error, `[@mwcp/${ConfigKey.namespace}] options.error is not undefined in afterAsync().
It should be handled in after() lifecycle redirect to afterThrow() with errorExt.
Error: ${options.error?.message}`);
await trxStatusSvc.tryCommitTrxIfKeyIsEntryTop(mergedDecoratorParam?.dbSourceName, options.scope, callerKey);
}
export function afterThrow(options, trxStatusService) {
const { error } = options;
assert(error instanceof Error, `[@mwcp/${ConfigKey.namespace}] ${ConfigKey.Transactional}() afterThrow error is not instance of Error`);
const { callerKey, mergedDecoratorParam } = options;
const key = callerKey ?? genCallerKey(options.instanceName, options.methodName);
const tkey = trxStatusService.retrieveUniqueTopCallerKey(mergedDecoratorParam?.dbSourceName, options.scope, key);
if (tkey && tkey === key) {
if (options.methodIsAsyncFunction) {
return trxStatusService.trxRollbackEntry(mergedDecoratorParam?.dbSourceName, options.scope, key).then(() => {
throw error;
});
}
}
throw error;
}
//# sourceMappingURL=transactional.helper.js.map