| 1 | import { MysqlClient } from "@effect/sql-mysql2" |
| 2 | import type { StartedMySqlContainer } from "@testcontainers/mysql" |
| 3 | import { MySqlContainer } from "@testcontainers/mysql" |
| 4 | import { Context, Data, Effect, Layer, Redacted, String } from "effect" |
| 5 | |
| 6 | export class ContainerError extends Data.TaggedError("ContainerError")<{ |
| 7 | cause: unknown |
| 8 | }> {} |
| 9 | |
| 10 | const 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 | |
| 21 | export 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 | } |