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

x7.core.bean.CriteriaBuilder Maven / Gradle / Ivy

There is a newer version: 2.2.7.RELEASE
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 x7.core.bean;

import x7.core.bean.Criteria.ResultMappedCriteria;
import x7.core.bean.Criteria.X;
import x7.core.util.BeanMapUtil;
import x7.core.util.BeanUtilX;
import x7.core.util.NumberUtil;
import x7.core.util.StringUtil;
import x7.core.web.Direction;
import x7.core.web.Fetched;
import x7.core.web.MapResult;
import x7.core.web.Paged;

import java.util.*;
import java.util.Map.Entry;

/**
 * Standard Query Builder
 *
 * @author Sim
 */
public class CriteriaBuilder {

    private Criteria criteria;
    private CriteriaBuilder instance;


    public PageBuilder paged() {
        return this.pageBuilder;
    }

    public void paged(Paged paged) {
        criteria.paged(paged);
        DataPermission.Chain.onBuild(criteria, paged);
    }

    public ConditionBuilder and() {

        X x = new X();
        x.setConjunction(Conjunction.AND);
        x.setValue(Conjunction.AND);

        X current = conditionBuilder.getX();
        if (current != null) {
            X parent = current.getParent();
            if (parent != null) {
                List subList = parent.getSubList();
                if (subList != null) {
                    subList.add(x);
                    x.setParent(parent);
                }
            } else {
                this.criteria.add(x);
            }
        } else {
            this.criteria.add(x);
        }

        conditionBuilder.under(x);

        return conditionBuilder;
    }

    public ConditionBuilder or() {

        X x = new X();
        x.setConjunction(Conjunction.OR);
        x.setValue(Conjunction.OR);

        X current = conditionBuilder.getX();
        if (current != null) {
            X parent = current.getParent();
            if (parent != null) {
                List subList = parent.getSubList();
                if (subList != null) {
                    subList.add(x);
                    x.setParent(parent);
                }
            } else {
                this.criteria.add(x);
            }
        } else {
            this.criteria.add(x);
        }

        conditionBuilder.under(x);

        return conditionBuilder;
    }

    public CriteriaBuilder endSub() {

        X x = new X();
        x.setPredicate(Predicate.SUB_END);
        x.setValue(Predicate.SUB_END);

        X current = conditionBuilder.getX();
        X parent = current.getParent();
        if (parent != null) {
            List subList = parent.getSubList();
            if (subList != null) {
                subList.add(x);
            }

            this.conditionBuilder.under(parent);
        }

        return instance;
    }

    private PageBuilder pageBuilder = new PageBuilder() {

        @Override
        public PageBuilder scroll(boolean isScroll) {
            criteria.setScroll(isScroll);
            return this;
        }

        @Override
        public PageBuilder rows(int rows) {
            criteria.setRows(rows);
            return this;
        }

        @Override
        public PageBuilder page(int page) {
            criteria.setPage(page);
            return this;
        }

        @Override
        public PageBuilder orderIn(String porperty, List inList) {
            if (Objects.nonNull(inList) && inList.size() > 0) {
                KV kv = new KV(porperty, inList);
                criteria.getFixedSortList().add(kv);
            }
            return this;
        }


        @Override
        public PageBuilder sort(String orderBy, Direction direction) {
            if (StringUtil.isNullOrEmpty(orderBy))
                return this;
            List sortList = criteria.getSortList();
            if (sortList == null){
                sortList = new ArrayList<>();
                criteria.setSortList(sortList);
            }
            Sort sort = new Sort(orderBy,direction);
            sortList.add(sort);
            return this;
        }
    };

