Skip to content

Feature/persistent solvers store - #154

Open
Keengfk wants to merge 4 commits into
stellar-vortex-protocol:mainfrom
Keengfk:feature/persistent-solvers-store
Open

Feature/persistent solvers store#154
Keengfk wants to merge 4 commits into
stellar-vortex-protocol:mainfrom
Keengfk:feature/persistent-solvers-store

Conversation

@Keengfk

@Keengfk Keengfk commented Jul 27, 2026

Copy link
Copy Markdown

Summary

Solver registrations, fill counts, and bond amounts currently live in a plain
Map inside SolversService and vanish on every restart. This PR extracts the
storage behind an ISolversRepository interface with an
InMemorySolversRepository as the first adapter, following the exact same
pattern established for intents in refactor/intents-repository-interface. The
in-memory behaviour is unchanged — this is purely a structural refactor that
makes the storage backend swappable so the Prisma adapter (issue #36) can be
plugged in without touching SolversService.

───────────────────────────────────────────────────────────────────────────────

Changes

src/solvers/solvers.repository.ts (new)
Defines the ISolversRepository interface (3 methods: save, findByAddress,
findAll) and the SOLVERS_REPOSITORY Symbol injection token.

src/solvers/in-memory-solvers.repository.ts (new)
The existing Map-based storage and seed logic lifted directly from
SolversService into an @Injectable() class that implements ISolversRepository.
Behaviour is identical — pure structural move.

src/solvers/solvers.service.ts (modified)
Stripped to pure orchestration: zeroed counters (fillsCompleted, fillsFailed,
totalVolume) and registeredAt timestamp are set here. All this.solvers.* calls
replaced with this.repo.* via the injected ISolversRepository. No logic added
or removed.

src/solvers/solvers.module.ts (modified)
Registers { provide: SOLVERS_REPOSITORY, useClass: InMemorySolversRepository }.
To swap to a Prisma-backed adapter, only this one binding changes.

───────────────────────────────────────────────────────────────────────────────

How to add a new storage adapter

// e.g. prisma-solvers.repository.ts
@Injectable()
export class PrismaSolversRepository implements ISolversRepository {
constructor(private readonly prisma: PrismaService) {}
// ... implement save, findByAddress, findAll
}

// solvers.module.ts — one line change:
{ provide: SOLVERS_REPOSITORY, useClass: PrismaSolversRepository }

───────────────────────────────────────────────────────────────────────────────

Testing

  • src/solvers/in-memory-solvers.repository.spec.ts (new) — 10 unit tests: seed
    count and addresses, save persists and returns, overwrite keeps count stable,
    count increments for new address, findByAddress miss/hit, findAll count,
    snapshot immutability (mutating the returned array does not affect the store)
  • src/solvers/solvers.service.spec.ts (updated) — wires SolversService via
    Test.createTestingModule with InMemorySolversRepository injected under the
    token, matching production DI exactly; added registeredAt timestamp assertion

npm run lint ✓ 0 errors
npm run typecheck ✓ 0 errors
npm run build ✓ clean
npm test ✓ 49 tests, 7 suites (+10 new)
npm run test:e2e ✓ 23 tests, 5 suites

closes #55

Keengfk added 4 commits July 27, 2026 20:12
- Add Prisma 5.22.0 (prisma + @prisma/client) as dependencies
- Add prisma/schema.prisma with Intent, Solver, Token models and
  IntentState / SupportedChain enums; all fields indexed appropriately
- Add initial migration SQL (prisma/migrations/20240101000000_init/)
- Add PrismaService (extends PrismaClient, NestJS lifecycle hooks) and
  global PrismaModule; wire into AppModule
- Add DATABASE_URL to Joi validation schema, AppConfig, and .env.example
- Add npm scripts: db:generate, db:migrate, db:migrate:prod, db:studio,
  db:validate
- Update Dockerfile: build stage runs prisma generate; runtime CMD runs
  prisma migrate deploy before starting the server
- Update CI: add postgres:16-alpine service container and migration steps
  (db:validate, db:generate, db:migrate:prod) before build/test
- Add PrismaService unit test (src/prisma/prisma.service.spec.ts)
- Mock PrismaService in e2e test helper so suites stay DB-free

Closes stellar-vortex-protocol#37
- Add IIntentsRepository interface (save, findById, findAll,
  findByState, findByUser, update) and INTENTS_REPOSITORY Symbol token
  in src/intents/intents.repository.ts
- Add InMemoryIntentsRepository in src/intents/in-memory-intents.repository.ts
  — lifts all Map logic and seed data out of IntentsService
- Refactor IntentsService to pure orchestration: UUID generation,
  default state/deadline live here; all persistence delegated to the
  injected IIntentsRepository
- Update IntentsModule to bind InMemoryIntentsRepository under the
  INTENTS_REPOSITORY token — swap the binding to change storage backend
- Update intents.service.spec.ts to wire service via TestingModule with
  real InMemoryIntentsRepository under the DI token
- Add in-memory-intents.repository.spec.ts — 14 tests covering every
  method including seed, overwrite, case-insensitive user lookup, and
  partial-patch behaviour

All tests pass: 35 unit (5 suites), 23 e2e (5 suites), lint clean,
typecheck clean.

Closes stellar-vortex-protocol#38
- Add DatabaseHealthService: probes via PrismaService.$queryRaw`SELECT 1`,
  races against a 3s timeout, never throws, returns
  { status, latencyMs?, error? }
- Update HealthController: async check(), injects DatabaseHealthService,
  response includes a top-level `db` field
- Update HealthModule: provide DatabaseHealthService (PrismaModule is
  already global so no import needed)
- Update health.e2e-spec.ts: assert db field shape for both the ok and
  unreachable branches — suite passes with the mock PrismaService that
  has no real connection, exercising the graceful-degradation path
- Add database-health.service.spec.ts: 4 unit tests covering the success
  path, query rejection, timeout (fake timers), and missing $queryRaw

Closes stellar-vortex-protocol#39
Extract ISolversRepository interface and InMemorySolversRepository
adapter from SolversService, following the same pattern established
for intents (refactor/intents-repository-interface).

- Add ISolversRepository interface (save, findByAddress, findAll) and
  SOLVERS_REPOSITORY Symbol token in src/solvers/solvers.repository.ts
- Add InMemorySolversRepository in src/solvers/in-memory-solvers.repository.ts
  — lifts all Map logic and seed data out of SolversService
- Refactor SolversService to pure orchestration: counter initialisation
  and timestamp generation live here; all persistence delegated to the
  injected ISolversRepository
- Update SolversModule to bind InMemorySolversRepository under the
  SOLVERS_REPOSITORY token — swap the binding to change storage backend
- Update solvers.service.spec.ts to wire service via TestingModule with
  InMemorySolversRepository injected under the DI token; add
  registeredAt timestamp test
- Add in-memory-solvers.repository.spec.ts — 10 tests covering seed,
  save/overwrite, findByAddress miss, findAll snapshot immutability

All tests pass: 49 unit (7 suites), 23 e2e (5 suites), lint clean,
typecheck clean.

Closes stellar-vortex-protocol#40
@drips-wave

drips-wave Bot commented Jul 27, 2026

Copy link
Copy Markdown

@Keengfk Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace SolversService's in-memory Map with persistent storage

1 participant