1import { assert, describe, it } from "@effect/vitest"
2import { Effect, Layer, Logger } from "effect"
3import { SqlClient, Statement } from "effect/sql"
4import { MysqlContainer } from "./utils.ts"
5
6const SqlLogger = Layer.succeed(Statement.CurrentTransformer)((statement) => {
7 const [query, params] = statement.compile()
8 return Effect.log("executing sql").pipe(
9 Effect.annotateLogs({ query, params }),
10 Effect.as(statement)
11 )
12})
13
14describe("sql", () => {
15 it.effect("releases completed nested savepoints", () =>
16 Effect.gen(function*() {
17 const sql = yield* SqlClient.SqlClient
18 yield* sql`CREATE TABLE savepoint_release (value INTEGER)`
19 yield* sql.withTransaction(Effect.gen(function*() {
20 for (const rollback of [false, true]) {
21 yield* sql.withTransaction(
22 sql`INSERT INTO savepoint_release VALUES (1)`.pipe(
23 Effect.andThen(rollback ? Effect.fail("rollback") : Effect.void)
24 )
25 ).pipe(Effect.ignore)
26 const error = yield* sql`RELEASE SAVEPOINT effect_sql_1`.unprepared.pipe(Effect.flip)
27 assert.strictEqual(error._tag, "SqlError")
28 }
29 }))
30 assert.deepStrictEqual(yield* sql`SELECT value FROM savepoint_release`, [{ value: 1 }])
31 }).pipe(Effect.provide(MysqlContainer.layerClient)), { timeout: 60_000 })
32
33 it.effect("tranformers", () =>
34 Effect.gen(function*() {
35 const logs: Array<unknown> = []
36 const sql = yield* SqlClient.SqlClient
37 const result = yield* sql<{ result: number }>`SELECT 1 + 1 AS result`.pipe(
38 Effect.provide(Logger.layer([
39 Logger.make((log) => {
40 logs.push(log.message)
41 })
42 ]))
43 )
44 assert.deepStrictEqual(result, [{ result: 2 }])
45 assert.deepStrictEqual(logs, [["executing sql"]])
46 }).pipe(
47 Effect.provide(MysqlContainer.layerClient.pipe(
48 Layer.provideMerge(SqlLogger)
49 )),
50 Effect.catchTag("ContainerError", () => Effect.void)
51 ), { timeout: 60_000 })
52})