104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
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<string, QueryValue>): { 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');
|
|
}
|