import { Effect, Exit, Layer, Request, RequestResolver, Schema, ServiceMap } from "effect"
export class User extends Schema.Class<User>("User")({
id: Schema.Number,
name: Schema.String,
email: Schema.String
}) {}
export class UserNotFound extends Schema.TaggedErrorClass<UserNotFound>()("UserNotFound", {
id: Schema.Number
}) {}
export class Users extends ServiceMap.Service<Users, {
getUserById(id: number): Effect.Effect<User, UserNotFound>
}>()("app/Users") {
static readonly layer = Layer.effect(
Users,
Effect.gen(function*() {
class GetUserById extends Request.Class<
{ readonly id: number },
User,
UserNotFound,
never
> {}
const usersTable = new Map<number, User>([
[1, new User({ id: 1, name: "Ada Lovelace", email: "[email protected]" })],
[2, new User({ id: 2, name: "Alan Turing", email: "[email protected]" })],
[3, new User({ id: 3, name: "Grace Hopper", email: "[email protected]" })]
])
const resolver = yield* RequestResolver.make<GetUserById>(
Effect.fnUntraced(function*(entries) {
for (const entry of entries) {
const user = usersTable.get(entry.request.id)
if (user) {
entry.completeUnsafe(Exit.succeed(user))
} else {
entry.completeUnsafe(Exit.fail(new UserNotFound({ id: entry.request.id })))
}
}
})
).pipe(
RequestResolver.setDelay("10 millis"),
RequestResolver.withSpan("Users.getUserById.resolver"),
RequestResolver.withCache({ capacity: 1024 })
)
const getUserById = (id: number) =>
Effect.request(new GetUserById({ id }), resolver).pipe(
Effect.withSpan("Users.getUserById", { attributes: { userId: id } })
)
return { getUserById } as const
})
)
}