@leancodepl/validation
Version: 
CQRS validation helpers for command and query validation
126 lines (123 loc) • 4.6 kB
JavaScript
/**
 * 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 };