Effect CommunityEC
Effect Community3y ago
13 replies
johannes

Lifting Dependencies from functions into wrapper object

When using services with effect I like to define an interface to group related functions. For example:

interface UserRepository {
  save: (user: User) => Effect.Effect<never, UserExistsError, void>
  getById: (id: ID) => Effect.Effect<never, never, Option.Option<User>>
}

const UserRepository = Context.Tag<UserRepository>()


When implementing this repository I create each function separately. Each function consists of smaller functions, all of which might have dependencies on other services. For example:

const save = (user: User) => pipe(
  DatabaseConnection,
  Effect.flatMap((sql) => sql`INSERT INTO users ${user}`
)


Now when I want to create a live version of this repository that implements my defined interface I naturally get an error as the dependency definitions don't match:

const UserRepositoryImpl = {
  save,
  getById
}

const UserRepositoryLive = Effect.provideService(UserRepository, UserRepositoryImpl); // <-- Here types don't match for each functions


However, as the interface definition is abstract I don't want to define all dependencies in it as they might differ for each implementation. In essence, I want to lift the dependencies out of the functions into the object creation so that I can provide the dependencies for each live implementation instead of defining them on the function level.

One obvious way of achieving this would be to pass the dependencies inside the repository as regular function arguments, but that gets tedious quickly with nested functions. Has anyone found a way to use objects as dependencies that consist of functions with dependencies, but not having to provide those dependencies on the interface level? Thanks for you help!
Was this page helpful?