UNPKG

@leancodepl/validation

Version:

CQRS validation helpers for command and query validation

126 lines (123 loc) 4.6 kB
/** * Creates a validation error handler that processes errors with type-safe error code mapping. * * @template TAllErrors - Error codes map type extending Record<string, number> * @template TInResult - Type of results accumulated from previous handlers * @param validationErrors - Array of validation errors to process * @param errorCodesMap - Mapping of error names to numeric codes * @param validationResults - Optional array of previous handler results * @returns Handler with handle, handleAll, and check methods * @example * ```typescript * const errorCodes = { EmailExists: 1, InvalidEmail: 2 } as const; * const errors = [{ ErrorCode: 1, ErrorMessage: 'Email exists', PropertyName: 'Email', AttemptedValue: 'test@example.com' }]; * * handleValidationErrors(errors, errorCodes) * .handle('EmailExists', () => console.warn('Email already registered')) * .handle('InvalidEmail', () => console.warn('Invalid email format')) * .check(); * ``` */ function handleValidationErrors(validationErrors, errorCodesMap, validationResults = []) { const handle = (validationErrorsToHandle, handler)=>{ let result = undefined; for (const validationErrorToHandle of Array.isArray(validationErrorsToHandle) ? validationErrorsToHandle : [ validationErrorsToHandle ]){ const ve = validationErrors.find((ve)=>ve.ErrorCode === errorCodesMap[validationErrorToHandle]); if (ve) { result = handler(validationErrorToHandle, ve); break; } } let nextResult = validationResults; if (result !== undefined) { nextResult = [ ...nextResult, result ]; } return handleValidationErrors(validationErrors, errorCodesMap, nextResult); }; const handleAll = (_validationErrorsToHandle, handler)=>{ let result = undefined; const validationErrorsToHandle = Array.isArray(_validationErrorsToHandle) ? _validationErrorsToHandle : [ _validationErrorsToHandle ]; const foundErrors = validationErrorsToHandle.reduce((prev, cur)=>{ const ves = validationErrors.filter((ve)=>ve.ErrorCode === errorCodesMap[cur]); if (ves.length === 0) { return prev; } return [ ...prev, { errorName: cur, errors: ves } ]; }, []); if (foundErrors.length > 0) { result = handler(foundErrors); } let nextResult = validationResults; if (result !== undefined) { nextResult = [ ...nextResult, result ]; } return handleValidationErrors(validationErrors, errorCodesMap, nextResult); }; return { handle, handleAll, check: (reducer)=>{ if (reducer) { return validationResults.reduce(reducer.reducer, reducer.initialValue); } return; } }; } /** * Handles CQRS command responses and transforms them into validation error handlers. * * @template TErrors - Error codes map type extending Record<string, number> * @param response - API response containing command result * @param errorCodesMap - Mapping of error names to numeric codes * @returns Validation error handler with success/failure support * @example * ```typescript * const errorCodes = { UserNotFound: 1 } as const; * const response = await commandClient.execute(createUserCommand); * * handleResponse(response, errorCodes) * .handle('success', () => console.log('User created')) * .handle('failure', () => console.log('Network error')) * .handle('UserNotFound', () => console.log('User not found')) * .check(); * ``` */ function handleResponse(response, errorCodesMap) { const newErrorCodesMap = { ...errorCodesMap, success: -1, failure: -2 }; const validationErrors = response.isSuccess ? response.result.WasSuccessful ? [ { AttemptedValue: "", ErrorMessage: "", PropertyName: "", ErrorCode: -1 } ] : response.result.ValidationErrors : [ { AttemptedValue: "", ErrorMessage: "", PropertyName: "", ErrorCode: -2 } ]; return handleValidationErrors(validationErrors, newErrorCodesMap); } export { handleResponse, handleValidationErrors };