02b51d7814
- Repository interfaces defined by domain (@landvex/domain) - 6 in-memory adapters: Session, Mission, DecisionCase, Artifact, EventStore, UnitOfWork - 9 tests verifying adapter contracts - Domain unchanged — infrastructure depends on domain, never reverse - ADR-006: In-Memory Adapters for Testing Definition of Done met: - All adapters compile against domain interfaces - Unit tests pass (9/9) - No PostgreSQL, S3, Express, AI in this PR - Ready for PR-003: PostgreSQL adapters
99 lines
3.4 KiB
TypeScript
99 lines
3.4 KiB
TypeScript
/**
|
|
* In-Memory Unit of Work
|
|
*
|
|
* Coordinates multiple in-memory repositories.
|
|
* Simulates transaction boundaries for testing.
|
|
*
|
|
* ADR-006: In-memory adapters for testing
|
|
* - commit() persists all changes
|
|
* - rollback() discards all changes
|
|
* - NOT atomic in production sense, but sufficient for tests
|
|
*/
|
|
|
|
import {
|
|
UnitOfWork,
|
|
FieldSessionRepository,
|
|
MissionRepository,
|
|
DecisionCaseRepository,
|
|
ArtifactRegistry,
|
|
EventStore,
|
|
} from '../repositories/repository-interfaces';
|
|
import { InMemoryFieldSessionRepository } from './in-memory-session-repository';
|
|
import { InMemoryMissionRepository } from './in-memory-mission-repository';
|
|
import { InMemoryDecisionCaseRepository } from './in-memory-decision-case-repository';
|
|
import { InMemoryArtifactRegistry } from './in-memory-artifact-registry';
|
|
import { InMemoryEventStore } from './in-memory-event-store';
|
|
|
|
export class InMemoryUnitOfWork implements UnitOfWork {
|
|
sessions: FieldSessionRepository;
|
|
missions: MissionRepository;
|
|
decisionCases: DecisionCaseRepository;
|
|
artifacts: ArtifactRegistry;
|
|
events: EventStore;
|
|
|
|
private snapshots: {
|
|
sessions: Map<string, unknown>;
|
|
missions: Map<string, unknown>;
|
|
cases: Map<string, unknown>;
|
|
artifacts: Map<string, unknown>;
|
|
events: unknown[];
|
|
} | null = null;
|
|
|
|
constructor() {
|
|
this.sessions = new InMemoryFieldSessionRepository();
|
|
this.missions = new InMemoryMissionRepository();
|
|
this.decisionCases = new InMemoryDecisionCaseRepository();
|
|
this.artifacts = new InMemoryArtifactRegistry();
|
|
this.events = new InMemoryEventStore();
|
|
}
|
|
|
|
async commit(): Promise<void> {
|
|
// In-memory: changes are already applied
|
|
// Real implementation would flush to database
|
|
this.snapshots = null;
|
|
}
|
|
|
|
async rollback(): Promise<void> {
|
|
if (!this.snapshots) {
|
|
throw new Error('No transaction in progress');
|
|
}
|
|
|
|
// Restore from snapshots
|
|
(this.sessions as InMemoryFieldSessionRepository).clear();
|
|
(this.missions as InMemoryMissionRepository).clear();
|
|
(this.decisionCases as InMemoryDecisionCaseRepository).clear();
|
|
(this.artifacts as InMemoryArtifactRegistry).clear();
|
|
(this.events as InMemoryEventStore).clear();
|
|
|
|
// Re-populate from snapshots
|
|
for (const [id, session] of this.snapshots.sessions) {
|
|
(this.sessions as InMemoryFieldSessionRepository).save(session as any);
|
|
}
|
|
for (const [id, mission] of this.snapshots.missions) {
|
|
(this.missions as InMemoryMissionRepository).save(mission as any);
|
|
}
|
|
for (const [id, c] of this.snapshots.cases) {
|
|
(this.decisionCases as InMemoryDecisionCaseRepository).save(c as any);
|
|
}
|
|
for (const [id, artifact] of this.snapshots.artifacts) {
|
|
(this.artifacts as InMemoryArtifactRegistry).register(artifact as any);
|
|
}
|
|
for (const event of this.snapshots.events) {
|
|
(this.events as InMemoryEventStore).append(event as any);
|
|
}
|
|
|
|
this.snapshots = null;
|
|
}
|
|
|
|
/** Begin transaction: capture snapshot */
|
|
begin(): void {
|
|
this.snapshots = {
|
|
sessions: new Map((this.sessions as InMemoryFieldSessionRepository as any).sessions),
|
|
missions: new Map((this.missions as InMemoryMissionRepository as any).missions),
|
|
cases: new Map((this.decisionCases as InMemoryDecisionCaseRepository as any).cases),
|
|
artifacts: new Map((this.artifacts as InMemoryArtifactRegistry as any).artifacts),
|
|
events: [...(this.events as InMemoryEventStore as any).events],
|
|
};
|
|
}
|
|
}
|