import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' import type { ResourceProfile } from '@vpp/domain' import { RepositoryConcurrencyError, createResourceRegistry } from '../src/relational.js' const fixture: ResourceProfile = JSON.parse( readFileSync( fileURLToPath(new URL('../../../contracts/fixtures/resource_profile/storage.json', import.meta.url)), 'utf8', ), ) const clock = () => '2026-03-14T08:00:00Z' describe('relational store: resource registry (资源台账)', () => { it('puts and gets a schema-valid row with version 1', () => { const reg = createResourceRegistry(clock) const row = reg.put(fixture) expect(row.key).toBe('res-storage-01') expect(row.version).toBe(1) expect(reg.get('res-storage-01')?.value).toEqual(fixture) expect(reg.get('missing')).toBeUndefined() }) it('rejects rows that fail the domain schema (no unvalidated master data)', () => { const reg = createResourceRegistry(clock) expect(() => reg.put({ ...fixture, rated_power_mw: 10 as unknown as string })).toThrow() expect(() => reg.put({ ...fixture, type: 'WINDMILL' as never })).toThrow() expect(reg.list()).toHaveLength(0) }) it('enforces optimistic concurrency when expectedVersion is supplied', () => { const reg = createResourceRegistry(clock) reg.put(fixture, 0) expect(() => reg.put({ ...fixture, reliability_score: '0.90' }, 0)).toThrow( RepositoryConcurrencyError, ) const updated = reg.put({ ...fixture, reliability_score: '0.90' }, 1) expect(updated.version).toBe(2) expect(updated.value.reliability_score).toBe('0.90') }) it('allows unconditional replace for master-data loads', () => { const reg = createResourceRegistry(clock) reg.put(fixture) const row = reg.put({ ...fixture, name: 'renamed' }) expect(row.version).toBe(2) }) it('lists rows sorted by key and isolates stored values from mutation', () => { const reg = createResourceRegistry(clock) reg.put({ ...fixture, resource_id: 'res-b' }) reg.put({ ...fixture, resource_id: 'res-a' }) expect(reg.list().map((r) => r.key)).toEqual(['res-a', 'res-b']) const row = reg.get('res-a')! row.value.name = 'mutated' expect(reg.get('res-a')!.value.name).toBe(fixture.name) }) })