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

org.fryske_akademy.ejb.Param Maven / Gradle / Ivy

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.fryske_akademy.ejb;

/*-
 * #%L
 * ejbCrudApi
 * %%
 * Copyright (C) 2018 Fryske Akademy
 * %%
 * 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.
 * #L%
 */
import java.util.ArrayList;
import java.util.List;

/**
 * Holder for parameter info that can be used when {@link JpqlBuilder building}
 * a jpql query, adds spaces where needed. Uses {@link Builder#Builder() } with syntax support by default.
 *
 * @author eduard
 */
public class Param  {
    
    /**
     * call {@link #one(java.lang.String, java.lang.Object, boolean, org.fryske_akademy.ejb.Param.Builder.WildcardMapping)  } with true and
     * {@link Builder#DEFAULT_MAPPING}
     * @param key
     * @param value
     * @return 
     */
    public static List one(String key, Object value) {
        return one(key, value, true, Builder.DEFAULT_MAPPING);
    }

    public static List one(String key, Object value, boolean syntaxSupport, Builder.WildcardMapping wildcardMapping) {
        return new Builder(syntaxSupport,wildcardMapping).add(key, value).build();
    }
    
    public enum AndOr {
        AND, OR;
        
        private static AndOr fromBool(boolean or) {
            return or ? OR : AND;
        }
        
        @Override
        public String toString() {
            return " " + name() + " ";
        }
        
    }
    
    private final String propertyPath;
    private final String paramKey;
    private final String operator;
    private final Object paramValue;
    private final String not;
    private final AndOr andOr;
    private final boolean skipSetValue;
    private final Class paramType;

    /**
     * Bottleneck constructor
     *
     * @param propertyPath the path to the property in an entity i.e.
     * lemma.soart.id, or id
     * @param paramKey the key of the parameter i.e. :id
     * @param operator the operator i.e. like or =
     * @param paramValue the value used in TypedQuery#setParameter
     * @param not when true use negation
     * @param or when true use or otherwise and
     */
    private Param(String propertyPath, String paramKey, String operator, Object paramValue, boolean not, boolean or) {
        this.propertyPath = propertyPath + " ";
        this.skipSetValue = Builder.nullComp(operator) || Builder.emptyComp(operator);
        this.paramKey = paramKey;
        this.operator = " " + operator + " ";
        this.paramValue = paramValue;
        this.not = not ? " NOT " : " ";
        this.andOr = AndOr.fromBool(or);
        paramType = paramValue==null?Object.class:paramValue.getClass();
    }

    /**
     * uses operator like for String and = for other paramValue
     *
     * @param propertyPath
     * @param paramKey
     * @param operator
     * @param paramValue
     */
    private Param(String propertyPath, String paramKey, String operator, Object paramValue) {
        this(propertyPath, paramKey, operator, paramValue, false, false);
    }

    /**
     * uses operator =
     *
     * @param paramKey
     * @param paramValue
     */
    private Param(String paramKey, Object paramValue) {
        this(paramKey, paramKey, "=", paramValue, false, false);
    }
    
    public String getPropertyPath() {
        return propertyPath;
    }
    
    /**
     * for native queries this key should be a numeric positional parameter
     * @return 
     */
    public String getParamKey() {
        return paramKey;
    }
    
    public String getOperator() {
        return operator;
    }
    
    public Object getParamValue() {
        return paramValue;
    }
    
    public String getNot() {
        return not;
    }
    
    public AndOr getAndOr() {
        return andOr;
    }

    public boolean isSkipSetValue() {
        return skipSetValue;
    }

    public Class getParamType() {
        return paramType;
    }

    @Override
    public String toString() {
        return "Param{" + "propertyPath=" + propertyPath + ", paramKey=" + paramKey + ", operator=" + operator + ", paramValue=" + paramValue + ", not=" + not + ", andOr=" + andOr + ", skipSetValue=" + skipSetValue + '}';
    }

    /**
     * helps building a list of Param, by default supports a bit of syntax in String values: "is [not] null/empty" and ! at the beginning of a value.
     * You can also use {@link #Builder(boolean, WildcardMapping)  }
     */
    public static class Builder {
        
        /**
         * translation table a wildcard for more characters and a wildcard for one character
         */
        public interface WildcardMapping {
            char getMoreIn();
            char getMoreOut();
            char getOneIn();
            char getOneOut();
        }
        
        /**
         * * => %, ? => _
         */
        public static class DefaultWildcardMapping implements WildcardMapping {

            @Override
            public char getMoreIn() {
                return '*';
            }

            @Override
            public char getMoreOut() {
                return '%';
            }

            @Override
            public char getOneIn() {
                return '?';
            }

            @Override
            public char getOneOut() {
                return '_';
            }
            
        }
        
        private final List params = new ArrayList<>(3);
        public static final WildcardMapping DEFAULT_MAPPING = new DefaultWildcardMapping();
        public static final String ISNULL = "is null";
        public static final String ISNOTNULL = "is not null";
        public static final String ISEMPTY = "is empty";
        public static final String ISNOTEMPTY = "is not empty";
        public static final char NEGATION = '!';
        private final boolean syntaxInValue;
        private final WildcardMapping wildcardMapping;

        public Builder(boolean syntaxInValue, WildcardMapping wildcardMapping) {
            this.syntaxInValue = syntaxInValue;
            this.wildcardMapping = wildcardMapping;
        }

        /**
         * Builder with syntax support in value (!, is [not] null). Calls
         * {@link #Builder(boolean, WildcardMapping)  } with true and null.
         */
        public Builder() {
            this(true,null);
        }
        

        /**
         * When paramValue is a String call {@link #add(java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)
         * } with false otherwise call {@link #add(java.lang.String, java.lang.String, java.lang.String, java.lang.Object, boolean, boolean)
         * } with false, false.
         *
         * @param propertyPath
         * @param paramKey
         * @param operator
         * @param paramValue
         * @return
         */
        public Builder add(String propertyPath, String paramKey, String operator, Object paramValue) {
            if (paramValue instanceof String) {
                return add(propertyPath, paramKey, operator, String.valueOf(paramValue), false);
            } else {
                return add(propertyPath, paramKey, operator, paramValue, false, false);
            }
        }

        /**
         * When paramValue starts with a ! {@link #getNot() negation} is used,
         * when trimmed paramValue is "is [not] null",
         * operator is set to value and value will be ignored.
         *
         * @param propertyPath
         * @param paramKey
         * @param operator
         * @param paramValue
         * @param or
         * @return
         */
        public Builder add(String propertyPath, String paramKey, String operator, String paramValue, boolean or) {
            return add(propertyPath, paramKey, determineOperator(operator, paramValue), replaceWildcards(stripNegation(paramValue)), isNegation(paramValue), or);
        }

        /**
         * Bottleneck function, adds a new Param
         *
         * @param propertyPath
         * @param paramKey
         * @param operator
         * @param paramValue
         * @param not
         * @param or
         * @return
         */
        public Builder add(String propertyPath, String paramKey, String operator, Object paramValue, boolean not, boolean or) {
            params.add(new Param(propertyPath, paramKey, operator, paramValue, not, or));
            return this;
        }
        
        /**
         * check if a value indicates a negation
         * @param value
         * @return 
         */
        public boolean isNegation(String value) {
            return syntaxInValue && value != null && value.indexOf(NEGATION) == 0;
        }
        
        private String stripNegation(String value) {
            return isNegation(value) ? value.substring(1) : value;
        }
        private String replaceWildcards(String value) {
            return wildcardMapping==null?value:value
                    .replace(wildcardMapping.getMoreIn(), wildcardMapping.getMoreOut())
                    .replace(wildcardMapping.getOneIn(), wildcardMapping.getOneOut());
        }
        
        private String determineOperator(String operator, String value) {
            if (syntaxInValue && nullComp(value)) {
                return value;
            }
            return operator;
        }
        
        /**
         * check if a value is a null comparison
         * @param s
         * @return 
         */
        public static boolean nullComp(String s) {
            if (s==null) return false;
            String t = s.trim().toLowerCase();
            return t.equals(ISNULL) || t.equals(ISNOTNULL);
        }
        /**
         * check if a value is a empty comparison
         * @param s
         * @return 
         */
        public static boolean emptyComp(String s) {
            if (s==null) return false;
            String t = s.trim().toLowerCase();
            return t.equals(ISEMPTY) || t.equals(ISNOTEMPTY);
        }

        /**
         * Calls {@link #add(java.lang.String, java.lang.Object, boolean) } with
         * false
         *
         * @param paramKey
         * @param paramValue
         * @return
         */
        public Builder add(String paramKey, Object paramValue) {
            return add(paramKey, paramValue, false);
        }

        /**
         * When paramValue is a String use like as operator otherwise = and call
         * {@link #add(java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean) },
         * otherwise call {@link #add(java.lang.String, java.lang.String, java.lang.String, java.lang.Object, boolean, boolean)
         * }
         * with false for not.
         *
         * @param paramKey
         * @param paramValue
         * @param or when true use or in queries
         * @return
         */
        public Builder add(String paramKey, Object paramValue, boolean or) {
            if (paramValue instanceof String) {
                return add(paramKey, paramKey, "like", (String) paramValue, or);
            } else {
                return add(paramKey, paramKey, "=", paramValue, false, or);
            }
        }
        
        public List build() {
            return params;
        }

        public boolean isSyntaxInValue() {
            return syntaxInValue;
        }
        
        public boolean containsKey(String key) {
            return params.stream().anyMatch((t) -> {
                return t.getParamKey().equals(key);
            });
        }
        
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy