use of io.micronaut.data.model.query.builder.QueryBuilder in project micronaut-data by micronaut-projects.
the class AbstractSpecificationInterceptor method preparedQueryForCriteria.
protected final <E, QR> PreparedQuery<E, QR> preparedQueryForCriteria(RepositoryMethodKey methodKey, MethodInvocationContext<T, R> context, Type type) {
Class<Object> rootEntity = getRequiredRootEntity(context);
Pageable pageable = Pageable.UNPAGED;
for (Object param : context.getParameterValues()) {
if (param instanceof Pageable) {
pageable = (Pageable) param;
break;
}
}
QueryBuilder sqlQueryBuilder = sqlQueryBuilderForRepositories.computeIfAbsent(methodKey, repositoryMethodKey -> {
Class<QueryBuilder> builder = context.getAnnotationMetadata().classValue(RepositoryConfiguration.class, "queryBuilder").orElseThrow(() -> new IllegalStateException("Cannot determine QueryBuilder"));
BeanIntrospection<QueryBuilder> introspection = BeanIntrospection.getIntrospection(builder);
if (introspection.getConstructorArguments().length == 1 && introspection.getConstructorArguments()[0].getType() == AnnotationMetadata.class) {
return introspection.instantiate(context.getAnnotationMetadata());
}
return introspection.instantiate();
});
QueryResult queryResult;
if (type == Type.COUNT || type == Type.FIND_ALL || type == Type.FIND_ONE || type == Type.FIND_PAGE) {
QuerySpecification<Object> specification = getQuerySpecification(context);
PersistentEntityCriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Root<Object> root = criteriaQuery.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaQuery, criteriaBuilder);
if (predicate != null) {
criteriaQuery.where(predicate);
}
}
if (type == Type.FIND_ALL) {
for (Object param : context.getParameterValues()) {
if (param instanceof Sort && param != pageable) {
Sort sort = (Sort) param;
if (sort.isSorted()) {
criteriaQuery.orderBy(getOrders(sort, root, criteriaBuilder));
break;
}
}
}
} else if (type == Type.COUNT) {
criteriaQuery.select(criteriaBuilder.count(root));
}
queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaQuery).buildQuery(sqlQueryBuilder);
} else if (type == Type.DELETE_ALL) {
DeleteSpecification<Object> specification = getDeleteSpecification(context);
PersistentEntityCriteriaDelete<Object> criteriaDelete = criteriaBuilder.createCriteriaDelete(rootEntity);
Root<Object> root = criteriaDelete.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaDelete, criteriaBuilder);
if (predicate != null) {
criteriaDelete.where(predicate);
}
}
queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaDelete).buildQuery(sqlQueryBuilder);
} else if (type == Type.UPDATE_ALL) {
UpdateSpecification<Object> specification = getUpdateSpecification(context);
PersistentEntityCriteriaUpdate<Object> criteriaUpdate = criteriaBuilder.createCriteriaUpdate(rootEntity);
Root<Object> root = criteriaUpdate.from(rootEntity);
if (specification != null) {
Predicate predicate = specification.toPredicate(root, criteriaUpdate, criteriaBuilder);
if (predicate != null) {
criteriaUpdate.where(predicate);
}
}
queryResult = ((QueryResultPersistentEntityCriteriaQuery) criteriaUpdate).buildQuery(sqlQueryBuilder);
} else {
throw new IllegalStateException("Unknown criteria type: " + type);
}
String query = queryResult.getQuery();
String update = queryResult.getUpdate();
List<io.micronaut.data.model.query.builder.QueryParameterBinding> parameterBindings = queryResult.getParameterBindings();
List<QueryParameterBinding> queryParameters = new ArrayList<>(parameterBindings.size());
for (io.micronaut.data.model.query.builder.QueryParameterBinding p : parameterBindings) {
queryParameters.add(new QueryResultParameterBinding(p, queryParameters));
}
String[] queryParts = queryParameters.stream().anyMatch(QueryParameterBinding::isExpandable) ? queryResult.getQueryParts().toArray(new String[0]) : null;
StoredQuery<E, QR> storedQuery;
if (type == Type.COUNT) {
storedQuery = (StoredQuery<E, QR>) storedQueryResolver.createCountStoredQuery(context.getExecutableMethod(), DataMethod.OperationType.COUNT, context.getName(), context.getAnnotationMetadata(), rootEntity, query, queryParts, queryParameters);
} else if (type == Type.FIND_ALL) {
storedQuery = storedQueryResolver.createStoredQuery(context.getExecutableMethod(), DataMethod.OperationType.QUERY, context.getName(), context.getAnnotationMetadata(), rootEntity, query, null, queryParts, queryParameters, !pageable.isUnpaged(), false);
} else {
DataMethod.OperationType operationType;
switch(type) {
case COUNT:
operationType = DataMethod.OperationType.COUNT;
break;
case DELETE_ALL:
operationType = DataMethod.OperationType.DELETE;
break;
case UPDATE_ALL:
operationType = DataMethod.OperationType.UPDATE;
break;
case FIND_ALL:
case FIND_ONE:
case FIND_PAGE:
operationType = DataMethod.OperationType.QUERY;
break;
default:
throw new IllegalStateException("Unknown value: " + type);
}
storedQuery = storedQueryResolver.createStoredQuery(context.getExecutableMethod(), operationType, context.getName(), context.getAnnotationMetadata(), rootEntity, query, update, queryParts, queryParameters, false, true);
}
return preparedQueryResolver.resolveQuery(context, storedQuery, pageable);
}
use of io.micronaut.data.model.query.builder.QueryBuilder in project micronaut-data by micronaut-projects.
the class RepositoryTypeElementVisitor method processMethodInfo.
private void processMethodInfo(MethodMatchContext methodMatchContext, MethodMatchInfo methodInfo) {
QueryBuilder queryEncoder = methodMatchContext.getQueryBuilder();
MethodElement element = methodMatchContext.getMethodElement();
SourcePersistentEntity entity = methodMatchContext.getRootEntity();
ParameterElement[] parameters = methodMatchContext.getParameters();
// populate parameter roles
for (Map.Entry<String, Element> entry : methodMatchContext.getParametersInRole().entrySet()) {
methodInfo.addParameterRole(entry.getKey(), entry.getValue().getName());
}
List<QueryParameterBinding> parameterBinding = null;
boolean encodeEntityParameters = false;
boolean supportsImplicitQueries = methodMatchContext.supportsImplicitQueries();
QueryResult queryResult = methodInfo.getQueryResult();
if (queryResult != null) {
if (methodInfo.isRawQuery()) {
// no need to annotation since already annotated, just replace the
// the computed parameter names
parameterBinding = queryResult.getParameterBindings();
element.annotate(Query.class, (builder) -> builder.member(DataMethod.META_MEMBER_RAW_QUERY, element.stringValue(Query.class).map(q -> addRawQueryParameterPlaceholders(queryEncoder, queryResult.getQuery(), queryResult.getQueryParts())).orElse(null)));
ClassElement genericReturnType = methodMatchContext.getReturnType();
if (methodMatchContext.isTypeInRole(genericReturnType, TypeRole.PAGE) || element.isPresent(Query.class, "countQuery")) {
QueryResult countQueryResult = methodInfo.getCountQueryResult();
if (countQueryResult == null) {
throw new MatchFailedException("Query returns a Page and does not specify a 'countQuery' member.", element);
} else {
element.annotate(Query.class, (builder) -> builder.member(DataMethod.META_MEMBER_RAW_COUNT_QUERY, addRawQueryParameterPlaceholders(queryEncoder, countQueryResult.getQuery(), countQueryResult.getQueryParts())));
}
}
encodeEntityParameters = methodInfo.isEncodeEntityParameters();
} else {
encodeEntityParameters = methodInfo.isEncodeEntityParameters();
parameterBinding = queryResult.getParameterBindings();
bindAdditionalParameters(methodMatchContext, entity, parameterBinding, parameters, queryResult.getAdditionalRequiredParameters());
QueryResult preparedCount = methodInfo.getCountQueryResult();
if (preparedCount != null) {
element.annotate(Query.class, annotationBuilder -> {
annotationBuilder.value(queryResult.getQuery());
annotationBuilder.member(DataMethod.META_MEMBER_COUNT_QUERY, preparedCount.getQuery());
});
} else {
element.annotate(Query.class, annotationBuilder -> {
annotationBuilder.value(queryResult.getQuery());
String update = queryResult.getUpdate();
if (StringUtils.isNotEmpty(update)) {
annotationBuilder.member("update", update);
}
});
}
}
}
ClassElement runtimeInterceptor = methodInfo.getRuntimeInterceptor();
if (runtimeInterceptor == null) {
throw new MatchFailedException("Unable to implement Repository method: " + currentRepository.getSimpleName() + "." + element.getName() + "(..). No possible runtime implementations found.", element);
}
boolean finalEncodeEntityParameters = encodeEntityParameters;
List<QueryParameterBinding> finalParameterBinding = parameterBinding;
element.annotate(DataMethod.class, annotationBuilder -> {
annotationBuilder.member(DataMethod.META_MEMBER_OPERATION_TYPE, methodInfo.getOperationType());
annotationBuilder.member(DataMethod.META_MEMBER_ROOT_ENTITY, new AnnotationClassValue<>(entity.getName()));
// include the roles
methodInfo.getParameterRoles().forEach(annotationBuilder::member);
if (methodInfo.isDto()) {
annotationBuilder.member(DataMethod.META_MEMBER_DTO, true);
}
if (methodInfo.isOptimisticLock()) {
annotationBuilder.member(DataMethod.META_MEMBER_OPTIMISTIC_LOCK, true);
}
TypedElement resultType = methodInfo.getResultType();
if (resultType != null) {
annotationBuilder.member(DataMethod.META_MEMBER_RESULT_TYPE, new AnnotationClassValue<>(resultType.getName()));
ClassElement type = resultType.getType();
if (!TypeUtils.isVoid(type)) {
annotationBuilder.member(DataMethod.META_MEMBER_RESULT_DATA_TYPE, TypeUtils.resolveDataType(type, dataTypes));
}
}
String idType = resolveIdType(entity);
if (idType != null) {
annotationBuilder.member(DataMethod.META_MEMBER_ID_TYPE, idType);
}
annotationBuilder.member(DataMethod.META_MEMBER_INTERCEPTOR, new AnnotationClassValue<>(runtimeInterceptor.getName()));
if (queryResult != null) {
if (finalParameterBinding.stream().anyMatch(QueryParameterBinding::isExpandable)) {
annotationBuilder.member(DataMethod.META_MEMBER_EXPANDABLE_QUERY, queryResult.getQueryParts().toArray(new String[0]));
QueryResult preparedCount = methodInfo.getCountQueryResult();
if (preparedCount != null) {
annotationBuilder.member(DataMethod.META_MEMBER_EXPANDABLE_COUNT_QUERY, preparedCount.getQueryParts().toArray(new String[0]));
}
}
int max = queryResult.getMax();
if (max > -1) {
annotationBuilder.member(DataMethod.META_MEMBER_PAGE_SIZE, max);
}
long offset = queryResult.getOffset();
if (offset > 0) {
annotationBuilder.member(DataMethod.META_MEMBER_PAGE_INDEX, offset);
}
}
Arrays.stream(parameters).filter(p -> p.getGenericType().isAssignable(entity.getName())).findFirst().ifPresent(parameterElement -> annotationBuilder.member(DataMethod.META_MEMBER_ENTITY, parameterElement.getName()));
if (CollectionUtils.isNotEmpty(finalParameterBinding)) {
bindParameters(supportsImplicitQueries, finalParameterBinding, finalEncodeEntityParameters, annotationBuilder);
}
});
}
use of io.micronaut.data.model.query.builder.QueryBuilder in project micronaut-data by micronaut-projects.
the class UpdateCriteriaMethodMatch method build.
@Override
protected MethodMatchInfo build(MethodMatchContext matchContext) {
MethodMatchSourcePersistentEntityCriteriaBuilderImpl cb = new MethodMatchSourcePersistentEntityCriteriaBuilderImpl(matchContext);
PersistentEntityCriteriaUpdate<Object> criteriaQuery = cb.createCriteriaUpdate(null);
apply(matchContext, criteriaQuery.from(matchContext.getRootEntity()), criteriaQuery, cb);
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = resolveReturnTypeAndInterceptor(matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
AbstractPersistentEntityCriteriaUpdate<?> criteriaUpdate = (AbstractPersistentEntityCriteriaUpdate<?>) criteriaQuery;
boolean optimisticLock = criteriaUpdate.hasVersionRestriction();
final AnnotationMetadataHierarchy annotationMetadataHierarchy = new AnnotationMetadataHierarchy(matchContext.getRepositoryClass().getAnnotationMetadata(), matchContext.getAnnotationMetadata());
QueryBuilder queryBuilder = matchContext.getQueryBuilder();
Map<String, Object> propertiesToUpdate = criteriaUpdate.getUpdateValues();
QueryModel queryModel = ((AbstractPersistentEntityCriteriaUpdate) criteriaQuery).getQueryModel();
QueryResult queryResult = queryBuilder.buildUpdate(annotationMetadataHierarchy, queryModel, propertiesToUpdate);
return new MethodMatchInfo(DataMethod.OperationType.UPDATE, resultType, getInterceptorElement(matchContext, interceptorType)).optimisticLock(optimisticLock).queryResult(queryResult);
}
use of io.micronaut.data.model.query.builder.QueryBuilder in project micronaut-data by micronaut-projects.
the class DeleteCriteriaMethodMatch method build.
@Override
protected MethodMatchInfo build(MethodMatchContext matchContext) {
MethodMatchSourcePersistentEntityCriteriaBuilderImpl cb = new MethodMatchSourcePersistentEntityCriteriaBuilderImpl(matchContext);
PersistentEntityCriteriaDelete<Object> criteriaQuery = cb.createCriteriaDelete(null);
apply(matchContext, criteriaQuery.from(matchContext.getRootEntity()), criteriaQuery, cb);
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = resolveReturnTypeAndInterceptor(matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
boolean optimisticLock = ((AbstractPersistentEntityCriteriaDelete<?>) criteriaQuery).hasVersionRestriction();
final AnnotationMetadataHierarchy annotationMetadataHierarchy = new AnnotationMetadataHierarchy(matchContext.getRepositoryClass().getAnnotationMetadata(), matchContext.getAnnotationMetadata());
QueryBuilder queryBuilder = matchContext.getQueryBuilder();
QueryModel queryModel = ((QueryModelPersistentEntityCriteriaQuery) criteriaQuery).getQueryModel();
QueryResult queryResult = queryBuilder.buildDelete(annotationMetadataHierarchy, queryModel);
return new MethodMatchInfo(DataMethod.OperationType.DELETE, resultType, getInterceptorElement(matchContext, interceptorType)).optimisticLock(optimisticLock).queryResult(queryResult);
}
use of io.micronaut.data.model.query.builder.QueryBuilder in project micronaut-data by micronaut-projects.
the class QueryCriteriaMethodMatch method build.
@Override
protected MethodMatchInfo build(MethodMatchContext matchContext) {
ClassElement queryResultType = matchContext.getRootEntity().getClassElement();
MethodMatchSourcePersistentEntityCriteriaBuilderImpl cb = new MethodMatchSourcePersistentEntityCriteriaBuilderImpl(matchContext);
PersistentEntityCriteriaQuery<Object> criteriaQuery = cb.createQuery();
apply(matchContext, criteriaQuery.from(matchContext.getRootEntity()), criteriaQuery, cb);
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = resolveReturnTypeAndInterceptor(matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
boolean optimisticLock = ((AbstractPersistentEntityCriteriaQuery<?>) criteriaQuery).hasVersionRestriction();
SourcePersistentEntityCriteriaQuery<?> query = (SourcePersistentEntityCriteriaQuery) criteriaQuery;
String selectedType = query.getQueryResultTypeName();
if (selectedType != null) {
queryResultType = matchContext.getVisitorContext().getClassElement(selectedType).orElse(null);
if (queryResultType == null) {
try {
queryResultType = PrimitiveElement.valueOf(selectedType);
} catch (Exception e) {
// Ignore
}
}
}
boolean isDto = resultType != null && !TypeUtils.areTypesCompatible(resultType, queryResultType) && (isDtoType(resultType) || resultType.hasStereotype(Introspected.class) && queryResultType.hasStereotype(MappedEntity.class));
if (isDto) {
if (!isDtoType(resultType)) {
List<SourcePersistentProperty> dtoProjectionProperties = getDtoProjectionProperties(matchContext.getRootEntity(), resultType);
if (!dtoProjectionProperties.isEmpty()) {
Root<?> root = query.getRoots().iterator().next();
query.multiselect(dtoProjectionProperties.stream().map(p -> {
if (matchContext.getQueryBuilder().shouldAliasProjections()) {
return root.get(p.getName()).alias(p.getName());
} else {
return root.get(p.getName());
}
}).collect(Collectors.toList()));
}
}
} else {
if (resultType == null || (!resultType.isAssignable(void.class) && !resultType.isAssignable(Void.class))) {
if (resultType == null || TypeUtils.areTypesCompatible(resultType, queryResultType)) {
if (!queryResultType.isPrimitive() || resultType == null) {
resultType = queryResultType;
}
} else {
throw new MatchFailedException("Query results in a type [" + queryResultType.getName() + "] whilst method returns an incompatible type: " + resultType.getName());
}
}
}
final AnnotationMetadataHierarchy annotationMetadataHierarchy = new AnnotationMetadataHierarchy(matchContext.getRepositoryClass().getAnnotationMetadata(), matchContext.getAnnotationMetadata());
QueryBuilder queryBuilder = matchContext.getQueryBuilder();
QueryModel queryModel = ((QueryModelPersistentEntityCriteriaQuery) criteriaQuery).getQueryModel();
QueryResult queryResult = queryBuilder.buildQuery(annotationMetadataHierarchy, queryModel);
ClassElement genericReturnType = matchContext.getReturnType();
if (TypeUtils.isReactiveOrFuture(genericReturnType)) {
genericReturnType = genericReturnType.getFirstTypeArgument().orElse(matchContext.getRootEntity().getType());
}
QueryResult countQueryResult = null;
if (matchContext.isTypeInRole(genericReturnType, TypeRole.PAGE)) {
// SourcePersistentEntityCriteriaQuery<Object> count = cb.createQuery();
// count.select(cb.count(query.getRoots().iterator().next()));
// CommonAbstractCriteria countQueryCriteria = defineQuery(matchContext, matchContext.getRootEntity(), cb);
QueryModel countQuery = QueryModel.from(queryModel.getPersistentEntity());
countQuery.projections().count();
QueryModel.Junction junction = queryModel.getCriteria();
for (QueryModel.Criterion criterion : junction.getCriteria()) {
countQuery.add(criterion);
}
for (JoinPath joinPath : queryModel.getJoinPaths()) {
Join.Type joinType = joinPath.getJoinType();
switch(joinType) {
case INNER:
case FETCH:
joinType = Join.Type.DEFAULT;
break;
case LEFT_FETCH:
joinType = Join.Type.LEFT;
break;
case RIGHT_FETCH:
joinType = Join.Type.RIGHT;
break;
default:
}
countQuery.join(joinPath.getPath(), joinType, null);
}
countQueryResult = queryBuilder.buildQuery(countQuery);
}
return new MethodMatchInfo(DataMethod.OperationType.QUERY, resultType, getInterceptorElement(matchContext, interceptorType)).dto(isDto).optimisticLock(optimisticLock).queryResult(queryResult).countQueryResult(countQueryResult);
}
Aggregations