    private ConditionBuilder conditionBuilder = new ConditionBuilder() {

        private X x = null;

        @Override
        public X getX() {
            return x;
        }

        @Override
        public void under(X x) {
            this.x = x;
        }

        @Override
        public CriteriaBuilder eq(String property, Object value) {

            if (value == null)
                return instance;
            if (Objects.nonNull(criteria.getParsed())) {
                if (isBaseType_0(property, value))
                    return instance;
            }
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.EQ);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder lt(String property, Object value) {

            if (value == null)
                return instance;
            if (isBaseType_0(property, value))
                return instance;
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.LT);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder lte(String property, Object value) {

            if (value == null)
                return instance;

            if (isBaseType_0(property, value))
                return instance;
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.LTE);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder gt(String property, Object value) {

            if (value == null)
                return instance;
            if (isBaseType_0(property, value))
                return instance;
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.GT);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder gte(String property, Object value) {

            if (value == null)
                return instance;

            if (isBaseType_0(property, value))
                return instance;
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.GTE);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder ne(String property, Object value) {

            if (value == null)
                return instance;

            if (isBaseType_0(property, value))
                return instance;
            if (isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.NE);
            x.setKey(property);
            x.setValue(value);

            return instance;
        }

        @Override
        public CriteriaBuilder like(String property, String value) {

            if (StringUtil.isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.LIKE);
            x.setKey(property);
            x.setValue(SqlScript.LIKE_HOLDER + value + SqlScript.LIKE_HOLDER);

            return instance;
        }

        @Override
        public CriteriaBuilder likeRight(String property, String value) {

            if (StringUtil.isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.LIKE);
            x.setKey(property);
            x.setValue(value + SqlScript.LIKE_HOLDER);

            return instance;
        }

        @Override
        public CriteriaBuilder notLike(String property, String value) {

            if (StringUtil.isNullOrEmpty(value))
                return instance;

            x.setPredicate(Predicate.NOT_LIKE);
            x.setKey(property);
            x.setValue(SqlScript.LIKE_HOLDER + value + SqlScript.LIKE_HOLDER);

            return instance;
        }

        @Override
        public CriteriaBuilder between(String property, Object min, Object max) {

            if (min == null || max == null)
                return instance;

            if (isBaseType_0(property, max))
                return instance;
            if (isNullOrEmpty(max))
                return instance;
            if (isNullOrEmpty(min))
                return instance;

            MinMax minMax = new MinMax();
            minMax.setMin(min);
            minMax.setMax(max);

            x.setPredicate(Predicate.BETWEEN);
            x.setKey(property);
            x.setValue(minMax);

            return instance;
        }

        @Override
        public CriteriaBuilder in(String property, List list) {

            if (list == null || list.isEmpty())
                return instance;

            List tempList = new ArrayList();
            for (Object obj : list) {
                if (Objects.isNull(obj))
                    continue;
                if (!tempList.contains(obj)) {
                    tempList.add(obj);
                }
            }

            if (tempList.isEmpty())
                return instance;

            if (tempList.size() == 1) {
                return eq(property, tempList.get(0));
            }

            x.setPredicate(Predicate.IN);
            x.setKey(property);
            x.setValue(tempList);

            return instance;
        }

        @Override
        public CriteriaBuilder nin(String property, List list) {

            if (list == null || list.isEmpty())
                return instance;

            List tempList = new ArrayList();
            for (Object obj : list) {
                if (Objects.isNull(obj))
                    continue;
                if (!tempList.contains(obj)) {
                    tempList.add(obj);
                }
            }

            if (tempList.isEmpty())
                return instance;

            if (tempList.size() == 1) {
                return ne(property, tempList.get(0));
            }

            x.setPredicate(Predicate.NOT_IN);
            x.setKey(property);
            x.setValue(tempList);

            return instance;
        }

        @Override
        public CriteriaBuilder nonNull(String property) {

            if (StringUtil.isNullOrEmpty(property))
                return instance;

            x.setPredicate(Predicate.IS_NOT_NULL);
            x.setValue(property);

            return instance;
        }

        @Override
        public CriteriaBuilder isNull(String property) {

            if (StringUtil.isNullOrEmpty(property))
                return instance;

            x.setPredicate(Predicate.IS_NULL);
            x.setValue(property);

            return instance;
        }

        @Override
        public CriteriaBuilder x(String sql) {

            if (StringUtil.isNullOrEmpty(sql))
                return instance;

            sql = BeanUtilX.normalizeSql(sql);

            x.setPredicate(Predicate.X);
            x.setValue(sql);

            return instance;
        }

        @Override
        public ConditionBuilder beginSub() {

            x.setKey(Predicate.SUB.sql());// special treat FIXME
            x.setValue(Predicate.SUB);

            List subList = new ArrayList<>();
            x.setSubList(subList);

            X from = new X();
            from.setPredicate(Predicate.SUB_BEGIN);
            from.setValue(Predicate.SUB_BEGIN);

            subList.add(from);

            X xx = new X();//?
            subList.add(xx);//?
            xx.setParent(x);
            conditionBuilder.under(xx);

            return conditionBuilder;
        }

    };

