Search in sources :

Example 1 with MethodMatchContext

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;
}
Also used : Query(io.micronaut.data.annotation.Query) MongoAnnotations(io.micronaut.data.document.mongo.MongoAnnotations) TypeRole(io.micronaut.data.annotation.TypeRole) ClassElement(io.micronaut.inject.ast.ClassElement) FindersUtils(io.micronaut.data.processor.visitors.finders.FindersUtils) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) ParameterElement(io.micronaut.inject.ast.ParameterElement) DataMethod(io.micronaut.data.intercept.annotation.DataMethod) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) MethodMatcher(io.micronaut.data.processor.visitors.finders.MethodMatcher) Map(java.util.Map) Optional(java.util.Optional) MethodMatchInfo(io.micronaut.data.processor.visitors.finders.MethodMatchInfo) Query(io.micronaut.data.annotation.Query) ClassElement(io.micronaut.inject.ast.ClassElement) ParameterElement(io.micronaut.inject.ast.ParameterElement) MethodMatchInfo(io.micronaut.data.processor.visitors.finders.MethodMatchInfo)

Example 2 with MethodMatchContext

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));
                    }
                }
            }
        }
    };
}
Also used : SourcePersistentEntityCriteriaBuilder(io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder) Arrays(java.util.Arrays) Parameter(io.micronaut.context.annotation.Parameter) MappedEntity(io.micronaut.data.annotation.MappedEntity) ParameterExpression(jakarta.persistence.criteria.ParameterExpression) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) ClassElement(io.micronaut.inject.ast.ClassElement) Internal(io.micronaut.core.annotation.Internal) AbstractPersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.impl.AbstractPersistentEntityCriteriaUpdate) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) ParameterElement(io.micronaut.inject.ast.ParameterElement) Version(io.micronaut.data.annotation.Version) Map(java.util.Map) Id(io.micronaut.data.annotation.Id) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) UpdateCriteriaMethodMatch(io.micronaut.data.processor.visitors.finders.criteria.UpdateCriteriaMethodMatch) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) Predicate(jakarta.persistence.criteria.Predicate) AutoPopulated(io.micronaut.data.annotation.AutoPopulated) Set(java.util.Set) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Collectors(java.util.stream.Collectors) PersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.PersistentEntityCriteriaUpdate) PersistentEntityRoot(io.micronaut.data.model.jpa.criteria.PersistentEntityRoot) List(java.util.List) Association(io.micronaut.data.model.Association) Stream(java.util.stream.Stream) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) MethodElement(io.micronaut.inject.ast.MethodElement) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Predicate(jakarta.persistence.criteria.Predicate) SourcePersistentEntityCriteriaBuilder(io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) PersistentEntityRoot(io.micronaut.data.model.jpa.criteria.PersistentEntityRoot) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) AbstractPersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.impl.AbstractPersistentEntityCriteriaUpdate) PersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.PersistentEntityCriteriaUpdate) Version(io.micronaut.data.annotation.Version) UpdateCriteriaMethodMatch(io.micronaut.data.processor.visitors.finders.criteria.UpdateCriteriaMethodMatch) List(java.util.List) ParameterElement(io.micronaut.inject.ast.ParameterElement) Id(io.micronaut.data.annotation.Id)

Example 3 with MethodMatchContext

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);
                }
            }
        }
    };
}
Also used : SourcePersistentEntityCriteriaBuilder(io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) PersistentEntityRoot(io.micronaut.data.model.jpa.criteria.PersistentEntityRoot) AbstractPersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.impl.AbstractPersistentEntityCriteriaUpdate) PersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.PersistentEntityCriteriaUpdate) UpdateCriteriaMethodMatch(io.micronaut.data.processor.visitors.finders.criteria.UpdateCriteriaMethodMatch) ParameterElement(io.micronaut.inject.ast.ParameterElement) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath)

