io.github.jhipster.service.QueryService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jhipster-framework Show documentation
Show all versions of jhipster-framework Show documentation
Server-side library used by applications created with the JHipster generator, see https://www.jhipster.tech/ for more information on JHipster
/*
* 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 super ENTITY, X>
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 super ENTITY,
String> 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 super ENTITY, X> 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 super ENTITY, OTHER> reference,
SingularAttribute super OTHER, X> 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 super ENTITY, OTHER> 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 super ENTITY, X> 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 super ENTITY, OTHER> reference,
SingularAttribute super OTHER, X> 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 super ENTITY, OTHER> 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 super ENTITY, String> 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 super ENTITY, X> 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 super ENTITY, X> 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 super ENTITY, OTHER> reference,
SingularAttribute super OTHER, X> 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 super
ENTITY, X> 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 super ENTITY,
X> 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 super
ENTITY, X> 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 super ENTITY, X>
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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> 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 super ENTITY, OTHER> reference, final SingularAttribute valueField, final X value) {
return lessThanOrEqualTo(root -> root.join(reference).get(valueField), value);
}
}