UNPKG

@mwcp/kmore

Version:

midway component for knex, supports declarative transaction and OpenTelemetry

134 lines 4.31 kB
import assert from 'node:assert'; import { relative } from 'node:path'; import { AttrNames } from '@mwcp/otel'; import { getStackCallerSites } from '@waiting/shared-core'; import { QueryBuilderExtKey, RowLockLevel, } from 'kmore'; export function genCallerKey(className, funcName) { assert(className, 'className is undefined'); assert(funcName, 'funcName is undefined'); const name1 = className.trim(); const name2 = funcName.trim(); assert(name1, 'className is empty'); assert(name2, 'funcName is empty'); const key = `${name1}:${name2}`; return key; } export function trxTrace(options) { const { type, appDir, traceSvc, span, trxPropagateOptions, attr, } = options; if (!span) { return; } let attrs = {}; if (trxPropagateOptions) { const path = 'path' in trxPropagateOptions && trxPropagateOptions.path ? relative(appDir, trxPropagateOptions.path).replaceAll('\\', '/') : ''; attrs = { [AttrNames.TrxPropagationType]: trxPropagateOptions.type, [AttrNames.TrxPropagationClass]: trxPropagateOptions.className, [AttrNames.TrxPropagationFunc]: trxPropagateOptions.funcName, [AttrNames.TrxPropagationPath]: path, // [AttrNames.TrxPropagationReadRowLockLevel]: trxPropagateOptions.readRowLockLevel, // [AttrNames.TrxPropagationWriteRowLockLevel]: trxPropagateOptions.writeRowLockLevel, ...attr, }; } else { attrs = { ...attr, }; } if (type === 'event') { traceSvc.addEvent(span, attrs); } else { traceSvc.otel.setAttributesLater(span, attrs); } } export function getSimpleCallers(limit = 64) { const ret = []; const sites = getStackCallerSites(limit); sites.forEach((site) => { const className = site.getTypeName() ?? ''; const fileName = site.getFileName() ?? ''; let funcName = ''; let methodName = ''; if (className) { funcName = site.getFunctionName() ?? ''; methodName = site.getMethodName() ?? ''; } const row = { path: fileName, className, funcName, methodName, line: -1, column: -1, }; ret.push(row); }); return ret; } const forShareMethods = [ 'first', 'select', ]; const skipMethods = ['truncate']; export function linkBuilderWithTrx(builder, trx) { assert(trx, 'trx is undefined'); void builder.transacting(trx); const trxPropagateOptions = builder[QueryBuilderExtKey.trxPropagateOptions]; if (trxPropagateOptions) { // @ts-expect-error const method = builder._method; if (forShareMethods.includes(method)) { // avoid error: "for share - FOR SHARE is not allowed with aggregate functions" if (!builderStatementsHasTypeAggregate(builder)) { builderRowLock(builder, trxPropagateOptions.readRowLockLevel); } } else if (!skipMethods.includes(method)) { builderRowLock(builder, trxPropagateOptions.writeRowLockLevel); } } builder.trxPropagated = true; } function builderRowLock(builder, rowLockLevel) { switch (rowLockLevel) { case RowLockLevel.ForShare: { void builder.forShare(); break; } case RowLockLevel.ForUpdate: { void builder.forUpdate(); break; } case RowLockLevel.ForShareSkipLocked: { void builder.forShare().skipLocked(); break; } case RowLockLevel.ForUpdateSkipLocked: { void builder.forUpdate().skipLocked(); break; } default: break; } void Object.defineProperty(builder, QueryBuilderExtKey.rowLockLevel, { value: rowLockLevel, }); } function builderStatementsHasTypeAggregate(builder) { // @ts-expect-error const statements = builder._statements; if (!statements?.length) { return false; } for (const row of statements) { if (row.type === 'aggregate') { return true; } } return false; } //# sourceMappingURL=trx-status.helper.js.map