/** * Type coercion utilities for query parameters * Converts string values from query params to proper types based on JSON Schema */ import type { TJsonSchema, IOpenApiParamMeta } from '../decorators/decorators.types.js'; /** * Coerce a single value based on JSON Schema type */ export function coerceValue(value: string | undefined, schema: TJsonSchema): unknown { if (value === undefined || value === '') { // Return default if available if (schema.default !== undefined) { return schema.default; } return undefined; } const type = Array.isArray(schema.type) ? schema.type[0] : schema.type; switch (type) { case 'integer': { const num = parseInt(value, 10); return isNaN(num) ? value : num; } case 'number': { const num = parseFloat(value); return isNaN(num) ? value : num; } case 'boolean': { if (value === 'true' || value === '1') return true; if (value === 'false' || value === '0' || value === '') return false; return value; } case 'array': { // Handle comma-separated values const items = value.split(',').map(item => item.trim()); if (schema.items) { return items.map(item => coerceValue(item, schema.items as TJsonSchema)); } return items; } case 'null': { if (value === 'null' || value === '') return null; return value; } case 'object': { // Attempt to parse JSON try { return JSON.parse(value); } catch { return value; } } case 'string': default: return value; } } /** * Coerce all query parameters based on their schemas */ export function coerceQueryParams( query: Record, schemas: Map ): Record { const result: Record = { ...query }; for (const [name, meta] of schemas) { if (meta.schema) { const rawValue = query[name]; const coercedValue = coerceValue(rawValue, meta.schema); if (coercedValue !== undefined) { result[name] = coercedValue; } else if (meta.schema.default !== undefined) { // Apply default when value is missing result[name] = meta.schema.default; } } } return result; } /** * Coerce path parameters based on their schemas */ export function coercePathParams( params: Record, schemas: Map ): Record { const result: Record = { ...params }; for (const [name, meta] of schemas) { if (meta.schema && params[name] !== undefined) { result[name] = coerceValue(params[name], meta.schema); } } return result; }