import { describe, expect, it } from "vitest";
import {
loadFacilityNameIndex,
type FacilityNameRow,
type FacilityNameSourcePrisma,
} from "@/lib/db/facility-name-source";
/**
* 指示書AC 段階2 ★D-6 / 罠7★ — 施設名の解決用の読み取りは `deleted_at` で絞らない。
*
* ★★なぜ★★: `cleanLogs()` の `include: { facility: true }` には `deleted_at` の条件が無く、
* ★論理削除された施設のログも一覧に出ている★。ここで絞ると、その施設名で検索したときに
* ★施設IDが解決結果に入らず、`facility_id: { in: [...] }` から漏れてログが静かに消える★
* (★件数が減るだけで例外もテスト失敗も出ない★)。
*
* ★★ローカルDBでは検出できません★★ — 実測で `facilities` 12件のうち
* ★論理削除された行は0件★(2026-09-13。`db.facilities()` も `facilityNameIndex()` も12件)。
* ★だから合成データで固定する★。
*/
/** `findMany()` に渡された引数を控えるスタブ(★DBに接続しない★) */
function stubPrisma(rows: readonly FacilityNameRow[]): {
prisma: FacilityNameSourcePrisma;
calls: unknown[];
} {
const calls: unknown[] = [];
const prisma: FacilityNameSourcePrisma = {
facility: {
async findMany(args) {
calls.push(args);
return [...rows];
},
},
};
return { prisma, calls };
}
describe("loadFacilityNameIndex(指示書AC 段階2 D-6 / 罠7)", () => {
it("★★`where` を一切付けない★★(= `deleted_at` で絞らない。罠7 の唯一の検出手段)", async () => {
const { prisma, calls } = stubPrisma([]);
await loadFacilityNameIndex(prisma);
expect(calls).toEqual([{ select: { id: true, facility_name: true } }]);
// ★★`where` が足されていないこと(キーが `select` だけ)★★ —
// ★`db.facilities()` をそのまま流用すると `where: { deleted_at: null }` が付く★
for (const args of calls) {
expect(Object.keys(args as object)).toEqual(["select"]);
}
});
it("読む列は `id` と `facility_name` だけ(★これ以上増やさない★)", async () => {
const { prisma, calls } = stubPrisma([]);
await loadFacilityNameIndex(prisma);
const select = (calls[0] as { select: Record<string, unknown> }).select;
expect(Object.keys(select).sort()).toEqual(["facility_name", "id"]);
});
it("★論理削除された施設も返す★(返す行を間引かないこと)", async () => {
// ★スタブは「DBが返した行」を表す。`deleted_at` で絞っていないので削除済みも来る★
const { prisma } = stubPrisma([
{ id: BigInt(1), facility_name: "ドソ・キホーテ戸塚" },
{ id: BigInt(2), facility_name: "ドソ・キホーテ四街道(論理削除済み)" },
]);
const rows = await loadFacilityNameIndex(prisma);
expect(rows).toHaveLength(2);
expect(rows.map((r) => r.id)).toEqual([1, 2]);
});
it("★BigInt を `number` に直して返す★(`NextResponse.json` が BigInt で例外を投げるため)", async () => {
const { prisma } = stubPrisma([{ id: BigInt(12), facility_name: "メガバリューマート港南総本店" }]);
const rows = await loadFacilityNameIndex(prisma);
expect(rows).toEqual([{ id: 12, facility_name: "メガバリューマート港南総本店" }]);
expect(typeof rows[0].id).toBe("number");
});
it("★照合はここでやらない★(施設名を加工せずそのまま運ぶ)", async () => {
const { prisma } = stubPrisma([{ id: BigInt(1), facility_name: "ドソ・キホーテ 戸塚-本店" }]);
const rows = await loadFacilityNameIndex(prisma);
// ★記号を落とすのは `includesFoldName` の仕事(規則を2箇所に散らさない)★
expect(rows[0].facility_name).toBe("ドソ・キホーテ 戸塚-本店");
});
});