139 lines
5.7 KiB
TypeScript
139 lines
5.7 KiB
TypeScript
import { z } from 'zod';
|
|
import { auditProcedure, findAuditMonth, readAudit, readAuditWorld, zAuditMonth } from './shared.js';
|
|
import {
|
|
citySelect,
|
|
generalSelect,
|
|
projectCurrentCity,
|
|
projectCurrentGeneral,
|
|
zAuditCityData,
|
|
zAuditGeneralData,
|
|
} from './projection.js';
|
|
|
|
const identity = z.object({ id: z.number(), name: z.string() });
|
|
const zDetail = z.object({ id: z.number().int().nonnegative(), at: zAuditMonth.optional() }).strict();
|
|
|
|
export const generalDetail = auditProcedure.input(zDetail).query(({ ctx, input }) =>
|
|
readAudit(ctx, async (tx) => {
|
|
const world = await readAuditWorld(tx);
|
|
if (input.at) {
|
|
const sample = await findAuditMonth(tx, world, input.at);
|
|
const row = sample
|
|
? await tx.playAuditGeneral.findUnique({
|
|
where: { sampleId_generalId: { sampleId: sample.id, generalId: input.id } },
|
|
select: { data: true },
|
|
})
|
|
: null;
|
|
const general = row ? zAuditGeneralData.parse(row.data) : null;
|
|
const nation =
|
|
general && sample
|
|
? await tx.playAuditNation.findUnique({
|
|
where: { sampleId_nationId: { sampleId: sample.id, nationId: general.nationId } },
|
|
select: { data: true },
|
|
})
|
|
: null;
|
|
const city =
|
|
general && sample
|
|
? await tx.playAuditCity.findUnique({
|
|
where: { sampleId_cityId: { sampleId: sample.id, cityId: general.cityId } },
|
|
select: { data: true },
|
|
})
|
|
: null;
|
|
return {
|
|
...world,
|
|
sample,
|
|
collected: Boolean(sample),
|
|
general,
|
|
nation: nation ? identity.parse(nation.data) : null,
|
|
city: city ? identity.parse(city.data) : null,
|
|
};
|
|
}
|
|
const row = await tx.general.findUnique({ where: { id: input.id }, select: generalSelect });
|
|
const general = row ? projectCurrentGeneral(row) : null;
|
|
const nation = general
|
|
? await tx.nation.findUnique({ where: { id: general.nationId }, select: { id: true, name: true } })
|
|
: null;
|
|
const city = general
|
|
? await tx.city.findUnique({ where: { id: general.cityId }, select: { id: true, name: true } })
|
|
: null;
|
|
return { ...world, sample: null, collected: true, general, nation, city };
|
|
})
|
|
);
|
|
|
|
export const cityDetail = auditProcedure.input(zDetail).query(({ ctx, input }) =>
|
|
readAudit(ctx, async (tx) => {
|
|
const world = await readAuditWorld(tx);
|
|
if (input.at) {
|
|
const sample = await findAuditMonth(tx, world, input.at);
|
|
const row = sample
|
|
? await tx.playAuditCity.findUnique({
|
|
where: { sampleId_cityId: { sampleId: sample.id, cityId: input.id } },
|
|
select: { data: true },
|
|
})
|
|
: null;
|
|
const city = row ? zAuditCityData.parse(row.data) : null;
|
|
const nation =
|
|
city && sample
|
|
? await tx.playAuditNation.findUnique({
|
|
where: { sampleId_nationId: { sampleId: sample.id, nationId: city.nationId } },
|
|
select: { data: true },
|
|
})
|
|
: null;
|
|
return {
|
|
...world,
|
|
sample,
|
|
collected: Boolean(sample),
|
|
city,
|
|
nation: nation ? identity.parse(nation.data) : null,
|
|
};
|
|
}
|
|
const row = await tx.city.findUnique({ where: { id: input.id }, select: citySelect });
|
|
const city = row ? projectCurrentCity(row) : null;
|
|
const nation = city
|
|
? await tx.nation.findUnique({ where: { id: city.nationId }, select: { id: true, name: true } })
|
|
: null;
|
|
return { ...world, sample: null, collected: true, city, nation };
|
|
})
|
|
);
|
|
|
|
// 현재 예약은 과거 표본과 분리한다. 잘못된 slot도 숨기지 않고 페이지로 조회한다.
|
|
export const generalTurns = auditProcedure
|
|
.input(
|
|
z
|
|
.object({
|
|
generalId: z.number().int().nonnegative(),
|
|
cursor: z.number().int().optional(),
|
|
limit: z.number().int().min(1).max(200).default(50),
|
|
})
|
|
.strict()
|
|
)
|
|
.query(({ ctx, input }) =>
|
|
readAudit(ctx, async (tx) => {
|
|
const world = await readAuditWorld(tx);
|
|
const general = await tx.general.findUnique({ where: { id: input.generalId }, select: { id: true } });
|
|
const rows = general
|
|
? await tx.generalTurn.findMany({
|
|
where: {
|
|
generalId: input.generalId,
|
|
turnIdx: input.cursor === undefined ? undefined : { gt: input.cursor },
|
|
},
|
|
orderBy: { turnIdx: 'asc' },
|
|
take: input.limit + 1,
|
|
select: { turnIdx: true, actionCode: true, arg: true },
|
|
})
|
|
: [];
|
|
return {
|
|
...world,
|
|
currentOnly: true,
|
|
generalExists: Boolean(general),
|
|
items: rows
|
|
.slice(0, input.limit)
|
|
.map((row) => ({
|
|
turnIdx: row.turnIdx,
|
|
actionCode: row.actionCode,
|
|
argumentJson: JSON.stringify(row.arg),
|
|
})),
|
|
nextCursor: rows.length > input.limit ? rows[input.limit - 1]!.turnIdx : null,
|
|
};
|
|
})
|
|
);
|