    private CriteriaBuilder() {
        this.instance = this;
    }

    private CriteriaBuilder(Criteria criteria) {
        this.criteria = criteria;
        this.instance = this;
    }

    public static CriteriaBuilder buildCondition() {
        Criteria criteria = new Criteria();
        CriteriaBuilder builder = new CriteriaBuilder(criteria);
        return builder;
    }

    public static CriteriaBuilder build(Class clz) {
        Criteria criteria = new Criteria();
        criteria.setClz(clz);
        CriteriaBuilder builder = new CriteriaBuilder(criteria);

        if (criteria.getParsed() == null) {
            Parsed parsed = Parser.get(clz);
            criteria.setParsed(parsed);
        }

        return builder;
    }

    public static CriteriaBuilder build(Class clz, Paged paged) {
        Criteria criteria = new Criteria();
        criteria.setClz(clz);
        CriteriaBuilder builder = new CriteriaBuilder(criteria);

        if (criteria.getParsed() == null) {
            Parsed parsed = Parser.get(clz);
            criteria.setParsed(parsed);
        }

        if (paged != null) {
            builder.paged(paged);
        }

        return builder;
    }


    public static ResultMappedBuilder buildResultMapped(Class clz, Fetched ro) {
        CriteriaBuilder b = new CriteriaBuilder();
        ResultMappedBuilder builder = b.new ResultMappedBuilder(clz);

        if (ro != null) {

            builder.xAddResultKey(ro);

            if (ro instanceof Paged) {
                builder.paged((Paged) ro);
            }

        }

        return builder;
    }

    public static ResultMappedBuilder buildResultMapped(Class clz, MapResult ro) {
        CriteriaBuilder b = new CriteriaBuilder();
        ResultMappedBuilder builder = b.new ResultMappedBuilder(clz);

        if (ro != null) {

            builder.xAddResultKey(ro);

            if (ro instanceof Paged) {
                builder.paged((Paged) ro);
            }

        }

        return builder;
    }

    public static ResultMappedBuilder buildResultMapped(Class clz) {
        CriteriaBuilder b = new CriteriaBuilder();
        ResultMappedBuilder builder = b.new ResultMappedBuilder(clz);

        return builder;
    }

    public static DomainObjectBuilder buildDomainObject(Class mainClz, Class withClz) {
        CriteriaBuilder b = new CriteriaBuilder();
        DomainObjectBuilder builder = b.new DomainObjectBuilder(mainClz, withClz);

        return builder;
    }


    public Class getClz() {
        return this.criteria.getClz();
    }


    private BeanElement getBeanElement(String property) {

        String str = null;
        if (property.contains(SqlScript.SPACE)) {
            String[] arr = property.split(SqlScript.SPACE);
            str = arr[0];
        } else {
            str = property;
        }
        if (str.contains(SqlScript.POINT)) {
            String[] xxx = str.split("\\.");
            if (xxx.length == 1)
                property = xxx[0];
            else
                property = xxx[1];
        } else {
            property = str;
        }

        BeanElement be = criteria.getParsed().getElement(property);

        return be;

    }

