/**
* `in: [...]` に渡す配列の分割(指示書AC 段階2 D-4 / ★§E-5★)。
*
* ★DBアクセスを混ぜない純粋関数★(上限の理由と値は `DB_IN_CLAUSE_MAX_ITEMS` の
* docstring にまとめてある。★ここに数字を直書きしないこと★。`CLAUDE.md` §7)。
*/
import { DB_IN_CLAUSE_MAX_ITEMS } from "@/lib/config";
/**
* `ids` を `DB_IN_CLAUSE_MAX_ITEMS` 件ずつの塊に分ける。
*
* ★★空配列は「塊が0個」を返す★★ — ★`[[]]`(空の塊1個)を返さないこと★。
* ★`in: []` を投げるクエリが1本走ってしまい、必ず0件なのに往復が発生します★。
* ★呼び出し側は「塊が0個 → クエリを1本も撃たず、空配列で続行」と書けること★。
*
* ★★`in: undefined` に化ける書き方をしないこと★★(罠1)— この関数は
* `clean_timetable_id` / `parent_id` のような ★「引いた id で引き直す」用途専用★ で、
* 「条件なし(全件)」を表す値を持ちません。★条件の有無の分岐は呼び出し側で `!== null`★。
*/
export function chunkForInClause<T>(
ids: readonly T[],
size: number = DB_IN_CLAUSE_MAX_ITEMS
): T[][] {
if (size < 1) {
// ★設定値が壊れたまま「1件ずつ無限に分割」や「無限ループ」に落ちるより、気づけるほうを選ぶ★
throw new Error(`[db] chunkForInClause: 分割サイズは1以上である必要があります(${size})`);
}
const chunks: T[][] = [];
for (let i = 0; i < ids.length; i += size) {
chunks.push(ids.slice(i, i + size));
}
return chunks;
}