Swap the storage, keep the logic
Services shouldn't care whether data lives in PostgreSQL, MongoDB or memory. The repository pattern puts data access behind a small set of methods (findAll, findById, save). Nest projects do this with TypeORM, Prisma or Mongoose — and you can swap an in-memory version in for tests.
An abstract repository token
export abstract class DishesRepository {
abstract findAll(): Promise<Dish[]>;
abstract findById(id: number): Promise<Dish | null>;
abstract save(dish: Omit<Dish, "id">): Promise<Dish>;
}
@Injectable()
export class InMemoryDishesRepository extends DishesRepository {
private rows: Dish[] = [];
async findAll() { return this.rows; }
async findById(id: number) { return this.rows.find((d) => d.id === id) ?? null; }
async save(dish: Omit<Dish, "id">) {
const row = { id: this.rows.length + 1, ...dish };
this.rows.push(row);
return row;
}
}
// app.module.ts
providers: [DishesService, { provide: DishesRepository, useClass: InMemoryDishesRepository }]
// production: { provide: DishesRepository, useClass: PrismaDishesRepository }- Prisma (Prisma course): a PrismaService extends PrismaClient; repositories call this.prisma.dish.findMany().
- TypeORM: @Entity classes and @InjectRepository(Dish).
- Keep database types out of controllers; return plain objects or DTOs.