Skip to content

Instantly share code, notes, and snippets.

@cowboyd
Last active March 6, 2025 15:06
Show Gist options
  • Save cowboyd/6c0ba30949dbae454673c549406ae800 to your computer and use it in GitHub Desktop.
Save cowboyd/6c0ba30949dbae454673c549406ae800 to your computer and use it in GitHub Desktop.
An implementation of a finalizable transaction
import { finalizable, finalize } from "./finalizable.ts"
export function transaction(): Operation<string> {
return finalizable(function*() {
// on success
yield* finalize(function* (result) {
if (result.ok) {
console.log("everything is fine", result.value);
}
});
// on failure
yield* finalize(function* (result) {
if (!result.ok) {
console.log("everything is BAD!", result.error);
}
});
let coinToss = Math.random();
if (coinToss >= .5) {
return "You win!";
} else {
throw new Error("You lose!");
}
});
}
import type { Operation, Result } from "effection";
import { createContext, Err, Ok } from "effection";
interface Finalizer {
(result: Result<unknown>): Operation<void>;
}
const Finalizers = createContext<Finalizer[]>("finalizers");
export function* finalize(finalizer: Finalizer) {
let finalizers = yield* Finalizers.expect();
finalizers.push(finalizer);
}
export function finalizable<T>(body: () => Operation<T>): Operation<T> {
return Finalizers.with([], function* (finalizers) {
let result = yield* box(body);
for (let finalizer of finalizers) {
yield* finalizer(result);
}
return unbox(result);
});
}
function* box<T>(op: () => Operation<T>): Operation<Result<T>> {
try {
return Ok(yield* op());
} catch (error) {
return Err(error as Error);
}
}
function unbox<T>(result: Result<T>): T {
if (result.ok) {
return result.value;
} else {
throw result.error;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment