fix: skip deleted reserved turn queues during flush
This commit is contained in:
@@ -26,7 +26,7 @@ import { asRecord } from '@sammo-ts/common';
|
|||||||
|
|
||||||
import type { TurnDaemonCommandResult, TurnDaemonHooks } from '../lifecycle/types.js';
|
import type { TurnDaemonCommandResult, TurnDaemonHooks } from '../lifecycle/types.js';
|
||||||
import type { InMemoryTurnWorld } from './inMemoryWorld.js';
|
import type { InMemoryTurnWorld } from './inMemoryWorld.js';
|
||||||
import type { InMemoryReservedTurnStore } from './reservedTurnStore.js';
|
import type { InMemoryReservedTurnStore, ReservedTurnChanges } from './reservedTurnStore.js';
|
||||||
import { buildDiplomacyMeta } from '@sammo-ts/logic';
|
import { buildDiplomacyMeta } from '@sammo-ts/logic';
|
||||||
import { ensureItemInventory, withSerializedItemInventory } from '@sammo-ts/logic/items/index.js';
|
import { ensureItemInventory, withSerializedItemInventory } from '@sammo-ts/logic/items/index.js';
|
||||||
import { persistGeneralLifecycleEvents } from './generalTurnLifecyclePersistence.js';
|
import { persistGeneralLifecycleEvents } from './generalTurnLifecyclePersistence.js';
|
||||||
@@ -43,6 +43,26 @@ export interface DatabaseTurnHooks {
|
|||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const excludeDeletedReservedTurnQueues = (
|
||||||
|
changes: ReservedTurnChanges,
|
||||||
|
deletedGeneralIds: readonly number[],
|
||||||
|
deletedNationIds: readonly number[]
|
||||||
|
): ReservedTurnChanges => {
|
||||||
|
const deletedGenerals = new Set(deletedGeneralIds);
|
||||||
|
const deletedNations = new Set(deletedNationIds);
|
||||||
|
const keepGeneral = (generalId: number): boolean => !deletedGenerals.has(generalId);
|
||||||
|
const keepNation = (key: string): boolean => !deletedNations.has(Number(key.split(':', 1)[0]));
|
||||||
|
|
||||||
|
return {
|
||||||
|
generalIds: changes.generalIds.filter(keepGeneral),
|
||||||
|
generalInitializationIds: changes.generalInitializationIds.filter(keepGeneral),
|
||||||
|
generalLeaseIds: changes.generalLeaseIds.filter(keepGeneral),
|
||||||
|
nationKeys: changes.nationKeys.filter(keepNation),
|
||||||
|
nationInitializationKeys: changes.nationInitializationKeys.filter(keepNation),
|
||||||
|
nationLeaseKeys: changes.nationLeaseKeys.filter(keepNation),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const asJson = (value: unknown): InputJsonValue => value as InputJsonValue;
|
const asJson = (value: unknown): InputJsonValue => value as InputJsonValue;
|
||||||
const formatLegacyNumber = (value: number): string => Math.round(value).toLocaleString('en-US');
|
const formatLegacyNumber = (value: number): string => Math.round(value).toLocaleString('en-US');
|
||||||
|
|
||||||
@@ -602,6 +622,9 @@ export const createDatabaseTurnHooks = async (
|
|||||||
pendingUnificationFinalizations,
|
pendingUnificationFinalizations,
|
||||||
} = changes;
|
} = changes;
|
||||||
const reservedTurnChanges = options?.reservedTurns?.peekDirtyState();
|
const reservedTurnChanges = options?.reservedTurns?.peekDirtyState();
|
||||||
|
const persistedReservedTurnChanges = reservedTurnChanges
|
||||||
|
? excludeDeletedReservedTurnQueues(reservedTurnChanges, deletedGenerals, deletedNations)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const worldStateUpdate: TurnEngineWorldStateUpdateInput = {
|
const worldStateUpdate: TurnEngineWorldStateUpdateInput = {
|
||||||
currentYear: state.currentYear,
|
currentYear: state.currentYear,
|
||||||
@@ -1010,8 +1033,8 @@ export const createDatabaseTurnHooks = async (
|
|||||||
message
|
message
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (options?.reservedTurns && reservedTurnChanges) {
|
if (options?.reservedTurns && persistedReservedTurnChanges) {
|
||||||
await options.reservedTurns.persistChanges(prisma, reservedTurnChanges);
|
await options.reservedTurns.persistChanges(prisma, persistedReservedTurnChanges);
|
||||||
}
|
}
|
||||||
if (commandCompletion) {
|
if (commandCompletion) {
|
||||||
await prisma.inputEvent.update({
|
await prisma.inputEvent.update({
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import { excludeDeletedReservedTurnQueues } from '../src/turn/databaseHooks.js';
|
||||||
|
|
||||||
|
describe('excludeDeletedReservedTurnQueues', () => {
|
||||||
|
it('omits dirty, initialization, and leased queues owned by deleted entities', () => {
|
||||||
|
expect(
|
||||||
|
excludeDeletedReservedTurnQueues(
|
||||||
|
{
|
||||||
|
generalIds: [1, 2],
|
||||||
|
generalInitializationIds: [2, 3],
|
||||||
|
generalLeaseIds: [1, 2, 3],
|
||||||
|
nationKeys: ['10:12', '20:11'],
|
||||||
|
nationInitializationKeys: ['20:9', '30:12'],
|
||||||
|
nationLeaseKeys: ['10:12', '20:11', '30:12'],
|
||||||
|
},
|
||||||
|
[2],
|
||||||
|
[20]
|
||||||
|
)
|
||||||
|
).toEqual({
|
||||||
|
generalIds: [1],
|
||||||
|
generalInitializationIds: [3],
|
||||||
|
generalLeaseIds: [1, 3],
|
||||||
|
nationKeys: ['10:12'],
|
||||||
|
nationInitializationKeys: ['30:12'],
|
||||||
|
nationLeaseKeys: ['10:12', '30:12'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -524,6 +524,12 @@ integration('RaiseInvader database persistence', () => {
|
|||||||
).toBe(30);
|
).toBe(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await reservedTurns.prepareTurnsForExecution(firstCreatedGeneralId, {
|
||||||
|
nationId: createdNationId,
|
||||||
|
officerLevel: 12,
|
||||||
|
});
|
||||||
|
reservedTurns.shiftGeneralTurns(firstCreatedGeneralId, -1);
|
||||||
|
reservedTurns.shiftNationTurns(createdNationId, 12, -1);
|
||||||
for (const generalId of createdGeneralIds) {
|
for (const generalId of createdGeneralIds) {
|
||||||
expect(world.removeGeneral(generalId)).toBe(true);
|
expect(world.removeGeneral(generalId)).toBe(true);
|
||||||
}
|
}
|
||||||
@@ -539,6 +545,20 @@ integration('RaiseInvader database persistence', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(await db.event.findUnique({ where: { id: createdEventIds[1]! } })).toBeNull();
|
expect(await db.event.findUnique({ where: { id: createdEventIds[1]! } })).toBeNull();
|
||||||
|
expect(await db.generalTurnRevision.findUnique({ where: { generalId: firstCreatedGeneralId } })).toBeNull();
|
||||||
|
expect(
|
||||||
|
await db.nationTurnRevision.findUnique({
|
||||||
|
where: {
|
||||||
|
nationId_officerLevel: { nationId: createdNationId, officerLevel: 12 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).toBeNull();
|
||||||
|
expect(reservedTurns.inspectState()).toMatchObject({
|
||||||
|
dirtyGeneralIds: [],
|
||||||
|
dirtyNationKeys: [],
|
||||||
|
leasedGeneralIds: [],
|
||||||
|
leasedNationKeys: [],
|
||||||
|
});
|
||||||
expect(await db.worldState.findUniqueOrThrow({ where: { id: stateRow.id } })).toMatchObject({
|
expect(await db.worldState.findUniqueOrThrow({ where: { id: stateRow.id } })).toMatchObject({
|
||||||
meta: expect.objectContaining({ isunited: 3, isUnited: 3, refreshLimit: 300 }),
|
meta: expect.objectContaining({ isunited: 3, isUnited: 3, refreshLimit: 300 }),
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user