use of io.micronaut.data.processor.visitors.finders.MethodMatchInfo in project micronaut-data by micronaut-projects.
the class MongoExecutorQueryMethodMatcher method match.
@Override
public MethodMatch match(MethodMatchContext matchContext) {
Optional<ClassElement> executor = matchContext.getVisitorContext().getClassElement(MongoAnnotations.EXECUTOR_REPOSITORY);
if (executor.isPresent() && executor.get().isAssignable(matchContext.getRepositoryClass())) {
return null;
}
String methodName = matchContext.getMethodElement().getName();
if ("findAll".equals(methodName) || "findOne".equals(methodName)) {
ParameterElement[] parameters = matchContext.getParameters();
switch(parameters.length) {
case 1:
ParameterElement parameter = parameters[0];
if (isBson(parameter)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter.getName());
}
};
} else if (isPipeline(parameter)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.PIPELINE_ROLE, parameter.getName());
}
};
} else if (parameter.getType().isAssignable(MongoAnnotations.FIND_OPTIONS_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FIND_OPTIONS_ROLE, parameter.getName());
}
};
}
break;
case 2:
ParameterElement parameter1 = parameters[0];
ParameterElement parameter2 = parameters[1];
if (isBson(parameter1) && parameter2.getType().isAssignable(MongoAnnotations.FIND_OPTIONS_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter1.getName());
matchInfo.addParameterRole(MongoAnnotations.FIND_OPTIONS_ROLE, parameter2.getName());
}
};
} else if (isPipeline(parameter1) && parameter2.getType().isAssignable(MongoAnnotations.AGGREGATION_OPTIONS_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.PIPELINE_ROLE, parameter1.getName());
matchInfo.addParameterRole(MongoAnnotations.AGGREGATE_OPTIONS_ROLE, parameter2.getName());
}
};
}
if ("findOne".equals(methodName)) {
break;
}
ParameterElement p1 = parameters[0];
ParameterElement p2 = parameters[1];
if (isBson(p1) && p2.getType().isAssignable(MongoAnnotations.PAGEABLE_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, p1.getName());
matchInfo.addParameterRole(TypeRole.PAGEABLE, p2.getName());
// Fake query to have stored query
matchContext.getMethodElement().annotate(Query.class, builder -> {
builder.member(DataMethod.META_MEMBER_COUNT_QUERY, "{}");
});
}
};
} else if (p1.getType().isAssignable(MongoAnnotations.FIND_OPTIONS_BEAN) && p2.getType().isAssignable(MongoAnnotations.PAGEABLE_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.QUERY) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FIND_OPTIONS_ROLE, p1.getName());
matchInfo.addParameterRole(TypeRole.PAGEABLE, p2.getName());
// Fake query to have stored query
matchContext.getMethodElement().annotate(Query.class, builder -> {
builder.member(DataMethod.META_MEMBER_COUNT_QUERY, "{}");
});
}
};
}
break;
default:
return null;
}
}
if ("count".equals(methodName)) {
ParameterElement[] parameters = matchContext.getParameters();
if (parameters.length == 1) {
ParameterElement parameter = parameters[0];
if (isBson(parameter)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.COUNT) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter.getName());
}
};
}
}
return null;
}
if ("deleteAll".equals(methodName)) {
ParameterElement[] parameters = matchContext.getParameters();
switch(parameters.length) {
case 1:
ParameterElement parameter = parameters[0];
if (isBson(parameter)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.DELETE) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter.getName());
}
};
}
break;
case 2:
ParameterElement parameter1 = parameters[0];
ParameterElement parameter2 = parameters[1];
if (isBson(parameter1) && parameter2.getType().isAssignable(MongoAnnotations.DELETE_OPTIONS_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.DELETE) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter1.getName());
matchInfo.addParameterRole(MongoAnnotations.DELETE_OPTIONS_ROLE, parameter2.getName());
}
};
}
break;
default:
return null;
}
}
if ("updateAll".equals(methodName)) {
ParameterElement[] parameters = matchContext.getParameters();
switch(parameters.length) {
case 2:
ParameterElement parameter1 = parameters[0];
ParameterElement parameter2 = parameters[1];
if (isBson(parameter1) && isBson(parameter2)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.UPDATE) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, parameter1.getName());
matchInfo.addParameterRole(MongoAnnotations.UPDATE_ROLE, parameter2.getName());
}
};
}
break;
case 3:
ParameterElement filter = parameters[0];
ParameterElement update = parameters[1];
ParameterElement options = parameters[2];
if (isBson(filter) && isBson(update) && options.getType().isAssignable(MongoAnnotations.UPDATE_OPTIONS_BEAN)) {
return new MongoQueryExecutorMatch(DataMethod.OperationType.UPDATE) {
@Override
protected void apply(MethodMatchInfo matchInfo) {
matchInfo.addParameterRole(MongoAnnotations.FILTER_ROLE, filter.getName());
matchInfo.addParameterRole(MongoAnnotations.UPDATE_ROLE, update.getName());
matchInfo.addParameterRole(MongoAnnotations.UPDATE_OPTIONS_ROLE, options.getName());
}
};
}
break;
default:
return null;
}
}
return null;
}
use of io.micronaut.data.processor.visitors.finders.MethodMatchInfo 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.processor.visitors.finders.MethodMatchInfo 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.processor.visitors.finders.MethodMatchInfo in project micronaut-data by micronaut-projects.
the class MongoRawQueryMethodMatcher method methodMatchByFilterQuery.
private MethodMatch methodMatchByFilterQuery(DataMethod.OperationType operationType) {
return new MethodMatch() {
@Override
public MethodMatchInfo buildMatchInfo(MethodMatchContext matchContext) {
ParameterElement[] parameters = matchContext.getParameters();
ParameterElement entityParameter;
ParameterElement entitiesParameter;
if (parameters.length > 1) {
entityParameter = null;
entitiesParameter = null;
} else {
entityParameter = Arrays.stream(parameters).filter(p -> TypeUtils.isEntity(p.getGenericType())).findFirst().orElse(null);
entitiesParameter = Arrays.stream(parameters).filter(p -> TypeUtils.isIterableOfEntity(p.getGenericType())).findFirst().orElse(null);
}
Map.Entry<ClassElement, Class<? extends DataInterceptor>> entry = FindersUtils.resolveInterceptorTypeByOperationType(entityParameter != null, entitiesParameter != null, operationType, matchContext);
ClassElement resultType = entry.getKey();
Class<? extends DataInterceptor> interceptorType = entry.getValue();
boolean isDto = false;
if (resultType == null) {
resultType = matchContext.getRootEntity().getType();
} else {
if (resultType.hasAnnotation(Introspected.class)) {
if (!resultType.hasAnnotation(MappedEntity.class)) {
isDto = true;
}
}
}
MethodMatchInfo methodMatchInfo = new MethodMatchInfo(operationType, resultType, FindersUtils.getInterceptorElement(matchContext, interceptorType));
methodMatchInfo.dto(isDto);
buildRawQuery(matchContext, methodMatchInfo, entityParameter, entitiesParameter, operationType);
if (entityParameter != null) {
methodMatchInfo.addParameterRole(TypeRole.ENTITY, entityParameter.getName());
} else if (entitiesParameter != null) {
methodMatchInfo.addParameterRole(TypeRole.ENTITIES, entitiesParameter.getName());
}
return methodMatchInfo;
}
};
}
use of io.micronaut.data.processor.visitors.finders.MethodMatchInfo in project micronaut-data by micronaut-projects.
the class RepositoryTypeElementVisitor method visitMethod.
@Override
public void visitMethod(MethodElement element, VisitorContext context) {
if (currentRepository == null || failing) {
return;
}
ClassElement genericReturnType = element.getGenericReturnType();
if (queryEncoder != null && currentClass != null && element.isAbstract() && !element.isStatic() && methodsMatchers != null) {
ParameterElement[] parameters = element.getParameters();
Map<String, Element> parametersInRole = new HashMap<>(2);
for (ParameterElement parameter : parameters) {
ClassElement type = parameter.getType();
this.typeRoles.entrySet().stream().filter(entry -> {
String roleType = entry.getKey();
return type.isAssignable(roleType);
}).forEach(entry -> parametersInRole.put(entry.getValue(), parameter));
}
if (element.hasDeclaredAnnotation(DataMethod.class)) {
// explicitly handled
return;
}
MatchContext matchContext = new MatchContext(queryEncoder, currentRepository, context, element, typeRoles, genericReturnType, parameters);
try {
SourcePersistentEntity entity = resolvePersistentEntity(element, parametersInRole);
MethodMatchContext methodMatchContext = new MethodMatchContext(queryEncoder, currentRepository, entity, context, genericReturnType, element, parametersInRole, typeRoles, parameters, entityResolver);
for (MethodMatcher finder : methodsMatchers) {
MethodMatcher.MethodMatch matcher = finder.match(methodMatchContext);
if (matcher == null) {
continue;
}
MethodMatchInfo methodInfo = matcher.buildMatchInfo(methodMatchContext);
if (methodInfo == null) {
continue;
}
processMethodInfo(methodMatchContext, methodInfo);
return;
}
if (matchContext.isPossiblyFailing()) {
matchContext.logPossibleFailures();
} else {
String messageStart = matchContext.getUnableToImplementMessage();
context.fail(messageStart + "No possible implementations found.", element);
}
this.failing = true;
} catch (MatchFailedException e) {
context.fail(matchContext.getUnableToImplementMessage() + e.getMessage(), e.getElement() == null ? element : e.getElement());
this.failing = true;
} catch (Exception e) {
matchContext.fail(e.getMessage());
this.failing = true;
}
}
}
Aggregations