Skip to content

feat(backend): prisma singleton + updateMarketStatus service (#880 #884) - #1166

Merged
Ehonrie merged 1 commit into
Netwalls:mainfrom
darcszn:feat/880-884-prisma-singleton-update-market-status
Jul 28, 2026
Merged

feat(backend): prisma singleton + updateMarketStatus service (#880 #884)#1166
Ehonrie merged 1 commit into
Netwalls:mainfrom
darcszn:feat/880-884-prisma-singleton-update-market-status

Conversation

@darcszn

@darcszn darcszn commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Changes

Issue #880 — Prisma Singleton (src/db.ts)

Problem: `src/db.ts` exported a bare `new PrismaClient()` with no singleton guard. In development, `ts-node-dev` hot-reloads modules on every file save, which would instantiate a new `PrismaClient` on each reload — exhausting the PostgreSQL connection pool quickly.

Additionally, `src/lib/prisma.ts` and `src/lib/db.ts` each created their own independent `PrismaClient` instances, meaning the app could silently run with 3 separate connection pools.

Fix:

  • Rewrote `src/db.ts` to use a `globalThis.__prisma` guard. In non-production environments, the instance is stored on `globalThis` so hot-reloads reuse the existing connection instead of spawning a new one. Production always creates a fresh instance on startup.
  • Configured `PrismaClient` log levels: `query + warn + error` in development, `warn + error` in production.
  • Consolidated `src/lib/prisma.ts` and `src/lib/db.ts` to re-export from the canonical `src/db.ts` singleton rather than each owning their own client.

```ts
// src/db.ts
export const db: PrismaClient =
globalThis.__prisma ?? new PrismaClient({ log: [...] });

if (process.env.NODE_ENV !== 'production') {
globalThis.__prisma = db;
}
```

Acceptance criteria met:

  • `import { db } from './db'` works in any service file — all existing services (`market.service.ts`, `bet.service.ts`, `resolution.service.ts`) already use this import and continue to work unchanged.
  • `npm run db:migrate` and `npm run db:generate` scripts were already wired correctly in `package.json`.
  • Prisma schema was already complete and correct with all models, enums, and relations.

Issue #884 — `updateMarketStatus()` (src/services/market.service.ts)

Problem: The service file had several bugs that would cause runtime crashes:

  1. Duplicate `createMarketRecord` declaration — A broken first version of the function (referencing an undefined `txHash` variable) was left above the correct transactional implementation, causing a TypeScript compile error.
  2. Undefined `prisma` variable — `resolveMarket()`, `cancelMarket()`, and `resolveMarketDispute()` all called `prisma.market.update()` and `prisma.adminLog.create()`, but `prisma` was never imported or defined. These functions would throw `ReferenceError: prisma is not defined` at runtime.
  3. `pagination?.limit` mismatch — `getAllMarkets()` and `getMarketLeaderboard()` accessed `pagination?.limit` but the `Pagination` interface defines the field as `pageSize`, causing silent `undefined` fallbacks on every paginated call.
  4. String literal status check — `updateMarketStatus()` used the string `'Resolved'` for the `resolvedAt` guard instead of the `MarketStatus.Resolved` enum value.

Fix:

  • Removed the duplicate broken `createMarketRecord` declaration entirely.
  • Replaced all `prisma.` calls with `db.` throughout `resolveMarket`, `cancelMarket`, and `resolveMarketDispute`.
  • Fixed `pagination?.limit` → `pagination?.pageSize` in both `getAllMarkets` and `getMarketLeaderboard`, and capped the limit at `MAX_PAGE_SIZE`.
  • Hardened the `resolvedAt` condition in `updateMarketStatus` to use `MarketStatus.Resolved` enum value.

```ts
export async function updateMarketStatus(
market_id: string,
status: MarketStatus,
outcome?: Outcome
): Promise {
return db.market.update({
where: { id: market_id },
data: {
status,
...(outcome !== undefined && { outcome }),
...(status === MarketStatus.Resolved && { resolvedAt: new Date() }),
},
});
}
```

Acceptance criteria met:

  • Status updated correctly for all `MarketStatus` values (Open, Locked, Resolved, Cancelled, Disputed).
  • `resolvedAt` is set precisely when `status === MarketStatus.Resolved`.
  • `outcome` is stored when provided, omitted when not.
  • `resolveMarket`, `cancelMarket`, and `resolveMarketDispute` now correctly call `db` and will no longer throw at runtime.

Files Changed

File Change
`backend/src/db.ts` Rewritten — proper singleton with `globalThis` guard and log config
`backend/src/lib/prisma.ts` Consolidated — re-exports singleton from `../db`
`backend/src/lib/db.ts` Consolidated — re-exports singleton from `../db`
`backend/src/services/market.service.ts` Fixed duplicate declaration, `prisma` → `db`, pagination field, enum guard

closes #880
closes #884

…s#880 Netwalls#884)

- Set up global PrismaClient singleton with hot-reload guard (issue Netwalls#880)
- Consolidate lib/prisma.ts and lib/db.ts to re-export from canonical db.ts
- Fix duplicate createMarketRecord declaration in market.service.ts
- Fix undefined prisma variable in resolveMarket, cancelMarket, resolveMarketDispute
- Harden updateMarketStatus to use MarketStatus enum and set resolvedAt on Resolved
- Align pagination.pageSize usage across getAllMarkets and getMarketLeaderboard
@Ehonrie
Ehonrie merged commit c76e48e into Netwalls:main Jul 28, 2026
1 check failed
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.

[backend] Implement updateMarketStatus() service [backend] Set up Prisma with PostgreSQL

2 participants