    private boolean isBaseType_0(String property, Object v) {

        if (v instanceof String)
            return false;

        BeanElement be = getBeanElement(property);

        if (be == null) {

            String s = v.toString();
            boolean isNumeric = NumberUtil.isNumeric(s);
            if (isNumeric) {

                if (s.contains(SqlScript.POINT)) {
                    return Double.valueOf(s) == 0;
                }
                return Long.valueOf(s) == 0;
            }
            return false;
        }

        Class vType = be.clz;

        String s = v.toString();

        if (vType == int.class) {
            if (s.contains(SqlScript.POINT)) {
                s = s.substring(0, s.indexOf(SqlScript.POINT));
            }
            return Integer.valueOf(s) == 0;
        }
        if (vType == long.class) {
            if (s.contains(SqlScript.POINT)) {
                s = s.substring(0, s.indexOf(SqlScript.POINT));
            }
            return Long.valueOf(s) == 0;
        }
        if (vType == float.class) {
            return Float.valueOf(s) == 0;
        }
        if (vType == double.class) {
            return Double.valueOf(s) == 0;
        }
        if (vType == short.class) {
            return Short.valueOf(s) == 0;
        }
        if (vType == byte.class) {
            return Byte.valueOf(s) == 0;
        }
        if (vType == boolean.class) {
            if (s.contains(SqlScript.POINT)) {
                s = s.substring(0, s.indexOf(SqlScript.POINT));
            }
            return Integer.valueOf(s) == 0;
        }

        return false;
    }

    private boolean isNullOrEmpty(Object v) {

        Class vType = v.getClass();

        if (vType == String.class) {
            return StringUtil.isNullOrEmpty(v.toString());
        }

        return false;
    }

    public interface ConditionBuilder {

        CriteriaBuilder eq(String property, Object value);

        CriteriaBuilder lt(String property, Object value);

        CriteriaBuilder lte(String property, Object value);

        CriteriaBuilder gt(String property, Object value);

        CriteriaBuilder gte(String property, Object value);

        CriteriaBuilder ne(String property, Object value);

        CriteriaBuilder like(String property, String value);

        CriteriaBuilder likeRight(String property, String value);

        CriteriaBuilder notLike(String property, String value);

        CriteriaBuilder between(String property, Object min, Object max);

        CriteriaBuilder in(String property, List list);

        CriteriaBuilder nin(String property, List list);

        CriteriaBuilder nonNull(String property);

        CriteriaBuilder isNull(String property);

        CriteriaBuilder x(String sql);

        void under(X x);

        X getX();

        ConditionBuilder beginSub();

    }

    public Criteria get() {
        DataPermission.Chain.befroeGetCriteria(this, this.criteria);
        Iterator ite = this.criteria.getListX().iterator();
        while (ite.hasNext()) {
            X x = ite.next();
            if (Objects.isNull(x.getConjunction()) && Objects.isNull(x.getPredicate()) && Objects.isNull(x.getKey()))
                ite.remove();
        }
        return this.criteria;
    }


    public class ResultMappedBuilder extends CriteriaBuilder {


        @Override
        public Criteria.ResultMappedCriteria get() {
            return (ResultMappedCriteria) super.get();
        }

        private void init() {
            super.instance = this;
            Criteria c = new Criteria();
            Criteria.ResultMappedCriteria resultMapped = c.new ResultMappedCriteria();
            super.criteria = resultMapped;
        }

        private void init(Class clz) {
            ResultMappedCriteria f = (Criteria.ResultMappedCriteria) super.criteria;
            f.setClz(clz);
            Parsed parsed = Parser.get(clz);
            f.setParsed(parsed);
        }

        public ResultMappedBuilder(Class clz) {
            init();
            init(clz);
        }


        private void xAddResultKey(List xExpressionList) {
            for (String xExpression : xExpressionList) {
                get().getResultKeyList().add(xExpression);
            }
        }

