use of io.micronaut.data.processor.visitors.MethodMatchContext 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.MethodMatchContext in project micronaut-data by micronaut-projects.
the class UpdateMethodMatcher method batchUpdate.
private UpdateCriteriaMethodMatch batchUpdate(java.util.regex.Matcher matcher, ParameterElement idParameter) {
return new UpdateCriteriaMethodMatch(matcher) {
@Override
protected <T> void applyPredicates(String querySequence, ParameterElement[] parameters, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
super.applyPredicates(querySequence, parameters, root, query, cb);
ParameterElement versionParameter = Arrays.stream(parameters).filter(p -> p.hasAnnotation(Version.class)).findFirst().orElse(null);
Predicate predicate;
if (versionParameter != null) {
predicate = cb.and(cb.equal(root.id(), cb.parameter(idParameter)), cb.equal(root.version(), cb.parameter(versionParameter)));
} else {
predicate = cb.equal(root.id(), cb.parameter(idParameter));
}
query.where(predicate);
}
@Override
protected <T> void applyPredicates(List<ParameterElement> parameters, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
ParameterElement versionParameter = parameters.stream().filter(p -> p.hasAnnotation(Version.class)).findFirst().orElse(null);
Predicate predicate;
if (versionParameter != null) {
predicate = cb.and(cb.equal(root.id(), cb.parameter(idParameter)), cb.equal(root.version(), cb.parameter(versionParameter)));
} else {
predicate = cb.equal(root.id(), cb.parameter(idParameter));
}
query.where(predicate);
}
@Override
protected <T> void addPropertiesToUpdate(MethodMatchContext matchContext, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
List<ParameterElement> parameters = matchContext.getParametersNotInRole();
List<ParameterElement> remainingParameters = parameters.stream().filter(p -> !p.hasAnnotation(Id.class) && !p.hasAnnotation(Version.class)).collect(Collectors.toList());
ParameterElement idParameter = parameters.stream().filter(p -> p.hasAnnotation(Id.class)).findFirst().orElse(null);
if (idParameter == null) {
throw new MatchFailedException("ID required for update method, but not specified");
}
SourcePersistentEntity entity = (SourcePersistentEntity) root.getPersistentEntity();
// Validate @IdClass for composite entity
if (entity.hasIdentity()) {
SourcePersistentProperty identity = entity.getIdentity();
String idType = TypeUtils.getTypeName(identity.getType());
String idParameterType = TypeUtils.getTypeName(idParameter.getType());
if (!idType.equals(idParameterType)) {
throw new MatchFailedException("ID type of method [" + idParameterType + "] does not match ID type of entity: " + idType);
}
} else {
throw new MatchFailedException("Cannot update by ID for entity that has no ID");
}
for (ParameterElement parameter : remainingParameters) {
String name = getParameterName(parameter);
SourcePersistentProperty prop = entity.getPropertyByName(name);
if (prop == null) {
throw new MatchFailedException("Cannot update non-existent property: " + name);
} else {
if (prop.isGenerated()) {
throw new MatchFailedException("Cannot update a generated property: " + name);
} else {
query.set(name, cb.parameter(parameter));
}
}
}
}
};
}
use of io.micronaut.data.processor.visitors.MethodMatchContext in project micronaut-data by micronaut-projects.
the class UpdateMethodMatcher method batchUpdate2.
private UpdateCriteriaMethodMatch batchUpdate2(java.util.regex.Matcher matcher) {
return new UpdateCriteriaMethodMatch(matcher) {
@Override
protected <T> void addPropertiesToUpdate(MethodMatchContext matchContext, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
Set<String> queryParameters = query.getParameters().stream().map(ParameterExpression::getName).collect(Collectors.toSet());
for (ParameterElement p : matchContext.getParametersNotInRole()) {
String parameterName = getParameterName(p);
if (queryParameters.contains(parameterName)) {
continue;
}
PersistentPropertyPath path = root.getPersistentEntity().getPropertyPath(parameterName);
if (path != null) {
query.set(path.getProperty().getName(), cb.parameter(p));
} else {
throw new MatchFailedException("Cannot perform batch update for non-existent property: " + parameterName);
}
}
}
};
}
use of io.micronaut.data.processor.visitors.MethodMatchContext in project micronaut-data by micronaut-projects.
the class UpdateMethodMatcher method entityUpdate.
private UpdateCriteriaMethodMatch entityUpdate(java.util.regex.Matcher matcher, ParameterElement entityParameter, ParameterElement entitiesParameter) {
return new UpdateCriteriaMethodMatch(matcher) {
ParameterElement entityParam = entityParameter == null ? entitiesParameter : entityParameter;
@Override
protected <T> void applyPredicates(List<ParameterElement> parameters, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
final SourcePersistentEntity rootEntity = (SourcePersistentEntity) root.getPersistentEntity();
Predicate predicate;
if (rootEntity.getVersion() != null) {
predicate = cb.and(cb.equal(root.id(), cb.entityPropertyParameter(entityParam)), cb.equal(root.version(), cb.entityPropertyParameter(entityParam)));
} else {
predicate = cb.equal(root.id(), cb.entityPropertyParameter(entityParam));
}
query.where(predicate);
}
@Override
protected <T> void addPropertiesToUpdate(MethodMatchContext matchContext, PersistentEntityRoot<T> root, PersistentEntityCriteriaUpdate<T> query, SourcePersistentEntityCriteriaBuilder cb) {
final SourcePersistentEntity rootEntity = matchContext.getRootEntity();
Stream.concat(rootEntity.getPersistentProperties().stream(), Stream.of(rootEntity.getVersion())).filter(p -> p != null && !((p instanceof Association) && ((Association) p).isForeignKey()) && !p.isGenerated() && p.findAnnotation(AutoPopulated.class).map(ap -> ap.getRequiredValue(AutoPopulated.UPDATEABLE, Boolean.class)).orElse(true)).forEach(p -> query.set(p.getName(), cb.entityPropertyParameter(entityParam)));
if (((AbstractPersistentEntityCriteriaUpdate<T>) query).getUpdateValues().isEmpty()) {
// Workaround for only ID entities
query.set(rootEntity.getIdentity().getName(), cb.entityPropertyParameter(entityParam));
}
}
@Override
protected boolean supportedByImplicitQueries() {
return true;
}
@Override
protected Map.Entry<ClassElement, Class<? extends DataInterceptor>> resolveReturnTypeAndInterceptor(MethodMatchContext matchContext) {
Map.Entry<ClassElement, Class<? extends DataInterceptor>> e = super.resolveReturnTypeAndInterceptor(matchContext);
ClassElement returnType = e.getKey();
if (returnType != null && !TypeUtils.isVoid(returnType) && !TypeUtils.isNumber(returnType) && !returnType.hasStereotype(MappedEntity.class) && !(TypeUtils.isReactiveOrFuture(matchContext.getReturnType()) && TypeUtils.isObjectClass(returnType))) {
throw new MatchFailedException("Cannot implement update method for specified return type: " + returnType.getName());
}
return e;
}
@Override
protected ParameterElement getEntityParameter() {
return entityParameter;
}
@Override
protected ParameterElement getEntitiesParameter() {
return entitiesParameter;
}
};
}
use of io.micronaut.data.processor.visitors.MethodMatchContext in project micronaut-data by micronaut-projects.
the class RawQueryMethodMatcher method match.
@Override
public MethodMatch match(MethodMatchContext matchContext) {
if (matchContext.getMethodElement().stringValue(Query.class).isPresent()) {
return new MethodMatch() {
@Override
public MethodMatchInfo buildMatchInfo(MethodMatchContext matchContext) {
MethodElement methodElement = matchContext.getMethodElement();
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);
}
boolean readOnly = matchContext.getAnnotationMetadata().booleanValue(Query.class, "readOnly").orElse(true);
String query = matchContext.getAnnotationMetadata().stringValue(Query.class).orElseThrow(IllegalStateException::new);
DataMethod.OperationType operationType = findOperationType(methodElement.getName(), query, readOnly);
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();
if (interceptorType.getSimpleName().startsWith("SaveOne")) {
// Use `executeUpdate` operation for "insert(String a, String b)" style queries
// - custom query doesn't need to use root entity
// - we would like to know how many rows were updated
operationType = DataMethod.OperationType.UPDATE;
Map.Entry<ClassElement, Class<? extends DataInterceptor>> e = FindersUtils.pickUpdateInterceptor(matchContext, matchContext.getReturnType());
resultType = e.getKey();
interceptorType = e.getValue();
}
if (operationType == DataMethod.OperationType.QUERY) {
// Entity parameter/parameters only make sense if the operation is based on entity
entityParameter = null;
entitiesParameter = null;
}
boolean isDto = false;
if (resultType == null) {
resultType = matchContext.getRootEntity().getType();
} else {
if (operationType == DataMethod.OperationType.QUERY) {
if (resultType.hasAnnotation(Introspected.class)) {
if (!resultType.hasAnnotation(MappedEntity.class)) {
isDto = true;
}
}
} else if (!isValidReturnType(resultType, operationType)) {
throw new MatchFailedException("Invalid result type: " + resultType.getName() + " for '" + operationType + "' operation");
}
}
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;
}
};
}
return null;
}
Aggregations