Skip to content

Instantly share code, notes, and snippets.

@mattiamanzati
Created March 16, 2022 16:26
Show Gist options
  • Save mattiamanzati/71700dcd2e17fe6ef7d0e523f87e74f8 to your computer and use it in GitHub Desktop.
Save mattiamanzati/71700dcd2e17fe6ef7d0e523f87e74f8 to your computer and use it in GitHub Desktop.
/* Just a fake NodeJS db api exposed by mysql, mssql, etc...*/
interface FakeTrans {}
interface FakeConnection {
query(sql: string, trans?: FakeTrans): Promise<ResultSet>;
beginTransaction(): Promise<FakeTrans>;
commitTransaction(trans: FakeTrans): Promise<void>;
rollbackTransaction(trans: FakeTrans): Promise<void>;
}
declare function fakeConnect(): Promise<FakeConnection>;
/* The domain of errors and result of the DB service */
type QueryError = unknown;
type ConnectionError = unknown;
type ResultSet = any[][];
interface Connection {
query(query: string): T.Effect<unknown, QueryError, ResultSet>;
transaction<R, E, A>(
eff: T.Effect<Has<Connection> & R, E, A>
): T.Effect<R, E | QueryError, A>;
}
const Connection = tag<Connection>();
function makeConnection(): T.Effect<unknown, ConnectionError, Connection> {
return pipe(
T.promise(fakeConnect), // <== here we create the root connection,
T.map((connectionHandle) => ({
query: (sql: string) => // implementation of regular query without trans
T.promise(() => connectionHandle.query(sql, undefined)),
transaction: <R, E, A>(
eff: T.Effect<Has<Connection> & R, E, A>
): T.Effect<R, E | QueryError, A> =>
T.bracketExit_(
T.promise(connectionHandle.beginTransaction), // acquire trans
(trans) => {
const connectionInTrans: Connection = {
query: (sql: string) =>
T.promise(() => connectionHandle.query(sql, trans)),
transaction: <R, E, A>(
eff: T.Effect<Has<Connection> & R, E, A>
): T.Effect<R, E | QueryError, A> =>
T.provideService(Connection)(connectionInTrans)(eff), // if already in trans, just use current trans
};
return T.provideService(Connection)(connectionInTrans)(eff);
},
(trans, exit) => // release trans by rollback if failed or interrupt or commit if done
T.promise(() =>
exit._tag === "Failure"
? connectionHandle.rollbackTransaction(trans)
: connectionHandle.commitTransaction(trans)
)
),
}))
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment