perf(game-api): 사령부 예약턴 조회를 일괄화한다
관직 8개의 턴과 revision을 16개 개별 query 대신 두 번의 findMany로 읽고 기존 응답 기본값을 회귀 검증한다.
This commit is contained in:
@@ -3,7 +3,7 @@ import { TRPCError } from '@trpc/server';
|
|||||||
import { accessAuthedProcedure } from '../../../trpc.js';
|
import { accessAuthedProcedure } from '../../../trpc.js';
|
||||||
import { getMyGeneral } from '../../shared/general.js';
|
import { getMyGeneral } from '../../shared/general.js';
|
||||||
import { resolveSecretPermission } from '../../shared/secretPermission.js';
|
import { resolveSecretPermission } from '../../shared/secretPermission.js';
|
||||||
import { MAX_NATION_TURNS, getNationTurnSnapshot } from '../../../turns/reservedTurns.js';
|
import { MAX_NATION_TURNS, getNationTurnSnapshots } from '../../../turns/reservedTurns.js';
|
||||||
import { assertNationAccess } from '../shared.js';
|
import { assertNationAccess } from '../shared.js';
|
||||||
|
|
||||||
export const getChiefCenter = accessAuthedProcedure.query(async ({ ctx }) => {
|
export const getChiefCenter = accessAuthedProcedure.query(async ({ ctx }) => {
|
||||||
@@ -56,17 +56,18 @@ export const getChiefCenter = accessAuthedProcedure.query(async ({ ctx }) => {
|
|||||||
const chiefLevels = [12, 10, 8, 6, 11, 9, 7, 5];
|
const chiefLevels = [12, 10, 8, 6, 11, 9, 7, 5];
|
||||||
const generalByLevel = new Map(nationGenerals.map((general) => [general.officerLevel, general]));
|
const generalByLevel = new Map(nationGenerals.map((general) => [general.officerLevel, general]));
|
||||||
|
|
||||||
const turnsByLevel = await Promise.all(chiefLevels.map((level) => getNationTurnSnapshot(ctx.db, nation.id, level)));
|
const turnsByLevel = await getNationTurnSnapshots(ctx.db, nation.id, chiefLevels);
|
||||||
|
|
||||||
const chiefs = chiefLevels.map((level, idx) => {
|
const chiefs = chiefLevels.map((level) => {
|
||||||
const entry = generalByLevel.get(level);
|
const entry = generalByLevel.get(level);
|
||||||
|
const snapshot = turnsByLevel.get(level);
|
||||||
return {
|
return {
|
||||||
officerLevel: level,
|
officerLevel: level,
|
||||||
name: entry?.name ?? null,
|
name: entry?.name ?? null,
|
||||||
npcState: entry?.npcState ?? null,
|
npcState: entry?.npcState ?? null,
|
||||||
turnTime: entry?.turnTime ? entry.turnTime.toISOString() : null,
|
turnTime: entry?.turnTime ? entry.turnTime.toISOString() : null,
|
||||||
revision: turnsByLevel[idx]?.revision ?? 0,
|
revision: snapshot?.revision ?? 0,
|
||||||
turns: turnsByLevel[idx]?.turns ?? [],
|
turns: snapshot?.turns ?? [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,42 @@ export const getNationTurnSnapshot = async (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getNationTurnSnapshots = async (
|
||||||
|
db: DatabaseClient,
|
||||||
|
nationId: number,
|
||||||
|
officerLevels: readonly number[]
|
||||||
|
): Promise<Map<number, ReservedTurnSnapshot>> => {
|
||||||
|
const levels = [...new Set(officerLevels)];
|
||||||
|
if (levels.length === 0) return new Map();
|
||||||
|
const [turnRows, revisionRows] = await Promise.all([
|
||||||
|
db.nationTurn.findMany({
|
||||||
|
where: { nationId, officerLevel: { in: levels } },
|
||||||
|
orderBy: [{ officerLevel: 'asc' }, { turnIdx: 'asc' }],
|
||||||
|
}),
|
||||||
|
db.nationTurnRevision.findMany({
|
||||||
|
where: { nationId, officerLevel: { in: levels } },
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
const turnsByLevel = new Map<number, NationTurnRow[]>();
|
||||||
|
for (const row of turnRows) {
|
||||||
|
const rows = turnsByLevel.get(row.officerLevel) ?? [];
|
||||||
|
rows.push(row);
|
||||||
|
turnsByLevel.set(row.officerLevel, rows);
|
||||||
|
}
|
||||||
|
const revisionByLevel = new Map(revisionRows.map((row) => [row.officerLevel, row.revision]));
|
||||||
|
return new Map(
|
||||||
|
levels.map((level) => [
|
||||||
|
level,
|
||||||
|
{
|
||||||
|
revision: revisionByLevel.get(level) ?? 0,
|
||||||
|
turns: serializeTurnList(
|
||||||
|
buildTurnListFromRows(turnsByLevel.get(level) ?? [], MAX_NATION_TURNS)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const claimGeneralRevision = async (
|
const claimGeneralRevision = async (
|
||||||
db: DatabaseClient,
|
db: DatabaseClient,
|
||||||
generalId: number,
|
generalId: number,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
MAX_GENERAL_TURNS,
|
MAX_GENERAL_TURNS,
|
||||||
MAX_NATION_TURNS,
|
MAX_NATION_TURNS,
|
||||||
expandGeneralTurnIndices,
|
expandGeneralTurnIndices,
|
||||||
|
getNationTurnSnapshots,
|
||||||
repeatGeneralTurns,
|
repeatGeneralTurns,
|
||||||
repeatNationTurns,
|
repeatNationTurns,
|
||||||
setGeneralTurn,
|
setGeneralTurn,
|
||||||
@@ -201,6 +202,52 @@ const buildDb = (autorunLimit: number | null = null) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('reservedTurns', () => {
|
describe('reservedTurns', () => {
|
||||||
|
it('loads multiple nation officer queues with two batched queries and preserves defaults', async () => {
|
||||||
|
const findTurns = vi.fn(async () => [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
nationId: 4,
|
||||||
|
officerLevel: 12,
|
||||||
|
turnIdx: 1,
|
||||||
|
actionCode: 'che_징병',
|
||||||
|
arg: { amount: 100 },
|
||||||
|
createdAt: new Date(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
nationId: 4,
|
||||||
|
officerLevel: 10,
|
||||||
|
turnIdx: 0,
|
||||||
|
actionCode: 'che_훈련',
|
||||||
|
arg: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
},
|
||||||
|
] satisfies NationTurnRow[]);
|
||||||
|
const findRevisions = vi.fn(async () => [
|
||||||
|
{ nationId: 4, officerLevel: 12, revision: 7, updatedAt: new Date() },
|
||||||
|
]);
|
||||||
|
const db = {
|
||||||
|
nationTurn: { findMany: findTurns },
|
||||||
|
nationTurnRevision: { findMany: findRevisions },
|
||||||
|
} as unknown as DatabaseClient;
|
||||||
|
|
||||||
|
const snapshots = await getNationTurnSnapshots(db, 4, [12, 10, 8, 12]);
|
||||||
|
|
||||||
|
expect(findTurns).toHaveBeenCalledOnce();
|
||||||
|
expect(findRevisions).toHaveBeenCalledOnce();
|
||||||
|
expect(snapshots.size).toBe(3);
|
||||||
|
expect(snapshots.get(12)?.revision).toBe(7);
|
||||||
|
expect(snapshots.get(12)?.turns.slice(0, 2)).toEqual([
|
||||||
|
{ index: 0, action: '휴식', args: {} },
|
||||||
|
{ index: 1, action: 'che_징병', args: { amount: 100 } },
|
||||||
|
]);
|
||||||
|
expect(snapshots.get(10)?.revision).toBe(0);
|
||||||
|
expect(snapshots.get(10)?.turns[0]).toEqual({ index: 0, action: 'che_훈련', args: {} });
|
||||||
|
expect(snapshots.get(8)?.revision).toBe(0);
|
||||||
|
expect(snapshots.get(8)?.turns[0]).toEqual({ index: 0, action: '휴식', args: {} });
|
||||||
|
expect(snapshots.get(8)?.turns).toHaveLength(MAX_NATION_TURNS);
|
||||||
|
});
|
||||||
|
|
||||||
it('sets and shifts general turns', async () => {
|
it('sets and shifts general turns', async () => {
|
||||||
const { db } = buildDb(2408);
|
const { db } = buildDb(2408);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user