SubCalcUtils.java 8.33 KB
package com.hotent.runtime.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.hotent.base.util.BeanUtils;
import com.hotent.base.util.JsonUtil;
import com.hotent.base.util.StringUtil;
import com.hotent.base.util.string.StringPool;

import java.math.BigDecimal;

/**
 * @author moka
 * */
public class SubCalcUtils {

    private final static String OP_EQUALS = "1";
    private final static String OP_NOT_EQUALS = "2";
    private final static String OP_GREAT_THAN = "3";
    private final static String OP_LESS_THAN = "4";
    private final static String OP_GREAT_EQUALS = "7";
    private final static String OP_LESS_EQUALS = "8";
    private final static String OP_CONTAINS = "9";
    private final static String OP_ISNULL = "11";
    private final static String OP_NOTNULL = "12";

    /**
     * 判断子表中某一行满足某个条件, 默认为false
     *
     * 若令条件为A,B,C为符合条件,包含则是A || B || C,即其中一个条件(如A)不满足,则直接返回true
     * */
    public static boolean subFieldContain(JsonNode subArray, String field, String op, Object value, String dataType) {
        //默认为false
        if(!(subArray instanceof ArrayNode)){
            return false;
        }
        ArrayNode arrayNode = (ArrayNode) subArray;
        if (arrayNode.isEmpty()) {
            return false;
        }
        for (JsonNode node : arrayNode) {
            ObjectNode row = (ObjectNode) node;
            boolean rowResult = SubCalcUtils.subRowCalc(row, field, op, value, dataType);
            if (rowResult) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断子表中是否全部不满足条件的
     *
     * 不包含正 等价于 全为反
     * 若令条件为A,B,C为符合条件,不包含则是!A and !B and !C,即其中一个条件(如!A)不满足,则直接返回false
     * */
    public static boolean subFieldNotContain(JsonNode subArray, String field, String op, Object value, String dateType) {
        if(!(subArray instanceof ArrayNode)){
            return false;
        }
        ArrayNode arrayNode = (ArrayNode) subArray;
        if (arrayNode.isEmpty()) {
            return false;
        }
        for (JsonNode node : arrayNode) {
            ObjectNode row = (ObjectNode) node;
            boolean rowResult = SubCalcUtils.subRowCalc(row, field, op, value, dateType);
            if (rowResult) {
                return false;
            }
        }
        return true;
    }

    private static boolean subRowCalc(ObjectNode row, String field, String op, Object value, String dateType) {
        switch (dateType) {
            case "string":
                return subRowStringCalc(row, field, op, BeanUtils.isEmpty(value) ? "" : value.toString());
            case "number":
                return subRowNumberCalc(row, field, op, BeanUtils.isEmpty(value) ? BigDecimal.ZERO : value);
            case "date":
                return subRowDateCalc(row, field, op, BeanUtils.isEmpty(value) ? "" : value.toString());
            default:
                throw new IllegalArgumentException("unknown date type");
        }
    }

    /**
     * 1: ==
     * 2: !=
     * 3: >
     * 4: <
     * 7: >=
     * 8: <=
     * 9: belong to(value split by comma and length is 2)
     * */
    private static boolean subRowDateCalc(ObjectNode row, String field, String op, String value) {
        String dateValue = JsonUtil.getString(row, field, StringPool.EMPTY);
        if (OP_ISNULL.equals(op)){
            return BeanUtils.isEmpty(dateValue);
        }else if (OP_NOTNULL.equals(op)){
            return BeanUtils.isNotEmpty(dateValue);
        }
        if (OP_CONTAINS.equals(op)) {
            return subRowDateRegionCalc(dateValue, value);
        }
        int diff = dateValue.compareTo(value);
        return getSubRowCalcResult(diff, op);
    }

    private static boolean subRowDateRegionCalc(String dateValue, String dateRegion) {
        if (StringUtil.isEmpty(dateRegion) || StringUtil.isEmpty(dateValue)) {
            return false;
        }
        String[] split = dateRegion.split(StringPool.COMMA);
        if (2 == split.length) {
            return (dateValue.compareTo(split[0]) >= 0 && dateValue.compareTo(split[1]) <= 0);
        }
        throw new IllegalArgumentException("illegal date argument, the date region must contains one comma");
    }

    /**
     * 1: ==
     * 2: !=
     * 3: >
     * 4: <
     * 7: >=
     * 8: <=
     * 9: belong to(value split by comma)
     * */
    private static boolean subRowNumberCalc(ObjectNode row, String field, String op, Object value) {
        JsonNode fieldNode = row.get(field);
        if (OP_ISNULL.equals(op)){
            return BeanUtils.isEmpty(fieldNode);
        }else if (OP_NOTNULL.equals(op)){
            return BeanUtils.isNotEmpty(fieldNode);
        }
        BigDecimal decimalValue;
        if (value instanceof BigDecimal) {
            decimalValue = ((BigDecimal) value);
        } else if (value instanceof Integer) {
            decimalValue = BigDecimal.valueOf((Integer) value);
        } else if (value instanceof Long) {
            decimalValue = BigDecimal.valueOf(((Long) value));
        } else if (value instanceof Double) {
            decimalValue = BigDecimal.valueOf(((Double) value));
        } else if (value instanceof String && OP_CONTAINS.equals(op)) {
            return calcNumberContains(value.toString(), row.get(field));
        } else {
            throw new IllegalArgumentException("unknown value type");
        }

        // numberValue 可能为 TextNode 则直接读取数据
        if (fieldNode instanceof TextNode ){
            int diff = new BigDecimal(fieldNode.asInt()).compareTo(decimalValue);
            return getSubRowCalcResult(diff, op);
        }

        // numberValue 可能为BigDecimal或Int
        BigDecimal curValue;
        try {
            curValue = fieldNode.decimalValue();
        } catch (Exception e) {
            curValue = BigDecimal.ZERO;
        }
        int diff = curValue.compareTo(decimalValue);
        return getSubRowCalcResult(diff, op);
    }

    private static boolean getSubRowCalcResult(int diff, String op) {
        switch (op) {
            case OP_EQUALS:
                return diff == 0;
            case OP_NOT_EQUALS:
                return diff != 0;
            case OP_GREAT_THAN:
                return diff > 0;
            case OP_LESS_THAN:
                return diff < 0;
            case OP_GREAT_EQUALS:
                return diff >= 0;
            case OP_LESS_EQUALS:
                return diff <= 0;
            default:
                throw new IllegalArgumentException("unknown operation type");
        }
    }

    private static boolean calcNumberContains(String valueStr, JsonNode node) {
        String[] split = valueStr.split(StringPool.COMMA);
        BigDecimal curValue;
        try {
            curValue = node.decimalValue();
        } catch (Exception e) {
            curValue = BigDecimal.ZERO;
        }
        for (String numberStr : split) {
            BigDecimal decimal = BigDecimal.valueOf(Long.parseLong(numberStr));
            if (curValue.compareTo(decimal) == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 1: ==
     * 2: !=
     * 9: contains(split by comma)
     * */
    private static boolean subRowStringCalc(ObjectNode row, String field, String op, String value) {
        String fieldValue = JsonUtil.getString(row, field, StringPool.EMPTY);
        switch (op) {
            case OP_EQUALS:
                return fieldValue.equals(value);
            case OP_NOT_EQUALS:
                return !fieldValue.equals(value);
            case OP_CONTAINS:
                String[] split = value.split(StringPool.COMMA);
                for (String s : split) {
                    if (fieldValue.equals(s)) {
                        return true;
                    }
                }
                return false;
            case OP_ISNULL:
                return StringUtil.isEmpty(fieldValue);
            case OP_NOTNULL:
                return StringUtil.isNotEmpty(fieldValue);
            default:
                throw new IllegalArgumentException("unknown operation type");
        }
    }

}