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

io.debezium.function.Predicates Maven / Gradle / Ivy

There is a newer version: 1.13.0
Show newest version
/*
 * Copyright Debezium Authors.
 *
 * Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
 */
package io.debezium.function;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import io.debezium.util.Strings;

/**
 * Utilities for constructing various predicates.
 *
 * @author Randall Hauch
 *
 */
public class Predicates {

    private static final Pattern LITERAL_SEPARATOR_PATTERN = Pattern.compile(",");

    /**
     * Generate a predicate function that for any supplied UUID strings returns {@code true} if any of the comma-separated
     * UUID literals or regular expressions matches the predicate parameter. This supplied strings can be a mixture
     * of regular expressions and UUID literals, and the most efficient method will be used for each.
     *
     * @param uuidPatterns the comma-separated UUID literals or regular expression patterns; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static Predicate includesUuids(String uuidPatterns) {
        return includesLiteralsOrPatterns(uuidPatterns, Strings::isUuid, (s) -> s);
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if none of the regular
     * expressions or literals in the supplied comma-separated list matches the predicate parameter. This supplied strings can be
     * a mixture of regular expressions and UUID literals, and the most efficient method will be used for each.
     *
     * @param uuidPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static Predicate excludesUuids(String uuidPatterns) {
        return includesUuids(uuidPatterns).negate();
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if any of the regular expressions
     * or literals in the supplied comma-separated list matches the predicate parameter. This supplied strings can be a mixture
     * of regular expressions and literals, and the most efficient method will be used for each.
     *
     * @param literalsOrPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @param isLiteral function that determines if a given pattern is a literal string; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static  Predicate includesLiteralsOrPatterns(String literalsOrPatterns, Predicate isLiteral,
                                                              Function conversion) {
        // First create the predicates that handle either literals or patterns ...
        Set literals = new HashSet<>();
        List patterns = new ArrayList<>();
        for (String literalOrPattern : LITERAL_SEPARATOR_PATTERN.split(literalsOrPatterns)) {
            if (isLiteral.test(literalOrPattern)) {
                literals.add(literalOrPattern.toLowerCase());
            }
            else {
                patterns.add(Pattern.compile(literalOrPattern, Pattern.CASE_INSENSITIVE));
            }
        }
        Predicate patternsPredicate = includedInPatterns(patterns, conversion);
        Predicate literalsPredicate = includedInLiterals(literals, conversion);

        // Now figure out which predicate(s) we need to use ...
        if (patterns.isEmpty()) {
            return literalsPredicate;
        }
        if (literals.isEmpty()) {
            return patternsPredicate;
        }
        return literalsPredicate.or(patternsPredicate);
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if none of the regular
     * expressions or literals in the supplied comma-separated list matches the predicate parameter. This supplied strings can be
     * a mixture of regular expressions and literals, and the most efficient method will be used for each.
     *
     * @param patterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @param isLiteral function that determines if a given pattern is a literal string; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static  Predicate excludesLiteralsOrPatterns(String patterns, Predicate isLiteral,
                                                              Function conversion) {
        return includesLiteralsOrPatterns(patterns, isLiteral, conversion).negate();
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if any of the literals in
     * the supplied comma-separated list case insensitively matches the predicate parameter.
     *
     * @param literals the comma-separated literal strings; may not be null
     * @return the predicate function that performs the matching
     */
    public static Predicate includesLiterals(String literals) {
        return includesLiterals(literals, (s) -> s);
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if none of the literals in
     * the supplied comma-separated list case insensitively matches the predicate parameter.
     *
     * @param literals the comma-separated literal strings; may not be null
     * @return the predicate function that performs the matching
     */
    public static Predicate excludesLiterals(String literals) {
        return includesLiterals(literals).negate();
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if any of the literals in
     * the supplied comma-separated list case insensitively matches the predicate parameter.
     *
     * @param literals the comma-separated literal strings; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     */
    public static  Predicate includesLiterals(String literals, Function conversion) {
        String[] literalValues = LITERAL_SEPARATOR_PATTERN.split(literals.toLowerCase());
        Set literalSet = new HashSet<>(Arrays.asList(literalValues));
        return includedInLiterals(literalSet, conversion);
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if none of the literals in
     * the supplied comma-separated list case insensitively matches the predicate parameter.
     *
     * @param literals the comma-separated literal strings; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     */
    public static  Predicate excludesLiterals(String literals, Function conversion) {
        return includesLiterals(literals, conversion).negate();
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if any of the regular expressions in
     * the supplied comma-separated list matches the predicate parameter.
     *
     * @param regexPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static Predicate includes(String regexPatterns) {
        return includes(regexPatterns, (str) -> str);
    }

    /**
     * Generate a predicate function that for any supplied string returns {@code true} if none of the regular
     * expressions in the supplied comma-separated list matches the predicate parameter.
     *
     * @param regexPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static Predicate excludes(String regexPatterns) {
        return includes(regexPatterns).negate();
    }

    /**
     * Generate a predicate function that for any supplied parameter returns {@code true} if any of the regular expressions
     * in the supplied comma-separated list matches the predicate parameter in a case-insensitive manner.
     *
     * @param regexPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static  Predicate includes(String regexPatterns, Function conversion) {
        Set patterns = Strings.setOfRegex(regexPatterns, Pattern.CASE_INSENSITIVE);
        return includedInPatterns(patterns, conversion);
    }

    public static  BiPredicate includes(String regexPatterns, BiFunction conversion) {
        Set patterns = Strings.setOfRegex(regexPatterns, Pattern.CASE_INSENSITIVE);
        return includedInPatterns(patterns, conversion);
    }

    protected static  Predicate includedInPatterns(Collection patterns, Function conversion) {
        return (t) -> matchedByPattern(patterns, conversion).apply(t).isPresent();
    }

    protected static  BiPredicate includedInPatterns(Collection patterns, BiFunction conversion) {
        return (t, u) -> matchedByPattern(patterns, conversion).apply(t, u).isPresent();
    }

    /**
     * Generate a predicate function that for any supplied string returns a {@link Pattern} representing the first regular expression
     * in the supplied comma-separated list that matches the predicate parameter in a case-insensitive manner.
     *
     * @param regexPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
    
     * @return the function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static Function> matchedBy(String regexPatterns) {
        return matchedByPattern(Strings.setOfRegex(regexPatterns, Pattern.CASE_INSENSITIVE), Function.identity());
    }

    protected static  Function> matchedByPattern(Collection patterns, Function conversion) {
        return (t) -> {
            String str = conversion.apply(t);
            if (str != null) {
                for (Pattern p : patterns) {
                    if (p.matcher(str).matches()) {
                        return Optional.of(p);
                    }
                }
            }
            return Optional.empty();
        };
    }

    protected static  BiFunction> matchedByPattern(Collection patterns, BiFunction conversion) {
        return (t, u) -> {
            String str = conversion.apply(t, u);
            if (str != null) {
                for (Pattern p : patterns) {
                    if (p.matcher(str).matches()) {
                        return Optional.of(p);
                    }
                }
            }
            return Optional.empty();
        };
    }

    protected static  Predicate includedInLiterals(Collection literals, Function conversion) {
        return (s) -> {
            String str = conversion.apply(s).toLowerCase();
            return literals.contains(str);
        };
    }

    /**
     * Generate a predicate function that for any supplied parameter returns {@code true} if none of the regular
     * expressions in the supplied comma-separated list matches the predicate parameter.
     *
     * @param regexPatterns the comma-separated regular expression pattern (or literal) strings; may not be null
     * @param conversion the function that converts each predicate-supplied value to a string that can be matched against the
     *            regular expressions; may not be null
     * @return the predicate function that performs the matching
     * @throws PatternSyntaxException if the string includes an invalid regular expression
     */
    public static  Predicate excludes(String regexPatterns, Function conversion) {
        return includes(regexPatterns, conversion).negate();
    }

    /**
     * Create a predicate function that allows only those values are allowed or not disallowed by the supplied predicates.
     *
     * @param allowed the predicate that defines the allowed values; may be null
     * @param disallowed the predicate that defines the disallowed values; may be null
     * @return the predicate function; never null
     */
    public static  Predicate filter(Predicate allowed, Predicate disallowed) {
        return allowed != null ? allowed : (disallowed != null ? disallowed : (id) -> true);
    }

    public static  Predicate not(Predicate predicate) {
        return predicate.negate();
    }

    public static  Predicate notNull() {
        return new Predicate() {
            @Override
            public boolean test(T t) {
                return t != null;
            }
        };
    }

    private Predicates() {
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy