(llm-first): context budget, validation, and eval harness, orchestration general-prompt
This commit is contained in:
103
server/src/modules/shared/query-utils.ts
Normal file
103
server/src/modules/shared/query-utils.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
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');
|
||||
}
|
||||
Reference in New Issue
Block a user