// The only values ever interpolated into SQL (sort column and direction) come // from the whitelists here; everything else is a bind parameter. const SORT_COLUMNS = { agreementUuid: '"agreementUuid"', eventUuid: '"eventUuid"', sender: "sender", date: "date", size: '"size"', }; export const SORTABLE_KEYS = Object.keys(SORT_COLUMNS); export function sortClause(sort, dir) { const col = SORT_COLUMNS[sort] || "date"; const direction = String(dir).toLowerCase() === "asc" ? "ASC" : "DESC"; return `ORDER BY ${col} ${direction} NULLS LAST`; } export function eventSearchClause(idx) { return ( `(e.event_id_uuid::text ILIKE '%'||$${idx}||'%'` + ` OR agr.agreement_id_uuid::text ILIKE '%'||$${idx}||'%'` + ` OR e.sender_id ILIKE '%'||$${idx}||'%'` + ` OR e.recipient_id ILIKE '%'||$${idx}||'%')` ); } export const DEFAULT_LIMIT = 50; const MAX_LIMIT = 200; // Server-side bound, applied on every request regardless of what the UI sends. export function clampLimit(v) { const n = parseInt(v, 10); if (!Number.isFinite(n)) return DEFAULT_LIMIT; return Math.min(Math.max(n, 1), MAX_LIMIT); } export function clampOffset(v) { const n = parseInt(v, 10); if (!Number.isFinite(n) || n < 0) return 0; return n; } export function pageCount(total, perPage = DEFAULT_LIMIT) { return Math.max(1, Math.ceil((Number(total) || 0) / (perPage || DEFAULT_LIMIT))); } const MAX_WINDOW_DAYS = 366; // Enforced server-side on every request, not in the UI. export function windowParams(query = {}) { const iso = (d) => d.toISOString().slice(0, 10); const valid = (s) => typeof s === "string" && /^\d{4}-\d{2}-\d{2}$/.test(s); const today = new Date(); today.setUTCHours(0, 0, 0, 0); const to = valid(query.to) ? query.to : iso(today); let from = valid(query.from) ? query.from : null; if (!from) { const d = new Date(`${to}T00:00:00Z`); d.setUTCDate(d.getUTCDate() - 29); from = iso(d); } let fromD = new Date(`${from}T00:00:00Z`); const toD = new Date(`${to}T00:00:00Z`); if (fromD > toD) { from = to; fromD = new Date(toD); } if ((toD - fromD) / 86_400_000 > MAX_WINDOW_DAYS) { const capped = new Date(toD); capped.setUTCDate(capped.getUTCDate() - MAX_WINDOW_DAYS); from = iso(capped); } return { from, to }; }