Newer
Older
client_dwatch / lib / db / facility-name-source.ts
/**
 * ★施設名 → 施設ID の解決★に使う施設マスタの読み取り(指示書AC 段階2 D-6 / ★罠7★)。
 *
 * ------------------------------------------------------------------------
 * ★★なぜ `db.facilities()` を流用しないのか(★罠7★。消さないこと)★★
 * ------------------------------------------------------------------------
 * `prismaSource.facilities()` は ★`where: { deleted_at: null }`★ を付けています
 * (画面の施設マスタ一覧は論理削除された施設を出さない、という別の要件)。
 *
 * 一方 `cleanLogs()` の `include: { facility: true }` には ★deleted_at の条件がありません★。
 * つまり ★★いまの清掃詳細ログには、論理削除された施設のログも出ています★★。
 *
 * ここで `db.facilities()` を流用すると、★論理削除された施設の名前で検索したときに
 * その施設IDが解決結果に入らず、`facility_id: { in: [...] }` から漏れて
 * ログが検索から**静かに**消えます★(★件数が減るだけで例外もテスト失敗も出ない★)。
 *
 * ★★この関数は「いまの挙動を変えない」ために `deleted_at` で絞りません★★。
 *   ★論理削除された施設を清掃詳細ログから外すかどうかは別の仕様判断★であり、
 *   ★「読み込み行数を減らす」本作業のついでに変えてよいものではありません★
 *   (`CLAUDE.md` §7「仕様が不明な箇所を推測で実装しない」)。
 *   ★★絞りたくなったら `cleanLogs()` の `include` 側と一緒に決めること★★。
 *
 * ------------------------------------------------------------------------
 * ★★照合そのものはここでやらない★★
 * ------------------------------------------------------------------------
 * 照合規則の正は ★`lib/format/search-text.ts` の `includesFoldName`★(指示書AG D-1 / D-5)。
 * この関数は ★行を読むだけ★ で、当たり外れを決めるのは
 * `lib/facilities/resolve-by-name.ts` の純粋関数です(規則を2箇所に散らさない)。
 */
import type { FacilityNameRef } from "@/lib/types";

/** `facilities` から読む列(★これ以上増やさないこと★。解決に要るのは id と名前だけ) */
export interface FacilityNameRow {
  id: bigint;
  facility_name: string;
}

/**
 * この関数が必要とする Prisma の最小限の形(★テストからスタブを渡せるようにするため★)。
 * ★`PrismaClient` をそのまま要求しないこと★ — 生成済みクライアントが無い環境でも
 * 単体テストが走るようにしてある(`lib/db/consecutive-source.ts` と同じ作法)。
 */
export interface FacilityNameSourcePrisma {
  facility: {
    findMany(args: {
      select: { id: true; facility_name: true };
    }): Promise<FacilityNameRow[]>;
  };
}

/**
 * 施設名の照合に使う行だけを、★列を絞って★全件読む。
 *
 * ★★`where` を足さないこと★★ — ★`deleted_at` で絞ると論理削除された施設のログが
 *   検索から静かに消えます★(上の「罠7」)。
 *   ★テスト(`lib/db/__tests__/facility-name-source.test.ts`)が
 *   「渡した引数のキーが `select` だけであること」を固定しています★。
 *
 * ★全件読んでよい理由★: 施設マスタは ★fixtures / seed / ローカルDB すべて実測12件★
 *   (指示書AC §E-5)。★清掃ログ本体(本番想定で約26万行)とは桁が違います★。
 *   ★施設が200件を超えたら `facility_id: { in: [...] }` の実行計画が静かに劣化する★
 *   という別の注意はありますが(申し送り⑫)、この読み取り自体は問題になりません。
 */
export async function loadFacilityNameIndex(
  prisma: FacilityNameSourcePrisma
): Promise<FacilityNameRef[]> {
  const rows = await prisma.facility.findMany({
    select: { id: true, facility_name: true },
  });
  // ★BigInt を残すと `NextResponse.json` が例外を投げる(`lib/db/index.ts` と同じ作法)★
  return rows.map((row) => ({
    id: Number(row.id),
    facility_name: row.facility_name,
  }));
}