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

io.github.jhipster.service.QueryService Maven / Gradle / Ivy

Go to download

Server-side library used by applications created with the JHipster generator, see https://www.jhipster.tech/ for more information on JHipster

There is a newer version: 3.9.1
Show newest version
/*
 * Copyright 2016-2018 the original author or authors.
 *
 * 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 io.github.jhipster.service;

import java.util.Collection;
import java.util.Set;
import java.util.function.Function;

import javax.persistence.criteria.CriteriaBuilder.In;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.SetJoin;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

import io.github.jhipster.service.filter.Filter;
import io.github.jhipster.service.filter.RangeFilter;
import io.github.jhipster.service.filter.StringFilter;

/**
 * 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.getSpecified() != null) {
            return byFieldSpecified(metaclassFunction, filter.getSpecified());
        }
        return null;
    }

    /**
     * Helper function to return a specification for filtering on a {@link 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 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.getContains() != null) {
            return likeUpperSpecification(metaclassFunction, filter.getContains());
        } else if (filter.getSpecified() != null) {
            return byFieldSpecified(metaclassFunction, filter.getSpecified());
        }
        return null;
    }

    /**
     * Helper function to return a specification for filtering on a single {@link 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 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 buildRangeSpecification(RangeFilter filter,
        SingularAttribute field) {
        return buildSpecification(filter, root -> root.get(field));
    }

    /**
     * Helper function to return a specification for filtering on a single {@link 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 filter the individual attribute filter coming from the frontend.
     * @param metaclassFunction lambda, which based on a Root<ENTITY> returns Expression - basicaly picks a column
     * @param     The type of the attribute which is filtered.
     * @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.getGreaterThan() != null) {
            result = result.and(greaterThan(metaclassFunction, filter.getGreaterThan()));
        }
        if (filter.getGreaterOrEqualThan() != null) {
            result = result.and(greaterThanOrEqualTo(metaclassFunction, filter.getGreaterOrEqualThan()));
        }
        if (filter.getLessThan() != null) {
            result = result.and(lessThan(metaclassFunction, filter.getLessThan()));
        }
        if (filter.getLessOrEqualThan() != null) {
            result = result.and(lessThanOrEqualTo(metaclassFunction, filter.getLessOrEqualThan()));
        }
        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-one or many-to-one 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> 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 * @deprecated just call buildSpecification(filter, root -> root.get(reference).get(valueField)) */ @Deprecated protected > Specification buildReferringEntitySpecification(final RangeFilter filter, final SingularAttribute reference, final 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 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(root -> functionToEntity.apply(root), 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 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(final RangeFilter filter, final SetAttribute reference, final 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 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(final 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(root -> functionToEntity.apply(root), filter.getSpecified())); } if (filter.getGreaterThan() != null) { result = result.and(greaterThan(fused, filter.getGreaterThan())); } if (filter.getGreaterOrEqualThan() != null) { result = result.and(greaterThanOrEqualTo(fused, filter.getGreaterOrEqualThan())); } if (filter.getLessThan() != null) { result = result.and(lessThan(fused, filter.getLessThan())); } if (filter.getLessOrEqualThan() != null) { result = result.and(lessThanOrEqualTo(fused, filter.getLessOrEqualThan())); } 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. * @return a Specification. */ protected Specification equalsSpecification(Function, Expression> metaclassFunction, final X value) { return (root, query, builder) -> builder.equal(metaclassFunction.apply(root), value); } /** * @deprecated Just call the equalsSpecification(root -> root.get(field), value) directly. */ protected Specification equalsSpecification(SingularAttribute field, final X value) { return equalsSpecification(root -> root.get(field), value); } /** * @deprecated Just call the equalsSpecification(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected Specification equalsSpecification( SingularAttribute reference, SingularAttribute valueField, X value) { return equalsSpecification(root -> root.get(reference).get(valueField), value); } /** * @deprecated Just call the equalsSpecification(root -> root.join(reference).get(valueField), value) directly. */ @Deprecated protected Specification equalsSetSpecification(SetAttribute reference, SingularAttribute idField, X value) { return equalsSpecification(root -> root.join(reference).get(idField), value); } protected Specification likeUpperSpecification(Function, Expression> metaclassFunction, final String value) { return (root, query, builder) -> builder.like(builder.upper(metaclassFunction.apply(root)), wrapLikeQuery(value)); } /** * @deprecated Just call the likeUpperSpecification(root -> root.get(field), value) directly. */ protected Specification likeUpperSpecification(SingularAttribute field, final String value) { return likeUpperSpecification(root -> root.get(field), value); } protected Specification byFieldSpecified(Function, Expression> metaclassFunction, final boolean specified) { return specified ? (root, query, builder) -> builder.isNotNull(metaclassFunction.apply(root)) : (root, query, builder) -> builder.isNull(metaclassFunction.apply(root)); } /** * @deprecated Just call the byFieldSpecified(root -> root.get(field), value) directly. */ @Deprecated protected Specification byFieldSpecified(SingularAttribute field, final boolean specified) { return byFieldSpecified(root -> root.get(field), specified); } protected Specification byFieldEmptiness(Function, Expression>> metaclassFunction, final boolean specified) { return specified ? (root, query, builder) -> builder.isNotEmpty(metaclassFunction.apply(root)) : (root, query, builder) -> builder.isEmpty(metaclassFunction.apply(root)); } /** * @deprecated Just call the byFieldEmptiness(root -> root.get(field), value) directly. */ @Deprecated protected Specification byFieldSpecified(SetAttribute field, final boolean specified) { return byFieldEmptiness(root -> root.get(field), specified); } protected Specification valueIn(Function, Expression> metaclassFunction, final Collection values) { return (root, query, builder) -> { In in = builder.in(metaclassFunction.apply(root)); for (X value : values) { in = in.value(value); } return in; }; } /** * @deprecated Just call the valueIn(root -> root.get(field), value) directly. */ @Deprecated protected Specification valueIn(SingularAttribute field, final Collection values) { return valueIn(root -> root.get(field), values); } /** * @deprecated Just call the valueIn(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected Specification valueIn(SingularAttribute reference, SingularAttribute valueField, final Collection values) { return valueIn(root -> root.get(reference).get(valueField), values); } protected > Specification greaterThanOrEqualTo(Function, Expression> metaclassFunction, final X value) { return (root, query, builder) -> builder.greaterThanOrEqualTo(metaclassFunction.apply(root), value); } protected > Specification greaterThan(Function, Expression> metaclassFunction, final X value) { return (root, query, builder) -> builder.greaterThan(metaclassFunction.apply(root), value); } protected > Specification lessThanOrEqualTo(Function, Expression> metaclassFunction, final X value) { return (root, query, builder) -> builder.lessThanOrEqualTo(metaclassFunction.apply(root), value); } protected > Specification lessThan(Function, Expression> metaclassFunction, final X value) { return (root, query, builder) -> builder.lessThan(metaclassFunction.apply(root), value); } /** * @deprecated Just call the greaterThanOrEqualTo(root -> root.get(field), value) directly. */ @Deprecated protected > Specification greaterThanOrEqualTo(SingularAttribute field, final X value) { return greaterThanOrEqualTo(root -> root.get(field), value); } /** * @deprecated Just call the greaterThan(root -> root.get(field), value) directly. */ @Deprecated protected > Specification greaterThan(SingularAttribute field, final X value) { return greaterThan(root -> root.get(field), value); } /** * @deprecated Just call the lessThanOrEqualTo(root -> root.get(field), value) directly. */ @Deprecated protected > Specification lessThanOrEqualTo(SingularAttribute field, final X value) { return lessThanOrEqualTo(root -> root.get(field), value); } /** * @deprecated Just call the lessThan(root -> root.get(field), value) directly. */ @Deprecated protected > Specification lessThan(SingularAttribute field, final X value) { return lessThan(root -> root.get(field), value); } protected String wrapLikeQuery(String txt) { return "%" + txt.toUpperCase() + '%'; } /** * @deprecated Just call the valueIn(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected Specification valueIn(final SetAttribute reference, final SingularAttribute valueField, final Collection values) { return valueIn(root -> root.join(reference).get(valueField), values); } /** * @deprecated Just call the greaterThan(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected > Specification greaterThan(final SingularAttribute reference, final SingularAttribute valueField, final X value) { return greaterThan(root -> root.get(reference).get(valueField), value); } /** * @deprecated Just call the greaterThan(root -> root.join(reference).get(valueField), value) directly. */ @Deprecated protected > Specification greaterThan(final SetAttribute reference, final SingularAttribute valueField, final X value) { return greaterThan(root -> root.join(reference).get(valueField), value); } /** * @deprecated Just call the greaterThanOrEqualTo(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected > Specification greaterThanOrEqualTo(final SingularAttribute reference, final SingularAttribute valueField, final X value) { return greaterThanOrEqualTo(root -> root.get(reference).get(valueField), value); } /** * @deprecated Just call the greaterThanOrEqualTo(root -> root.join(reference).get(valueField), value) directly. */ @Deprecated protected > Specification greaterThanOrEqualTo(final SetAttribute reference, final SingularAttribute valueField, final X value) { return greaterThanOrEqualTo(root -> root.join(reference).get(valueField), value); } /** * @deprecated Just call the lessThan(root -< root.get(reference).get(valueField), value) directly. */ @Deprecated protected > Specification lessThan(final SingularAttribute reference, final SingularAttribute valueField, final X value) { return lessThan(root -> root.get(reference).get(valueField), value); } /** * @deprecated Just call the lessThan(root -> root.join(reference).get(valueField), value) directly. */ @Deprecated protected > Specification lessThan(final SetAttribute reference, final SingularAttribute valueField, final X value) { return lessThan(root -> root.join(reference).get(valueField), value); } /** * @deprecated Just call the lessThanOrEqualTo(root -> root.get(reference).get(valueField), value) directly. */ @Deprecated protected > Specification lessThanOrEqualTo(final SingularAttribute reference, final SingularAttribute valueField, final X value) { return lessThanOrEqualTo(root -> root.get(reference).get(valueField), value); } /** * @deprecated Just call the lessThanOrEqualTo(root -> root.join(reference).get(valueField), value) directly. */ @Deprecated protected > Specification lessThanOrEqualTo(final SetAttribute reference, final SingularAttribute valueField, final X value) { return lessThanOrEqualTo(root -> root.join(reference).get(valueField), value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy