[SOLVED] Defining inMemoryRepository via Context.Tag

Hi all,
I'm trying to create a testable repository pattern via effect.
Here's the pseudo code:

interface ProductsRepositoryImpl {
  readonly count: () => Effect.Effect<number, DatabaseError>;
  readonly getAll: () => Effect.Effect<Array<Product>, DatabaseError>;
}

export class ProductsRepository extends Context.Tag("ProductsRepository")<
  ProductsRepository,
  ProductsRepositoryImpl
>() {}

export class ProductsRepositoryLive extends ProductsRepository {
  constructor() {
    super(undefined as never); // Hackery for TS to pass
  }

  getAll() {
    return Effect.tryPromise({
      try: () => db.products.toArray(),
      catch: (error) =>
        new DatabaseError({ message: `Failed to get all products: ${error}` }),
    });
  }

  count() {
    return Effect.tryPromise({
      try: () => db.products.count(),
      catch: (error) =>
        new DatabaseError({
          message: `Failed to get products count, ${error}`,
        }),
    });
  }
}


And I use it like so:
const runnable = ProductsRepository.pipe(
  Effect.flatMap((repo) => repo.count()),
  Effect.provideService(ProductsRepository, new ProductsRepositoryLive()),
);


It works, but if you paid attention I had to do a hackery in the constructor of my class ProductsRepositoryLive

  constructor() {
    super(undefined as never);
  }


It just doesn't feel right.
Am I doing something wrong?

I want to be able to define class so I can create a InMemoryProductsRepository and keep the state within the class, something like so:

export class ProductsRepositoryInMemory extends ProductsRepository {
  private products = [product1, product2];

  constructor() {
    super(undefined as never);
  }

  getAll() {
    return Effect.try({
      try: () => this.products,
      catch: (error) =>
        new DatabaseError({ message: `Failed to get all products: ${error}` }),
    });
  }
  //  etc....
}


Thank you 🙂
Was this page helpful?