1import { MysqlClient } from "@effect/sql-mysql2"
2import type { StartedMySqlContainer } from "@testcontainers/mysql"
3import { MySqlContainer } from "@testcontainers/mysql"
4import { Context, Data, Effect, Layer, Redacted, String } from "effect"
5
6export class ContainerError extends Data.TaggedError("ContainerError")<{
7 cause: unknown
8}> {}
9
10const makeMysqlContainer = () =>
11 new MySqlContainer("mysql:lts").withHealthCheck({
12 test: [
13 "CMD-SHELL",
14 "MYSQL_PWD=\"$MYSQL_ROOT_PASSWORD\" mysqladmin ping --protocol TCP --host 127.0.0.1 --user root --silent"
15 ],
16 interval: 250,
17 timeout: 1000,
18 retries: 1000
19 })
20
21export class MysqlContainer extends Context.Service<
22 MysqlContainer,
23 StartedMySqlContainer
24>()("test/MysqlContainer") {
25 static readonly layer = Layer.effect(this)(
26 Effect.acquireRelease(
27 Effect.tryPromise({
28 try: () => makeMysqlContainer().start(),
29 catch: (cause) => new ContainerError({ cause })
30 }),
31 (container) => Effect.promise(() => container.stop())
32 )
33 )
34
35 static client = Layer.unwrap(
36 Effect.gen(function*() {
37 const container = yield* MysqlContainer
38 return MysqlClient.layer({
39 url: Redacted.make(container.getConnectionUri())
40 })
41 })
42 )
43
44 static layerClient = this.client.pipe(Layer.provide(this.layer))
45
46 static clientWithTransforms = Layer.unwrap(
47 Effect.gen(function*() {
48 const container = yield* MysqlContainer
49 return MysqlClient.layer({
50 url: Redacted.make(container.getConnectionUri()),
51 transformQueryNames: String.camelToSnake,
52 transformResultNames: String.snakeToCamel
53 })
54 })
55 )
56
57 static layerVitest = Layer.effect(
58 this,
59 Effect.acquireRelease(
60 Effect.tryPromise({
61 try: () =>
62 new MySqlContainer("vitess/vttestserver:mysql80").withEnvironment({
63 KEYSPACES: "test,unsharded",
64 NUM_SHARDS: "1,1",
65 MYSQL_BIND_HOST: "0.0.0.0",
66 PORT: "3303"
67 }).start(),
68 catch: (cause) => new ContainerError({ cause })
69 }),
70 (container) => Effect.promise(() => container.stop())
71 )
72 )
73
74 static layerClientVitess = this.client.pipe(Layer.provide(this.layerVitest))
75}