making/yavi

How to transfor - Validated<A> to Validated<B>

ffroliva opened this issue · 12 comments

I have the following Validated<A> a; with errors. and I want to transform it to Validated<B> b. How can achieve that?

Thank you in advance.

Hi,

I wanted to combine the errors from two Validated into a single ConstraintViolations.

Validated<A> or Validated<B> errors might exist because the validations where successfull.

This is how I did and it might be interesting for others:

import am.ik.yavi.core.ConstraintViolations;
import am.ik.yavi.core.Validated;

import java.util.Collection;
import java.util.Collections;
import java.util.stream.Stream;

public class ConstraintViolationsUtil {

    public static ConstraintViolations combineConstraintViolations(Validated<?>... validated) {
        return ConstraintViolations.of(Stream.of(validated)
                .map(ConstraintViolationsUtil::getErrorsIfInvalid)
                .map(ConstraintViolations::violations)
                .flatMap(Collection::stream)
                .toList());
    }


    public static ConstraintViolations getErrorsIfInvalid(Validated<?> validated) {
        return validated.isValid() ? ConstraintViolations.of(Collections.emptyList()) : validated.errors();
    }

}

As a result I generated a object Validated.of(Validated.failure(constraintViolations))

Yes, but didn't work for me.

Basically, I have a matrix of data and I have to perform several validations on it. Column headers, row headers, and the data itself.

I only care about the data to generate my Validated<T> object, but I need to validate the column and rows headers.

If I have validation errors in my column and row headers I need to combine the errors from these two validators together and return the errors as a Validated<T> object.

I am not sure if this would be the best approached to handle the validation, but it made sense for me. if you other ideias on how to tackle such a scenario, I would be more then happy to hear.

Thanks for the support as always.

Can you share a minimal reproducible project?

Here is the link with the code.

https://github.com/ffroliva/excel-validation

In your example, you just want to concatenate two Validated<List<Integer>>s (integerColumnHeaders.getHeaders() and integerRowHeaders.getHeaders()) into a Validated<List<Integer>>.
Is it correct?

I would write

	public Validated<Matrix> read() {
		Validated<List<Integer>> columnHeaders = new IntegerColumnHeaders(this.sheet).getHeaders();
		Validated<List<Integer>> rowHeaders = new IntegerRowHeaders(this.sheet).getHeaders();
		Validation<ConstraintViolation, Sheet> sheetValidation = Validations.combine(columnHeaders, rowHeaders).apply((c, r) -> this.sheet);
		return Validated.of(sheetValidation.flatMap(sheet -> {
			short numOfColumns = sheet.getRow(0).getLastCellNum();
			int numOfRows = sheet.getLastRowNum();
			final double[][] data = new double[numOfRows][numOfColumns];
			ConstraintViolations constraintViolations = new ConstraintViolations();
			for (int rIndex = 1; numOfRows > rIndex; rIndex++) {
				for (int cIndex = 1; numOfColumns > cIndex; cIndex++) {
					Cell cell = CellUtil.getCell(sheet.getRow(rIndex), cIndex); //CellUtil#getCell creates a cell it it doesn't exist
					final Validated<Double> cellValidated = CellValidator.NUMERIC_CELL_TYPE_VALIDATOR.validate(cell);
					if (cellValidated.isValid()) {
						data[rIndex - 1][cIndex - 1] = sheet.getRow(rIndex).getCell(cIndex).getNumericCellValue();
					}
					else {
						constraintViolations.addAll(cellValidated.errors());
					}
				}
			}
			if (constraintViolations.isValid()) {
				return Validation.success(new Matrix(data));
			}
			else {
				return Validation.failure(constraintViolations);
			}
		}));
	}

or

	final ValueValidator<Sheet, Matrix> sheetValidator = (sheet, locale, constraintContext) -> {
		short numOfColumns = sheet.getRow(0).getLastCellNum();
		int numOfRows = sheet.getLastRowNum();
		final double[][] data = new double[numOfRows][numOfColumns];
		ConstraintViolations constraintViolations = new ConstraintViolations();
		for (int rIndex = 1; numOfRows > rIndex; rIndex++) {
			for (int cIndex = 1; numOfColumns > cIndex; cIndex++) {
				Cell cell = CellUtil.getCell(sheet.getRow(rIndex), cIndex); //CellUtil#getCell creates a cell it it doesn't exist
				final Validated<Double> cellValidated = CellValidator.NUMERIC_CELL_TYPE_VALIDATOR.validate(cell);
				if (cellValidated.isValid()) {
					data[rIndex - 1][cIndex - 1] = sheet.getRow(rIndex).getCell(cIndex).getNumericCellValue();
				}
				else {
					constraintViolations.addAll(cellValidated.errors());
				}
			}
		}
		if (constraintViolations.isValid()) {
			return Validated.of(Validation.success(new Matrix(data)));
		}
		else {
			return Validated.of(Validation.failure(constraintViolations));
		}
	};

	public Validated<Matrix> read() {
		Validated<List<Integer>> columnHeaders = new IntegerColumnHeaders(this.sheet).getHeaders();
		Validated<List<Integer>> rowHeaders = new IntegerRowHeaders(this.sheet).getHeaders();
		Validation<ConstraintViolation, Sheet> sheetValidation = Validations.combine(columnHeaders, rowHeaders).apply((c, r) -> this.sheet);
		return sheetValidation.flatMap(sheetValidator::validate);
	}

In your example, you just want to concatenate two Validated<List<Integer>>s (integerColumnHeaders.getHeaders() and integerRowHeaders.getHeaders()) into a Validated<List<Integer>>. Is it correct?

The errors yes, but the values no.

All the errors are related to the sheet but the validations happen in the cell level.

Thank your view on this @making. You insight gave me ideas on how to proceed. 👍

BTW, when you combine the the two Validated<List> will the values also will be combined?

Let say that I have a Validator A input is List.of(1,2,3) and Validator B has the input List.of(4,5,6) by combining the validators the value will return a list with 1,2,3,4,5,6 ?

yes, you can as bellow

Validation<ConstraintViolation, List<Integer>> validation = Validations.combine(columnHeaders, rowHeaders)
        .apply((c, r) -> {
            List<Integer> list = new ArrayList<>();
            list.addAll(c);
            list.addAll(r);
            return list;
        });