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

com.wl4g.infra.common.expression.aviator.ExpressionOperator Maven / Gradle / Ivy

There is a newer version: 3.1.72
Show newest version
/*
 *  Copyright (C) 2023 ~ 2035 the original authors WL4G (James Wong).
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package com.wl4g.infra.common.expression.aviator;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;

import static com.wl4g.infra.common.collection.CollectionUtils2.safeList;
import static com.wl4g.infra.common.lang.Assert2.hasTextOf;
import static com.wl4g.infra.common.lang.Assert2.notNullOf;

/**
 * The {@link ExpressionOperator}
 *
 * @author James Wong
 * @since v3.0
 **/
@Schema(oneOf = {ExpressionOperator.LogicalOperator.class, ExpressionOperator.RelationOperator.class}, discriminatorProperty = "type")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
@JsonSubTypes({@JsonSubTypes.Type(value = ExpressionOperator.LogicalOperator.class, name = "LOGICAL"),
        @JsonSubTypes.Type(value = ExpressionOperator.RelationOperator.class, name = "RELATION")})
@Getter
@Setter
@SuperBuilder
@ToString(callSuper = true)
@NoArgsConstructor
public abstract class ExpressionOperator implements Function {
    private @NotBlank String name;
    @Schema(name = "type", implementation = OperatorType.class)
    @JsonProperty(value = "type", access = JsonProperty.Access.WRITE_ONLY)
    private @NotBlank String type;

    public void validate() {
        hasTextOf(name, "name");
        OperatorType.of(type);
    }

    @Getter
    @AllArgsConstructor
    public enum OperatorType {

        LOGICAL(LogicalOperator.class),

        RELATION(RelationOperator.class);

        private final Class clazz;

        @JsonCreator
        public static OperatorType of(String type) {
            for (OperatorType a : OperatorType.values()) {
                if (a.name().equalsIgnoreCase(type)) {
                    return a;
                }
            }
            throw new IllegalArgumentException(String.format("Invalid node type for '%s'", type));
        }
    }

    @Getter
    @Setter
    @SuperBuilder
    @ToString(callSuper = true)
    @NoArgsConstructor
    public static class LogicalOperator extends ExpressionOperator {
        private @NotNull LogicalType logical;
        private @NotEmpty List subConditions;

        @Override
        public Boolean apply(JsonNode record) {
            validate();
            switch (logical) {
                case AND:
                    return safeList(subConditions).stream().allMatch(sub -> sub.apply(record));
                case OR:
                    return safeList(subConditions).stream().anyMatch(sub -> sub.apply(record));
                case NOT:
                    return safeList(subConditions).stream().noneMatch(sub -> sub.apply(record));
                default:
                    throw new Error(String.format("Unsupported logical type '%s'", logical));
            }
        }

        @Override
        public void validate() {
            super.validate();
            notNullOf(logical, "logical");
            safeList(subConditions).forEach(ExpressionOperator::validate);
        }
    }

    @Getter
    @AllArgsConstructor
    public enum LogicalType {
        AND((subFilters, record) -> safeList(subFilters).stream().allMatch(sub -> sub.apply(record))),

        OR((subFilters, record) -> safeList(subFilters).stream().anyMatch(sub -> sub.apply(record))),

        NOT((subFilters, record) -> safeList(subFilters).stream().noneMatch(sub -> sub.apply(record)));

        private final BiFunction, JsonNode, Boolean> fn;
    }

    @Getter
    @Setter
    @SuperBuilder
    @ToString(callSuper = true)
    @NoArgsConstructor
    public static class RelationOperator extends ExpressionOperator {
        private @NotNull AviatorFunction fn;

        @Override
        public Boolean apply(JsonNode record) {
            validate();
            return fn.apply(record);
        }

        @Override
        public void validate() {
            super.validate();
            notNullOf(fn, "aviatorFunction");
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy