com.sonicle.webtop.core.app.sdk.BaseJOOQVisitor.java Source code

Java tutorial

Introduction

Here is the source code for com.sonicle.webtop.core.app.sdk.BaseJOOQVisitor.java

Source

/*
 * Copyright (C) 2019 Sonicle S.r.l.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY SONICLE, SONICLE DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Sonicle S.r.l. at email address sonicle[at]sonicle[dot]com
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * Sonicle logo and Sonicle copyright notice. If the display of the logo is not
 * reasonably feasible for technical reasons, the Appropriate Legal Notices must
 * display the words "Copyright (C) 2019 Sonicle S.r.l.".
 */
package com.sonicle.webtop.core.app.sdk;

import com.github.rutledgepaulv.qbuilders.nodes.AndNode;
import com.github.rutledgepaulv.qbuilders.nodes.ComparisonNode;
import com.github.rutledgepaulv.qbuilders.nodes.OrNode;
import com.github.rutledgepaulv.qbuilders.operators.ComparisonOperator;
import com.github.rutledgepaulv.qbuilders.visitors.AbstractVoidContextNodeVisitor;
import com.sonicle.commons.time.DateTimeUtils;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.impl.DSL;

/**
 *
 * @author malbinola
 */
public abstract class BaseJOOQVisitor extends AbstractVoidContextNodeVisitor<Condition> {
    protected final Function<Object, Object> normalizer;
    protected final boolean ignoreCase;

    public BaseJOOQVisitor() {
        this(new DefaultNormalizer(), false);
    }

    public BaseJOOQVisitor(Function<Object, Object> normalizer) {
        this(normalizer, false);
    }

    public BaseJOOQVisitor(boolean ignoreCase) {
        this(new DefaultNormalizer(), ignoreCase);
    }

    public BaseJOOQVisitor(Function<Object, Object> normalizer, boolean ignoreCase) {
        this.normalizer = normalizer;
        this.ignoreCase = ignoreCase;
    }

    abstract protected Condition toCondition(String fieldName, ComparisonOperator operator, Collection<?> values,
            ComparisonNode node);

    @Override
    protected Condition visit(AndNode node) {
        //Condition condition = DSL.and(conditions); in jOOQ 3.6+
        Condition result = DSL.trueCondition();
        List<Condition> conditions = node.getChildren().stream().map(this::visitAny).collect(Collectors.toList());
        for (Condition condition : conditions) {
            result = result.and(condition);
        }
        return result;
    }

    @Override
    protected Condition visit(OrNode node) {
        //Condition condition = DSL.and(conditions); in jOOQ 3.6+
        Condition result = DSL.trueCondition();
        List<Condition> conditions = node.getChildren().stream().map(this::visitAny).collect(Collectors.toList());
        for (Condition condition : conditions) {
            result = result.or(condition);
        }
        return result;
    }

    @Override
    protected Condition visit(ComparisonNode node) {
        String fieldName = node.getField().asKey();
        ComparisonOperator operator = node.getOperator();
        Collection<?> values = node.getValues().stream().map(normalizer).collect(Collectors.toList());
        return toCondition(fieldName, operator, values, node);
    }

    protected <T> Condition defaultCondition(Field<T> field, ComparisonOperator operator, Collection<?> values) {
        if (ComparisonOperator.EQ.equals(operator)) {
            if (hasStringType(field)) {
                String value = (String) single(values);
                if (valueContainsWildcard(value)) {
                    return ignoreCase ? field.likeIgnoreCase(valueToLikePattern(value))
                            : field.like(valueToLikePattern(value));
                } else if (ignoreCase) {
                    return field.equalIgnoreCase(value);
                }

            } else if (hasBooleanType(field)) {
                String value = (String) single(values);
                return Boolean.parseBoolean(value) ? field.isTrue() : field.isFalse();
            }
            return field.equal(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.NE.equals(operator)) {
            if (hasStringType(field)) {
                String value = (String) single(values);
                if (valueContainsWildcard(value)) {
                    return ignoreCase ? field.notLikeIgnoreCase(valueToLikePattern(value))
                            : field.notLike(valueToLikePattern(value));
                } else if (ignoreCase) {
                    return field.notEqualIgnoreCase(value);
                }

            } else if (hasBooleanType(field)) {
                String value = (String) single(values);
                return Boolean.parseBoolean(value) ? field.isFalse() : field.isTrue();
            }
            return field.notEqual(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.EX.equals(operator)) {
            throw new UnsupportedOperationException("Operator not supported: " + operator);

        } else if (ComparisonOperator.GT.equals(operator)) {
            return field.greaterThan(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.LT.equals(operator)) {
            return field.lessThan(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.GTE.equals(operator)) {
            return field.greaterOrEqual(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.LTE.equals(operator)) {
            return field.lessOrEqual(field.getDataType().convert(single(values)));

        } else if (ComparisonOperator.IN.equals(operator)) {
            return field.in(field.getDataType().convert(values));

        } else if (ComparisonOperator.NIN.equals(operator)) {
            return field.notIn(field.getDataType().convert(values));

        } else if (ComparisonOperator.RE.equals(operator)) {
            return field.likeRegex((String) single(values));

        } else if (ComparisonOperator.SUB_CONDITION_ANY.equals(operator)) {
            throw new UnsupportedOperationException("Operator not supported: " + operator);

        } else {
            throw new UnsupportedOperationException("Operator not supported: " + operator);
        }
    }

    protected boolean hasStringType(Field<?> field) {
        return field.getType().equals(java.lang.String.class);
    }

    protected boolean hasBooleanType(Field<?> field) {
        return field.getType().equals(java.lang.Boolean.class);
    }

    protected String singleAsString(Collection<?> values) {
        return (String) single(values);
    }

    protected String valueToSmartLikePattern(String value) {
        if (valueContainsWildcard(value)) {
            return valueToLikePattern(value);
        } else {
            return valueToLikePattern("*" + value + "*");
        }
    }

    protected boolean valueContainsWildcard(String value) {
        int escapedAsterisks = StringUtils.countMatches(value, "\\*");
        int asterisks = StringUtils.countMatches(value, "*");
        return asterisks > escapedAsterisks;
    }

    protected String valueToLikePattern(String value) {
        value = StringUtils.replace(value, "*", "%");
        value = StringUtils.replace(value, "\\*", "*");
        return value;
    }

    protected static class DefaultNormalizer implements Function<Object, Object> {

        @Override
        public Object apply(Object o) {
            if (o instanceof java.time.Instant) {
                return DateTimeUtils
                        .toDateTime(DateTimeUtils.toZonedDateTime((java.time.Instant) o, java.time.ZoneOffset.UTC));
            }
            return o;
        }
    }
}