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

tech.jhipster.service.QueryService Maven / Gradle / Ivy

Go to download

Server-side library used by applications created with the BegCode generator, see https://www.begcode.com/ for more information on BegCode

There is a newer version: 8.6.2
Show newest version
/*
 * Copyright 2016-2023 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * 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.
 */

package tech.jhipster.service;

import tech.jhipster.service.filter.Filter;
import tech.jhipster.service.filter.RangeFilter;
import tech.jhipster.service.filter.StringFilter;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.criteria.CriteriaBuilder.In;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.SetJoin;
import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
import java.util.Collection;
import java.util.Set;
import java.util.function.Function;

/**
 * Base service for constructing and executing complex queries.
 *
 * @param  the type of the entity which is queried.
 */
@Transactional(readOnly = true)
public abstract class QueryService {

    /**
     * Helper function to return a specification for filtering on a single field, where equality, and null/non-null
     * conditions are supported.
     *
     * @param filter the individual attribute filter coming from the frontend.
     * @param field  the JPA static metamodel representing the field.
     * @param     The type of the attribute which is filtered.
     * @return a Specification
     */
    protected  Specification buildSpecification(Filter filter, SingularAttribute
        field) {
        return buildSpecification(filter, root -> root.get(field));
    }

    /**
     * Helper function to return a specification for filtering on a single field, where equality, and null/non-null
     * conditions are supported.
     *
     * @param filter            the individual attribute filter coming from the frontend.
     * @param metaclassFunction the function, which navigates from the current entity to a column, for which the filter applies.
     * @param                The type of the attribute which is filtered.
     * @return a Specification
     */
    protected  Specification buildSpecification(Filter filter, Function, Expression> metaclassFunction) {
        if (filter.getEquals() != null) {
            return equalsSpecification(metaclassFunction, filter.getEquals());
        } else if (filter.getIn() != null) {
            return valueIn(metaclassFunction, filter.getIn());
        } else if (filter.getNotIn() != null) {
            return valueNotIn(metaclassFunction, filter.getNotIn());
        } else if (filter.getNotEquals() != null) {
            return notEqualsSpecification(metaclassFunction, filter.getNotEquals());
        } else if (filter.getSpecified() != null) {
            return byFieldSpecified(metaclassFunction, filter.getSpecified());
        }
        return null;
    }

    /**
     * Helper function to return a specification for filtering on a {@link java.lang.String} field, where equality, containment,
     * and null/non-null conditions are supported.
     *
     * @param filter the individual attribute filter coming from the frontend.
     * @param field  the JPA static metamodel representing the field.
     * @return a Specification
     */
    protected Specification buildStringSpecification(StringFilter filter, SingularAttribute field) {
        return buildSpecification(filter, root -> root.get(field));
    }

    /**
     * Helper function to return a specification for filtering on a {@link java.lang.String} field, where equality, containment,
     * and null/non-null conditions are supported.
     *
     * @param filter            the individual attribute filter coming from the frontend.
     * @param metaclassFunction lambda, which based on a Root<ENTITY> returns Expression - basicaly picks a column
     * @return a Specification
     */
    protected Specification buildSpecification(StringFilter filter, Function, Expression> metaclassFunction) {
        if (filter.getEquals() != null) {
            return equalsSpecification(metaclassFunction, filter.getEquals());
        } else if (filter.getIn() != null) {
            return valueIn(metaclassFunction, filter.getIn());
        } else if (filter.getNotIn() != null) {
            return valueNotIn(metaclassFunction, filter.getNotIn());
        } else if (filter.getContains() != null) {
            return likeUpperSpecification(metaclassFunction, filter.getContains());
        } else if (filter.getDoesNotContain() != null) {
            return doesNotContainSpecification(metaclassFunction, filter.getDoesNotContain());
        } else if (filter.getNotEquals() != null) {
            return notEqualsSpecification(metaclassFunction, filter.getNotEquals());
        } else if (filter.getSpecified() != null) {
            return byFieldSpecified(metaclassFunction, filter.getSpecified());
        }
        return null;
    }

    /**
     * Helper function to return a specification for filtering on a single {@link java.lang.Comparable}, where equality, less
     * than, greater than and less-than-or-equal-to and greater-than-or-equal-to and null/non-null conditions are
     * supported.
     *
     * @param     The type of the attribute which is filtered.
     * @param filter the individual attribute filter coming from the frontend.
     * @param field  the JPA static metamodel representing the field.
     * @return a Specification
     */
    protected > Specification buildRangeSpecification(RangeFilter filter,
                                                                                              SingularAttribute field) {
        return buildSpecification(filter, root -> root.get(field));
    }

    /**
     * Helper function to return a specification for filtering on a single {@link java.lang.Comparable}, where equality, less
     * than, greater than and less-than-or-equal-to and greater-than-or-equal-to and null/non-null conditions are
     * supported.
     *
     * @param                The type of the attribute which is filtered.
     * @param filter            the individual attribute filter coming from the frontend.
     * @param metaclassFunction lambda, which based on a Root<ENTITY> returns Expression - basicaly picks a column
     * @return a Specification
     */
    protected > Specification buildSpecification(RangeFilter filter,
                                                                                         Function, Expression> metaclassFunction) {
        if (filter.getEquals() != null) {
            return equalsSpecification(metaclassFunction, filter.getEquals());
        } else if (filter.getIn() != null) {
            return valueIn(metaclassFunction, filter.getIn());
        }

        Specification result = Specification.where(null);
        if (filter.getSpecified() != null) {
            result = result.and(byFieldSpecified(metaclassFunction, filter.getSpecified()));
        }
        if (filter.getNotEquals() != null) {
            result = result.and(notEqualsSpecification(metaclassFunction, filter.getNotEquals()));
        }
        if (filter.getNotIn() != null) {
            result = result.and(valueNotIn(metaclassFunction, filter.getNotIn()));
        }
        if (filter.getGreaterThan() != null) {
            result = result.and(greaterThan(metaclassFunction, filter.getGreaterThan()));
        }
        if (filter.getGreaterThanOrEqual() != null) {
            result = result.and(greaterThanOrEqualTo(metaclassFunction, filter.getGreaterThanOrEqual()));
        }
        if (filter.getLessThan() != null) {
            result = result.and(lessThan(metaclassFunction, filter.getLessThan()));
        }
        if (filter.getLessThanOrEqual() != null) {
            result = result.and(lessThanOrEqualTo(metaclassFunction, filter.getLessThanOrEqual()));
        }
        return result;
    }

