(effect: Effect.Effect<A, E>)
| 361 | ).pipe(Effect.withSpan(`fumadb.${label}`)); |
| 362 | |
| 363 | const transaction = <A, E>(effect: Effect.Effect<A, E>): Effect.Effect<A, E | StorageFailure> => |
| 364 | Effect.flatMap(Effect.service(activeFumaDbRef), (active) => { |
| 365 | if (active) return effect as Effect.Effect<unknown, unknown>; |
| 366 | |
| 367 | // The outermost transaction owns the post-commit hook queue; hooks |
| 368 | // queued anywhere inside (including nested pass-through transactions) |
| 369 | // run only after THIS commit, and are discarded on rollback. |
| 370 | const commitHooks: PendingCommitHook[] = []; |
| 371 | return Effect.contextWith((context) => |
| 372 | Effect.tryPromise({ |
| 373 | try: () => |
| 374 | db.transaction(async (transactionDb) => { |
| 375 | const exit = await Effect.runPromiseExitWith(context)( |
| 376 | effect.pipe( |
| 377 | Effect.provideService(activeFumaDbRef, transactionDb), |
| 378 | Effect.provideService(pendingCommitHooksRef, commitHooks), |
| 379 | ), |
| 380 | ); |
| 381 | if (Exit.isSuccess(exit)) return exit.value; |
| 382 | |
| 383 | const failure = exit.cause.reasons.find(Cause.isFailReason); |
| 384 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: FumaDB transactions roll back when the callback rejects |
| 385 | if (failure) throw new TransactionEffectFailure(failure.error); |
| 386 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: FumaDB transactions roll back when the callback rejects |
| 387 | throw new TransactionEffectDefect(exit.cause); |
| 388 | }), |
| 389 | catch: (cause): E | StorageFailure => { |
| 390 | if (cause instanceof TransactionEffectFailure) return cause.error as E; |
| 391 | if (cause instanceof TransactionEffectDefect) { |
| 392 | return fumaFailureFromCause("transaction", cause.cause); |
| 393 | } |
| 394 | return fumaFailureFromCause("transaction", cause); |
| 395 | }, |
| 396 | }).pipe(Effect.tap(() => runCommitHooks(commitHooks))), |
| 397 | ); |
| 398 | }).pipe(Effect.withSpan("fumadb.transaction")) as Effect.Effect<A, E | StorageFailure>; |
| 399 | |
| 400 | return { use, transaction }; |
| 401 | }; |
nothing calls this directly
no test coverage detected