import { ConflictException } from '@nestjs/common'; import { Kysely, PostgresDialect } from 'kysely'; import { Pool } from 'pg'; import type { Database } from '../../database/src'; import { TripsRepository } from '../src/trips.repository'; import { TripsService } from '../src/trips.service'; import { UsersRepository } from '../../users/src/users.repository'; describe('Trip optimistic locking (integration)', () => { let db: Kysely; let tripsService: TripsService; let ownerId: string; beforeAll(async () => { db = new Kysely({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: process.env.DATABASE_URL }), }), }); const usersRepository = new UsersRepository(db); const owner = await usersRepository.upsertByExternalSubjectId( 'optimistic-locking-test-sub', { email: 'owner@example.test', displayName: 'Owner', }, ); ownerId = owner.id; tripsService = new TripsService(new TripsRepository(db)); }); afterAll(async () => { await db.destroy(); }); it('rejects a second update that used a stale version', async () => { const trip = await tripsService.createTrip(ownerId, { name: 'Slovenia 2027', }); expect(trip.version).toBe(1); const firstUpdate = await tripsService.updateTrip(trip.id, { name: 'Slovenia 2027 (v2)', version: 1, }); expect(firstUpdate.version).toBe(2); await expect( tripsService.updateTrip(trip.id, { name: 'Conflicting concurrent edit', version: 1, }), ).rejects.toThrow(ConflictException); }); });