    /**
     * Helper function to return a specification for filtering on one-to-one or many-to-one reference. Usage:
     * 
     *   Specification<Employee> specByProjectId = buildReferringEntitySpecification(criteria.getProjectId(),
     * Employee_.project, Project_.id);
     *   Specification<Employee> specByProjectName = buildReferringEntitySpecification(criteria.getProjectName(),
     * Employee_.project, Project_.name);
     * 
* * @param filter the filter object which contains a value, which needs to match or a flag if nullness is * checked. * @param reference the attribute of the static metamodel for the referring entity. * @param valueField the attribute of the static metamodel of the referred entity, where the equality should be * checked. * @param The type of the referenced entity. * @param The type of the attribute which is filtered. * @return a Specification */ protected Specification buildReferringEntitySpecification(Filter filter, SingularAttribute reference, SingularAttribute valueField) { return buildSpecification(filter, root -> root.get(reference).get(valueField)); } /** * Helper function to return a specification for filtering on one-to-many or many-to-many reference. Usage: *
     *   Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(criteria.getEmployeId(),
     * Project_.employees, Employee_.id);
     *   Specification<Employee> specByEmployeeName = buildReferringEntitySpecification(criteria.getEmployeName(),
     * Project_.project, Project_.name);
     * 
* * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is * checked. * @param reference the attribute of the static metamodel for the referring entity. * @param valueField the attribute of the static metamodel of the referred entity, where the equality should be * checked. * @param The type of the referenced entity. * @param The type of the attribute which is filtered. * @return a Specification */ protected Specification buildReferringEntitySpecification(Filter filter, SetAttribute reference, SingularAttribute valueField) { return buildReferringEntitySpecification(filter, root -> root.join(reference), entity -> entity.get(valueField)); } /** * Helper function to return a specification for filtering on one-to-many or many-to-many reference.Usage:
     *   Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(
     *          criteria.getEmployeId(),
     *          root -> root.get(Project_.company).join(Company_.employees),
     *          entity -> entity.get(Employee_.id));
     *   Specification<Employee> specByProjectName = buildReferringEntitySpecification(
     *          criteria.getProjectName(),
     *          root -> root.get(Project_.project)
     *          entity -> entity.get(Project_.name));
     * 
* * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is * checked. * @param functionToEntity the function, which joins he current entity to the entity set, on which the filtering is applied. * @param entityToColumn the function, which of the static metamodel of the referred entity, where the equality should be * checked. * @param The type of the referenced entity. * @param The type of the entity which is the last before the OTHER in the chain. * @param The type of the attribute which is filtered. * @return a Specification */ protected Specification buildReferringEntitySpecification(Filter filter, Function, SetJoin> functionToEntity, Function, Expression> entityToColumn) { if (filter.getEquals() != null) { return equalsSpecification(functionToEntity.andThen(entityToColumn), filter.getEquals()); } else if (filter.getSpecified() != null) { // Interestingly, 'functionToEntity' doesn't work, we need the longer lambda formula return byFieldSpecified(functionToEntity::apply, filter.getSpecified()); } return null; } /** * Helper function to return a specification for filtering on one-to-many or many-to-many reference.Where equality, less * than, greater than and less-than-or-equal-to and greater-than-or-equal-to and null/non-null conditions are * supported. Usage: *
     *   Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(criteria.getEmployeId(),
     * Project_.employees, Employee_.id);
     *   Specification<Employee> specByEmployeeName = buildReferringEntitySpecification(criteria.getEmployeName(),
     * Project_.project, Project_.name);
     * 
* * @param The type of the attribute which is filtered. * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is * checked. * @param reference the attribute of the static metamodel for the referring entity. * @param valueField the attribute of the static metamodel of the referred entity, where the equality should be * checked. * @param The type of the referenced entity. * @return a Specification */ protected > Specification buildReferringEntitySpecification( RangeFilter filter, SetAttribute reference, SingularAttribute valueField) { return buildReferringEntitySpecification(filter, root -> root.join(reference), entity -> entity.get(valueField)); } /** * Helper function to return a specification for filtering on one-to-many or many-to-many reference.Where equality, less * than, greater than and less-than-or-equal-to and greater-than-or-equal-to and null/non-null conditions are * supported. Usage: *

     *   Specification<Employee> specByEmployeeId = buildReferringEntitySpecification(
     *          criteria.getEmployeId(),
     *          root -> root.get(Project_.company).join(Company_.employees),
     *          entity -> entity.get(Employee_.id));
     *   Specification<Employee> specByProjectName = buildReferringEntitySpecification(
     *          criteria.getProjectName(),
     *          root -> root.get(Project_.project)
     *          entity -> entity.get(Project_.name));
     * 
     * 
* * @param The type of the attribute which is filtered. * @param filter the filter object which contains a value, which needs to match or a flag if emptiness is * checked. * @param functionToEntity the function, which joins he current entity to the entity set, on which the filtering is applied. * @param entityToColumn the function, which of the static metamodel of the referred entity, where the equality should be * checked. * @param The type of the referenced entity. * @param The type of the entity which is the last before the OTHER in the chain. * @return a Specification */ protected > Specification buildReferringEntitySpecification( RangeFilter filter, Function, SetJoin> functionToEntity, Function, Expression> entityToColumn) { Function, Expression> fused = functionToEntity.andThen(entityToColumn); if (filter.getEquals() != null) { return equalsSpecification(fused, filter.getEquals()); } else if (filter.getIn() != null) { return valueIn(fused, filter.getIn()); } Specification result = Specification.where(null); if (filter.getSpecified() != null) { // Interestingly, 'functionToEntity' doesn't work, we need the longer lambda formula result = result.and(byFieldSpecified(functionToEntity::apply, filter.getSpecified())); } if (filter.getNotEquals() != null) { result = result.and(notEqualsSpecification(fused, filter.getNotEquals())); } if (filter.getNotIn() != null) { result = result.and(valueNotIn(fused, filter.getNotIn())); } if (filter.getGreaterThan() != null) { result = result.and(greaterThan(fused, filter.getGreaterThan())); } if (filter.getGreaterThanOrEqual() != null) { result = result.and(greaterThanOrEqualTo(fused, filter.getGreaterThanOrEqual())); } if (filter.getLessThan() != null) { result = result.and(lessThan(fused, filter.getLessThan())); } if (filter.getLessThanOrEqual() != null) { result = result.and(lessThanOrEqualTo(fused, filter.getLessThanOrEqual())); } return result; } /** * Generic method, which based on a Root<ENTITY> returns an Expression which type is the same as the given 'value' type. * * @param metaclassFunction function which returns the column which is used for filtering. * @param value the actual value to filter for. * @param The type of the attribute which is filtered. * @return a Specification. */ protected Specification equalsSpecification(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.equal(metaclassFunction.apply(root), value); } /** * Generic method, which based on a Root<ENTITY> returns an Expression which type is the same as the given 'value' type. * * @param metaclassFunction function which returns the column which is used for filtering. * @param value the actual value to exclude for. * @param The type of the attribute which is filtered. * @return a Specification. */ protected Specification notEqualsSpecification(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.not(builder.equal(metaclassFunction.apply(root), value)); } /** *

likeUpperSpecification.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a {@link java.lang.String} object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification likeUpperSpecification(Function, Expression> metaclassFunction, String value) { return (root, query, builder) -> builder.like(builder.upper(metaclassFunction.apply(root)), wrapLikeQuery(value)); } /** *

doesNotContainSpecification.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a {@link java.lang.String} object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification doesNotContainSpecification(Function, Expression> metaclassFunction, String value) { return (root, query, builder) -> builder.not(builder.like(builder.upper(metaclassFunction.apply(root)), wrapLikeQuery(value))); } /** *

byFieldSpecified.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param specified a boolean. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification byFieldSpecified(Function, Expression> metaclassFunction, boolean specified) { return specified ? (root, query, builder) -> builder.isNotNull(metaclassFunction.apply(root)) : (root, query, builder) -> builder.isNull(metaclassFunction.apply(root)); } /** *

byFieldEmptiness.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param specified a boolean. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification byFieldEmptiness(Function, Expression>> metaclassFunction, boolean specified) { return specified ? (root, query, builder) -> builder.isNotEmpty(metaclassFunction.apply(root)) : (root, query, builder) -> builder.isEmpty(metaclassFunction.apply(root)); } /** *

valueIn.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param values a {@link java.util.Collection} object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification valueIn(Function, Expression> metaclassFunction, Collection values) { return (root, query, builder) -> { In in = builder.in(metaclassFunction.apply(root)); for (X value : values) { in = in.value(value); } return in; }; } /** *

valueNotIn.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param values a {@link java.util.Collection} object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification valueNotIn(Function, Expression> metaclassFunction, Collection values) { return (root, query, builder) -> { In in = builder.in(metaclassFunction.apply(root)); for (X value : values) { in = in.value(value); } return builder.not(in); }; } /** *

greaterThanOrEqualTo.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a X object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected > Specification greaterThanOrEqualTo(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.greaterThanOrEqualTo(metaclassFunction.apply(root), value); } /** *

greaterThan.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a X object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected > Specification greaterThan(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.greaterThan(metaclassFunction.apply(root), value); } /** *

lessThanOrEqualTo.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a X object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected > Specification lessThanOrEqualTo(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.lessThanOrEqualTo(metaclassFunction.apply(root), value); } /** *

lessThan.

* * @param metaclassFunction a {@link java.util.function.Function} object. * @param value a X object. * @param a X object. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected > Specification lessThan(Function, Expression> metaclassFunction, X value) { return (root, query, builder) -> builder.lessThan(metaclassFunction.apply(root), value); } /** *

wrapLikeQuery.

* * @param txt a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ protected String wrapLikeQuery(String txt) { return "%" + txt.toUpperCase() + '%'; } /** *

distinct.

* * @param distinct a boolean. * @return a {@link org.springframework.data.jpa.domain.Specification} object. */ protected Specification distinct(boolean distinct) { return (root, query, cb) -> { query.distinct(distinct); return null; }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy