Effect CommunityEC
Effect Community2y ago
10 replies
Stephen Bluck

Layer Implementation for UsersRepository and Alerts

Working on my layer game. Am I doing things correctly?

import { Context, Effect, Layer } from "effect";

export class UsersRepository extends Context.Tag("UsersRepository")<
  UsersRepository,
  { create: (name: string) => Effect.Effect<{ name: string }> }
>() {
  // In memory implementation
  static Test = Layer.effect(UsersRepository, Effect.succeed({ create: (name) => Effect.succeed({ name }) }));
  // Real DB implementation
  static Live = Layer.effect(UsersRepository, Effect.succeed({ create: (name) => Effect.succeed({ name }) }));
}

export class Alerts extends Context.Tag("Alerts")<Alerts, { notify: Effect.Effect<void> }>() {
  // Console.log implementation
  static Test = Layer.effect(Alerts, Effect.succeed({ notify: Effect.unit }));
  // Email implementation
  static Live = Layer.effect(Alerts, Effect.succeed({ notify: Effect.unit }));
}

// This guy does not care about what implementation is used
// Does all the business logic like sending alerts and saving to the DB
export class Users extends Context.Tag("Users")<
  Users,
  { register: (name: string) => Effect.Effect<{ name: string }> }
>() {
  static Live = Layer.effect(
    Users,
    Effect.gen(function* (_) {
      const repo = yield* _(UsersRepository);
      const alerts = yield* _(Alerts);

      return Users.of({
        register: (name) => repo.create(name).pipe(Effect.tap(() => alerts.notify)),
      });
    }),
  );
}

// Test version 
export const MainTest = Users.Live.pipe(Layer.provide(Alerts.Test), Layer.provide(UsersRepository.Test));

// Live version 
export const MainLive = Users.Live.pipe(Layer.provide(Alerts.Live), Layer.provide(UsersRepository.Live));
Was this page helpful?