Created
March 16, 2022 16:26
-
-
Save mattiamanzati/71700dcd2e17fe6ef7d0e523f87e74f8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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