/**
* JST の `YYYY-MM-DD` の範囲を、★Prisma の `where` に渡せる「DBの壁時計値」★ に変換する
* (指示書AC 段階2 D-2 / ★C-6★)。
*
* ------------------------------------------------------------------------
* ★★なぜ純粋関数に切り出したのか — ローカルDBではこの間違いを検出できないから★★
* ------------------------------------------------------------------------
* `clean_timetables.start_at` は DATETIME で、中身は ★日本時間の壁時計値★ です
* (TeamWorks 第8回 A2 / D-115 / `fromDbJst()` の docstring)。
* 一方 `parseDate("2026-09-08")`(`lib/clean-logs/query.ts`)が返すのは ★真の瞬間★ です。
*
* ```
* parseDate("2026-09-08") = 2026-09-07T15:00:00.000Z (真の瞬間)
* toDbJst(parseDate("2026-09-08")) = 2026-09-08T00:00:00.000Z (DBの壁時計値として渡せる形)
* ```
*
* ★★この2つをそのまま比較すると9時間ずれ、境界の行が静かに消えます★★。
*
* ★★ところがローカルDB(`dwatch_local`)ではこの間違いが1件も表に出ません★★ —
* `clean_timetables` 1,044行の `start_at`(壁時計)は ★0時:210 / 1時:516 / 2時:288 / 3時:30★ で、
* ★15時以降が0件★。9時間ずらしても日付が変わらない時間帯にしかデータがないため、
* ★補正を忘れても件数が1件も変わりません★(指示書AC C-6 の実測)。
* ★★だからこの関数には「壁時計 20:00 の清掃」を含む合成データの単体テストがあります★★
* (`lib/db/__tests__/date-range.test.ts`)。★そのテストを消さないこと★。
*/
import { parseDate } from "@/lib/clean-logs/query";
import { toDbJst } from "@/lib/format/date";
/** Prisma の `where.start_at` にそのまま展開できる形(`gte` / `lt` は無ければキーごと無い) */
export interface DbDateRange {
gte?: Date;
lt?: Date;
}
/** 1日(ミリ秒)。`to` を「その日を含む」=「翌日 00:00 未満」にするために足す */
const ONE_DAY_MS = 86_400_000;
/**
* @param from JST の `YYYY-MM-DD`。★下限なしは `null`★
* @param to JST の `YYYY-MM-DD`。★上限なしは `null`★。★その日を**含む**★
* @returns `{ gte?, lt? }`。★どちらも無ければ空オブジェクト★(呼び出し側は
* `start_at` のキーごと付けないこと。`start_at: {}` は Prisma では条件なしだが、
* ★キーを付けないほうが生成SQLを読んだときに意図が分かる★)
*
* ★形式が不正な文字列(`parseDate()` が `null` を返すもの)は「指定なし」として扱う★ —
* ★★ここに検証を持たせないこと★★。入口の検証は `parseCleanLogQuery()` の仕事で
* (422 を返す。指示書AC §E-2)、そこを通った値しかここには来ない。
* ★2箇所で検証すると、片方だけ緩めたときに気づけない★。
*/
export function dbDateRange(from: string | null, to: string | null): DbDateRange {
const range: DbDateRange = {};
const fromDate = parseDate(from);
if (fromDate) {
// ★★必ず `toDbJst()` を通す★★(通さないと9時間ずれる。C-6)
range.gte = toDbJst(fromDate);
}
const toDate = parseDate(to);
if (toDate) {
// ★`to` はその日を**含む**ので「翌日 00:00 未満」にする★。
// ★★`lte: その日 23:59:59` にしないこと★★ — `start_at` は DATETIME(0) なので
// いまは秒までだが、桁が増えたときに 23:59:59.5 の行が静かに落ちる。
range.lt = toDbJst(new Date(toDate.getTime() + ONE_DAY_MS));
}
return range;
}