import type { Response } from 'express'; import { Prisma } from '@prisma/client'; export type QueryValue = unknown; export function getSingle(value: QueryValue): string | undefined { if (Array.isArray(value)) { const first = value[0]; return typeof first === 'string' ? first : first === undefined || first === null ? undefined : String(first); } if (typeof value === 'string') { return value; } if (value === undefined || value === null) { return undefined; } return String(value); } export function getFirst(value: QueryValue): string | undefined { return getSingle(value); } export function getStringArray(value: QueryValue): string[] { if (Array.isArray(value)) { return value .filter((item) => item !== undefined && item !== null && item !== '') .map((item) => String(item)); } if (value === undefined || value === null || value === '') { return []; } return [String(value)]; } export function toArray(value: QueryValue): string[] { return getStringArray(value); } export function parseRange(query: Record): { start: number; end: number; take: number } { const start = Number(getFirst(query._start) ?? 0); const end = Number(getFirst(query._end) ?? start + 25); const safeStart = Number.isFinite(start) && start >= 0 ? start : 0; const safeEnd = Number.isFinite(end) && end > safeStart ? end : safeStart + 25; return { start: safeStart, end: safeEnd, take: safeEnd - safeStart, }; } export function toSortOrder(value: string | undefined): 'asc' | 'desc' { return String(value ?? 'ASC').toLowerCase() === 'desc' ? 'desc' : 'asc'; } export function containsInsensitive(value: string) { return { contains: value, mode: 'insensitive' as const, }; } export function toNumberValue(value: unknown): number | null | undefined { if (value === undefined) return undefined; if (value === null || value === '') return null; const numeric = Number(value); return Number.isNaN(numeric) ? undefined : numeric; } export function toDateValue(value: unknown): Date | null | undefined { if (value === undefined) return undefined; if (value === null || value === '') return null; return new Date(String(value)); } export function toDecimalValue(value: unknown): Prisma.Decimal | null | undefined { if (value === undefined) return undefined; if (value === null || value === '') return null; return new Prisma.Decimal(String(value)); } export function setListHeaders( response: Response, totalOrResource: number | string, start: number, end: number, resourceOrTotal: string | number, ): void { const total = typeof totalOrResource === 'number' ? totalOrResource : Number(resourceOrTotal); const resource = typeof totalOrResource === 'string' ? totalOrResource : String(resourceOrTotal); const safeStart = Number.isFinite(start) ? start : 0; const safeEnd = Number.isFinite(end) ? end : safeStart; const contentEnd = total === 0 ? safeStart : Math.min(Math.max(safeEnd - 1, safeStart), Math.max(total - 1, safeStart)); response.setHeader('Content-Range', `${resource} ${safeStart}-${contentEnd}/${total}`); response.setHeader('Access-Control-Expose-Headers', 'Content-Range'); }