        private void xAddResultKey(Fetched fetchResult) {
            if (fetchResult == null)
                return;
            Map resultObjMap = fetchResult.getResultKeyMap();
            if (resultObjMap == null || resultObjMap.isEmpty())
                return;
            List xExpressionList = BeanMapUtil.toStringKeyList(resultObjMap);
            xAddResultKey(xExpressionList);
        }

        private void xAddResultKey(MapResult mappedKey) {
            if (mappedKey == null)
                return;
            String[] arr = mappedKey.getResultKeys();
            if (arr == null || arr.length == 0)
                return;
            List list = Arrays.asList(arr);
            xAddResultKey(list);
        }

        public ResultMappedBuilder resultKey(String resultKey) {
            get().getResultKeyList().add(resultKey);
            return this;
        }

        @Override
        public void paged(Paged paged) {
            super.criteria.paged(paged);
            DataPermission.Chain.onBuild(super.criteria, paged);
        }

        public ResultMappedBuilder distinct(Object... objs) {
            if (objs == null)
                throw new RuntimeException("distinct non resultKey");
            ResultMappedCriteria resultMapped = get();
            Distinct distinct = resultMapped.getDistinct();
            if (Objects.isNull(distinct)) {
                distinct = new Distinct();
                resultMapped.setDistinct(distinct);
            }
            for (Object obj : objs) {
                if (obj instanceof String) {
                    distinct.add(obj.toString());
                } else if (obj instanceof Map) {
                    Map map = (Map) obj;
                    Set set = map.entrySet();
                    for (Entry entry : set) {
                        Object key = entry.getKey();
                        Object value = entry.getValue();
                        if (value instanceof Map) {
                            Map vMap = (Map) value;
                            for (Object k : vMap.keySet()) {
                                distinct.add(key.toString() + SqlScript.POINT + k.toString());
                            }
                        }
                    }

                } else {
                    throw new RuntimeException("distinct param suggests String, or Map");
                }
            }
            return this;
        }

        public ResultMappedBuilder groupBy(String property) {
            get().setGroupBy(property);
            return this;
        }


        public ResultMappedBuilder reduce(Reduce.ReduceType type, String property) {
            Reduce reduce = new Reduce();
            reduce.setType(type);
            reduce.setProperty(property);
            get().getReduceList().add(reduce);
            return this;
        }

    }


    public class DomainObjectBuilder extends CriteriaBuilder {

        @Override
        public Criteria.DomainObjectCriteria get() {
            return (Criteria.DomainObjectCriteria) super.get();
        }

        private void init() {
            super.instance = this;
            Criteria c = new Criteria();
            Criteria.DomainObjectCriteria domainObjectCriteria = c.new DomainObjectCriteria();
            super.criteria = domainObjectCriteria;
        }

        private void init(Class mainClz, Class withClz) {
            Criteria.DomainObjectCriteria doc = (Criteria.DomainObjectCriteria) super.criteria;
            doc.setClz(mainClz);
            doc.setWithClz(withClz);
            Parsed parsed = Parser.get(mainClz);
            doc.setParsed(parsed);
        }


        public DomainObjectBuilder(Class mainClz, Class withClz) {
            init();
            init(mainClz, withClz);
        }

        public DomainBuilder domain() {
            return this.domainBuilder;
        }

        private DomainBuilder domainBuilder = new DomainBuilder() {
            @Override
            public DomainBuilder known(List mainIdList) {
                get().setKnownMainIdList(mainIdList);
                return this;
            }

            @Override
            public DomainBuilder relative(Class relativeClz) {
                get().setRelativeClz(relativeClz);
                return this;
            }

            @Override
            public DomainBuilder on(String mainProperty) {
                get().setMainPropperty(mainProperty);
                return this;
            }

            @Override
            public CriteriaBuilder with(String withProperty) {
                get().setWithProperty(withProperty);
                return instance;
            }
        };


    }

}