Example 4 with MethodMatchContext

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;
        }
    };
}
Also used : SourcePersistentEntityCriteriaBuilder(io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder) Arrays(java.util.Arrays) Parameter(io.micronaut.context.annotation.Parameter) MappedEntity(io.micronaut.data.annotation.MappedEntity) ParameterExpression(jakarta.persistence.criteria.ParameterExpression) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) ClassElement(io.micronaut.inject.ast.ClassElement) Internal(io.micronaut.core.annotation.Internal) AbstractPersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.impl.AbstractPersistentEntityCriteriaUpdate) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) ParameterElement(io.micronaut.inject.ast.ParameterElement) Version(io.micronaut.data.annotation.Version) Map(java.util.Map) Id(io.micronaut.data.annotation.Id) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) UpdateCriteriaMethodMatch(io.micronaut.data.processor.visitors.finders.criteria.UpdateCriteriaMethodMatch) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) Predicate(jakarta.persistence.criteria.Predicate) AutoPopulated(io.micronaut.data.annotation.AutoPopulated) Set(java.util.Set) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Collectors(java.util.stream.Collectors) PersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.PersistentEntityCriteriaUpdate) PersistentEntityRoot(io.micronaut.data.model.jpa.criteria.PersistentEntityRoot) List(java.util.List) Association(io.micronaut.data.model.Association) Stream(java.util.stream.Stream) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) MethodElement(io.micronaut.inject.ast.MethodElement) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) MappedEntity(io.micronaut.data.annotation.MappedEntity) ClassElement(io.micronaut.inject.ast.ClassElement) Predicate(jakarta.persistence.criteria.Predicate) SourcePersistentEntityCriteriaBuilder(io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) Association(io.micronaut.data.model.Association) PersistentEntityRoot(io.micronaut.data.model.jpa.criteria.PersistentEntityRoot) AbstractPersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.impl.AbstractPersistentEntityCriteriaUpdate) PersistentEntityCriteriaUpdate(io.micronaut.data.model.jpa.criteria.PersistentEntityCriteriaUpdate) UpdateCriteriaMethodMatch(io.micronaut.data.processor.visitors.finders.criteria.UpdateCriteriaMethodMatch) List(java.util.List) ParameterElement(io.micronaut.inject.ast.ParameterElement) Map(java.util.Map) AutoPopulated(io.micronaut.data.annotation.AutoPopulated)

Example 5 with MethodMatchContext

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;
}
Also used : QueryParameterBinding(io.micronaut.data.model.query.builder.QueryParameterBinding) Arrays(java.util.Arrays) Parameter(io.micronaut.context.annotation.Parameter) RepositoryConfiguration(io.micronaut.data.annotation.RepositoryConfiguration) TypeRole(io.micronaut.data.annotation.TypeRole) MappedEntity(io.micronaut.data.annotation.MappedEntity) ClassElement(io.micronaut.inject.ast.ClassElement) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) DataMethod(io.micronaut.data.intercept.annotation.DataMethod) Locale(java.util.Locale) Map(java.util.Map) QueryResult(io.micronaut.data.model.query.builder.QueryResult) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) SourceParameterExpressionImpl(io.micronaut.data.processor.model.criteria.impl.SourceParameterExpressionImpl) BindingContext(io.micronaut.data.model.query.BindingParameter.BindingContext) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) Query(io.micronaut.data.annotation.Query) Utils(io.micronaut.data.processor.visitors.Utils) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Introspected(io.micronaut.core.annotation.Introspected) NonNull(io.micronaut.core.annotation.NonNull) List(java.util.List) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) MethodElement(io.micronaut.inject.ast.MethodElement) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) Collections(java.util.Collections) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) Query(io.micronaut.data.annotation.Query) MappedEntity(io.micronaut.data.annotation.MappedEntity) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) DataMethod(io.micronaut.data.intercept.annotation.DataMethod) ParameterElement(io.micronaut.inject.ast.ParameterElement) Map(java.util.Map)

Aggregations

MethodMatchContext (io.micronaut.data.processor.visitors.MethodMatchContext)12 ParameterElement (io.micronaut.inject.ast.ParameterElement)11 DataInterceptor (io.micronaut.data.intercept.DataInterceptor)10 MatchFailedException (io.micronaut.data.processor.visitors.MatchFailedException)10 ClassElement (io.micronaut.inject.ast.ClassElement)10 Map (java.util.Map)10 SourcePersistentEntity (io.micronaut.data.processor.model.SourcePersistentEntity)9 Parameter (io.micronaut.context.annotation.Parameter)8 List (java.util.List)8 MappedEntity (io.micronaut.data.annotation.MappedEntity)7 DataMethod (io.micronaut.data.intercept.annotation.DataMethod)7 PersistentPropertyPath (io.micronaut.data.model.PersistentPropertyPath)7 MethodElement (io.micronaut.inject.ast.MethodElement)7 Arrays (java.util.Arrays)7 NonNull (io.micronaut.core.annotation.NonNull)6 PersistentEntityRoot (io.micronaut.data.model.jpa.criteria.PersistentEntityRoot)6 SourcePersistentEntityCriteriaBuilder (io.micronaut.data.processor.model.criteria.SourcePersistentEntityCriteriaBuilder)6 Query (io.micronaut.data.annotation.Query)5 TypeRole (io.micronaut.data.annotation.TypeRole)5 QueryResult (io.micronaut.data.model.query.builder.QueryResult)5