플레이 감사 장수 이름 검색과 번호 역순 조회 추가

This commit is contained in:
2026-09-16 07:32:29 +00:00
parent 52cea882ab
commit 2f5036ea6b
6 changed files with 122 additions and 7 deletions
+15 -4
View File
@@ -154,6 +154,8 @@ export const playAuditRouter = router({
zAuditPage.extend({
cityId: z.number().int().nonnegative().optional(),
population: z.enum(['human', 'npc', 'troopNpc']).optional(),
name: z.string().trim().max(64).optional(),
order: z.enum(['asc', 'desc']).default('asc'),
})
)
.query(({ ctx, input }) =>
@@ -168,6 +170,14 @@ export const playAuditRouter = router({
? 5
: undefined;
const filter = { nationId: input.nationId, cityId: input.cityId, npcState };
// LIKE wildcard도 이름의 문자로 취급한다. 과거 검색은 선택한 표본 안에서만 수행한다.
const name = input.name?.replace(/[\\%_]/g, '\\$&');
const idRange =
input.cursor === undefined
? undefined
: input.order === 'desc'
? { lt: input.cursor }
: { gt: input.cursor };
if (input.at) {
const sample = await findAuditMonth(tx, world, input.at);
const rows = sample
@@ -175,9 +185,10 @@ export const playAuditRouter = router({
where: {
sampleId: sample.id,
...filter,
generalId: input.cursor === undefined ? undefined : { gt: input.cursor },
generalId: idRange,
data: name ? { path: ['name'], string_contains: name } : undefined,
},
orderBy: { generalId: 'asc' },
orderBy: { generalId: input.order },
take: input.limit + 1,
select: { data: true },
})
@@ -194,8 +205,8 @@ export const playAuditRouter = router({
};
}
const rows = await tx.general.findMany({
where: { ...filter, id: input.cursor === undefined ? undefined : { gt: input.cursor } },
orderBy: { id: 'asc' },
where: { ...filter, id: idRange, name: name ? { contains: name } : undefined },
orderBy: { id: input.order },
take: input.limit + 1,
select: generalSelect,
});
@@ -2628,6 +2628,43 @@ integration('game API security over HTTP transport', () => {
result: { data: { collected: true, items: [{ name: '과거이름' }] } },
});
expect(JSON.stringify(history.body)).not.toContain('must-not-expose');
for (const name of ['과거', ' 과거 ']) {
expect((await get('generals', admin, { at: { year: 190, month: 1 }, name })).body).toMatchObject({
result: { data: { items: [{ name: '과거이름' }] } },
});
}
for (const name of ['없는이름', '%', '_', '\\']) {
expect((await get('generals', admin, { at: { year: 190, month: 1 }, name })).body).toMatchObject({
result: { data: { items: [] } },
});
}
const currentName = (await db.general.findUniqueOrThrow({ where: { id: generalId } })).name;
expect((await get('generals', admin, { name: currentName })).body).toMatchObject({
result: { data: { items: expect.arrayContaining([expect.objectContaining({ id: generalId })]) } },
});
expect((await get('generals', admin, { name: '과거이름' })).body).toMatchObject({
result: { data: { items: [] } },
});
expect((await get('generals', admin, { name: '%' })).body).toMatchObject({
result: { data: { items: [] } },
});
const descendingIds = await db.general.findMany({ orderBy: { id: 'desc' }, select: { id: true } });
expect((await get('generals', admin, { order: 'desc', limit: 1 })).body).toMatchObject({
result: { data: { nextCursor: descendingIds[0]!.id, items: [descendingIds[0]] } },
});
expect(
(await get('generals', admin, { order: 'desc', limit: 1, cursor: descendingIds[0]!.id })).body
).toMatchObject({
result: { data: { items: [descendingIds[1]] } },
});
expect(
(await get('generals', admin, { order: 'desc', at: { year: 190, month: 1 }, cursor: generalId })).body
).toMatchObject({
result: { data: { items: [] } },
});
expect((await get('generals', admin, { name: '가'.repeat(65) })).status).toBe(400);
expect((await get('generals', admin, { order: 'gold' })).status).toBe(400);
expect((await get('generals', admin, { at: { year: 190, month: 2 } })).body).toMatchObject({
result: { data: { collected: false, items: [] } },
});