All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jsonvalues.spec.JsTupleSpec Maven / Gradle / Ivy

package jsonvalues.spec;

import com.dslplatform.json.parsers.JsSpecParser;
import com.dslplatform.json.parsers.JsSpecParsers;
import io.vavr.collection.Vector;
import jsonvalues.JsArray;
import jsonvalues.JsPath;
import jsonvalues.JsValue;

import java.util.HashSet;
import java.util.Set;

import static jsonvalues.spec.ERROR_CODE.ARRAY_EXPECTED;
import static jsonvalues.spec.ERROR_CODE.SPEC_MISSING;

/**
 Represents a specification of every element of a Json array. It allows to define
 tuples and the schema of every of its elements.
 */
public class JsTupleSpec implements JsArraySpec {

    private final boolean required;
    private final boolean nullable;
    private final Vector specs;
    private final boolean strict = true;

    private JsTupleSpec(final Vector specs) {
        this(specs,
             true,
             false
            );
    }
    private JsTupleSpec(final Vector specs,
                        boolean required,
                        boolean nullable
                       ) {
        this.specs = specs;
        this.required = required;
        this.nullable = nullable;
    }

    static JsTupleSpec of(JsSpec spec,
                          JsSpec... others
                         ) {
        Vector specs = Vector.empty();
        specs = specs.append(spec);
        for (JsSpec s : others) specs = specs.append(s);
        return new JsTupleSpec(specs);
    }

    @Override
    public boolean isRequired() {
        return required;
    }

    @Override
    public JsTupleSpec nullable() {
        return new JsTupleSpec(specs,
                               required,
                               true
        );
    }

    @Override
    public JsTupleSpec optional() {
        return new JsTupleSpec(specs,
                               false,
                               nullable
        );
    }

    @Override
    public JsSpecParser parser() {

        Vector parsers = Vector.empty();
        for (final JsSpec spec : specs) {
            parsers = parsers.append(spec.parser());
        }
        return JsSpecParsers.INSTANCE.ofArraySpec(parsers,
                                                  nullable
                                                 );
    }

    @Override
    public Set test(final JsPath parentPath,
                                 final JsValue value
                                ) {
        return test(JsPath.empty()
                          .append(JsPath.fromIndex(-1)),
                    this,
                    new HashSet<>(),
                    value
                   );
    }

    public Set test(final JsArray array) {
        return test(JsPath.empty(),
                    array);
    }

    private Set test(final JsPath parent,
                                  final JsTupleSpec tupleSpec,
                                  final Set errors,
                                  final JsValue value
                                 ) {
        if (value.isNull() && nullable) return errors;

        if (!value.isArray()) {
            errors.add(JsErrorPair.of(parent,
                                      new Error(value,
                                                ARRAY_EXPECTED)));
            return errors;
        }
        JsArray              array     = value.toJsArray();
        final Vector specs     = tupleSpec.specs;
        final int            specsSize = tupleSpec.specs.size();
        if (specsSize > 0 && array.size() > specsSize && tupleSpec.strict) {
            errors.add(JsErrorPair.of(parent.tail()
                                            .index(specsSize),
                                      new Error(array.get(specsSize),
                                                SPEC_MISSING
                                      )
                                     )
                      );
            return errors;
        }
        JsPath currentPath = parent;

        for (int i = 0; i < specsSize; i++) {
            currentPath = currentPath.inc();
            final JsSpec spec = specs.get(i);
            errors.addAll(spec.test(currentPath,
                                    array.get(i)));
        }
        return errors;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy