| 1 | /** |
| 2 | * @title Context.Service |
| 3 | * |
| 4 | * The default way to define a service is to extend `Context.Service`, |
| 5 | * passing in the service interface as a type parameter. |
| 6 | */ |
| 7 | |
| 8 | // file: src/db/Database.ts |
| 9 | import { Context, Effect, Layer, Schema } from "effect" |
| 10 | |
| 11 | // Pass in the service class name as the first type parameter, and the service |
| 12 | // interface as the second type parameter. |
| 13 | export class Database extends Context.Service<Database, { |
| 14 | query(sql: string): Effect.Effect<Array<unknown>, DatabaseError> |
| 15 | }>()( |
| 16 | // The string identifier for the service, which should include the package |
| 17 | // name and the subdirectory path to the service file. |
| 18 | "myapp/db/Database" |
| 19 | ) { |
| 20 | // Attach a static layer to the service, which will be used to provide an |
| 21 | // implementation of the service. |
| 22 | static readonly layer = Layer.effect( |
| 23 | Database, |
| 24 | Effect.gen(function*() { |
| 25 | // Define the service methods using Effect.fn |
| 26 | const query = Effect.fn("Database.query")(function*(sql: string) { |
| 27 | yield* Effect.log("Executing SQL query:", sql) |
| 28 | return [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }] |
| 29 | }) |
| 30 | |
| 31 | // Return an instance of the service using Database.of, passing in an |
| 32 | // object that implements the service interface. |
| 33 | return Database.of({ |
| 34 | query |
| 35 | }) |
| 36 | }) |
| 37 | ) |
| 38 | } |
| 39 | |
| 40 | export class DatabaseError extends Schema.TaggedError<DatabaseError>()("DatabaseError", { |
| 41 | cause: Schema.Defect() |
| 42 | }) {} |
| 43 | |
| 44 | // If you ever need to access the service type, use `Database["Service"]` |
| 45 | export type DatabaseService = Database["Service"] |