Search in sources :

Example 6 with JoinPath

use of io.micronaut.data.model.query.JoinPath in project micronaut-data by micronaut-projects.

the class DefaultJdbcRepositoryOperations method findStream.

private <T, R> Stream<R> findStream(@NonNull PreparedQuery<T, R> preparedQuery, Connection connection) {
    Class<R> resultType = preparedQuery.getResultType();
    AtomicBoolean finished = new AtomicBoolean();
    PreparedStatement ps;
    try {
        ps = prepareStatement(connection, connection::prepareStatement, preparedQuery, false, false);
    } catch (Exception e) {
        throw new DataAccessException("SQL Error preparing Query: " + e.getMessage(), e);
    }
    ResultSet openedRs = null;
    ResultSet rs;
    try {
        openedRs = ps.executeQuery();
        rs = openedRs;
        boolean dtoProjection = preparedQuery.isDtoProjection();
        boolean isEntity = preparedQuery.getResultDataType() == DataType.ENTITY;
        Spliterator<R> spliterator;
        if (isEntity || dtoProjection) {
            SqlResultConsumer sqlMappingConsumer = preparedQuery.hasResultConsumer() ? preparedQuery.getParameterInRole(SqlResultConsumer.ROLE, SqlResultConsumer.class).orElse(null) : null;
            SqlTypeMapper<ResultSet, R> mapper;
            final RuntimePersistentEntity<R> persistentEntity = getEntity(resultType);
            if (dtoProjection) {
                mapper = new SqlDTOMapper<>(persistentEntity, columnNameResultSetReader, jsonCodec, conversionService);
            } else {
                Set<JoinPath> joinFetchPaths = preparedQuery.getJoinFetchPaths();
                SqlResultEntityTypeMapper<ResultSet, R> entityTypeMapper = new SqlResultEntityTypeMapper<>(persistentEntity, columnNameResultSetReader, joinFetchPaths, jsonCodec, (loadedEntity, o) -> {
                    if (loadedEntity.hasPostLoadEventListeners()) {
                        return triggerPostLoad(o, loadedEntity, preparedQuery.getAnnotationMetadata());
                    } else {
                        return o;
                    }
                }, conversionService);
                boolean onlySingleEndedJoins = isOnlySingleEndedJoins(getEntity(preparedQuery.getRootEntity()), joinFetchPaths);
                // Cannot stream ResultSet for "many" joined query
                if (!onlySingleEndedJoins) {
                    try {
                        SqlResultEntityTypeMapper.PushingMapper<ResultSet, List<R>> manyMapper = entityTypeMapper.readAllWithJoins();
                        while (rs.next()) {
                            manyMapper.processRow(rs);
                        }
                        return manyMapper.getResult().stream();
                    } finally {
                        closeResultSet(ps, rs, finished);
                    }
                } else {
                    mapper = entityTypeMapper;
                }
            }
            spliterator = new Spliterators.AbstractSpliterator<R>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE) {

                @Override
                public boolean tryAdvance(Consumer<? super R> action) {
                    if (finished.get()) {
                        return false;
                    }
                    boolean hasNext = mapper.hasNext(rs);
                    if (hasNext) {
                        R o = mapper.map(rs, resultType);
                        if (sqlMappingConsumer != null) {
                            sqlMappingConsumer.accept(rs, o);
                        }
                        action.accept(o);
                    } else {
                        closeResultSet(ps, rs, finished);
                    }
                    return hasNext;
                }
            };
        } else {
            spliterator = new Spliterators.AbstractSpliterator<R>(Long.MAX_VALUE, Spliterator.ORDERED | Spliterator.IMMUTABLE) {

                @Override
                public boolean tryAdvance(Consumer<? super R> action) {
                    if (finished.get()) {
                        return false;
                    }
                    try {
                        boolean hasNext = rs.next();
                        if (hasNext) {
                            Object v = columnIndexResultSetReader.readDynamic(rs, 1, preparedQuery.getResultDataType());
                            if (resultType.isInstance(v)) {
                                // noinspection unchecked
                                action.accept((R) v);
                            } else if (v != null) {
                                Object r = columnIndexResultSetReader.convertRequired(v, resultType);
                                if (r != null) {
                                    action.accept((R) r);
                                }
                            }
                        } else {
                            closeResultSet(ps, rs, finished);
                        }
                        return hasNext;
                    } catch (SQLException e) {
                        throw new DataAccessException("Error retrieving next JDBC result: " + e.getMessage(), e);
                    }
                }
            };
        }
        return StreamSupport.stream(spliterator, false).onClose(() -> {
            closeResultSet(ps, rs, finished);
        });
    } catch (Exception e) {
        closeResultSet(ps, openedRs, finished);
        throw new DataAccessException("SQL Error executing Query: " + e.getMessage(), e);
    }
}
Also used : JoinPath(io.micronaut.data.model.query.JoinPath) SQLException(java.sql.SQLException) SqlResultConsumer(io.micronaut.data.jdbc.mapper.SqlResultConsumer) ResultSet(java.sql.ResultSet) ArrayList(java.util.ArrayList) List(java.util.List) SqlResultEntityTypeMapper(io.micronaut.data.runtime.mapper.sql.SqlResultEntityTypeMapper) DataAccessException(io.micronaut.data.exceptions.DataAccessException) PreparedStatement(java.sql.PreparedStatement) SQLException(java.sql.SQLException) DataAccessException(io.micronaut.data.exceptions.DataAccessException) NoSuchElementException(java.util.NoSuchElementException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Spliterators(java.util.Spliterators)

Example 7 with JoinPath

use of io.micronaut.data.model.query.JoinPath in project micronaut-data by micronaut-projects.

the class SqlQueryBuilder method buildJoin.

@Override
protected String[] buildJoin(final String alias, JoinPath joinPath, String joinType, StringBuilder target, Map<String, String> appliedJoinPaths, QueryState queryState) {
    Association[] associationPath = joinPath.getAssociationPath();
    String[] joinAliases;
    if (ArrayUtils.isEmpty(associationPath)) {
        throw new IllegalArgumentException("Invalid association path [" + joinPath.getPath() + "]");
    }
    List<Association> joinAssociationsPath = new ArrayList<>(associationPath.length);
    joinAliases = new String[associationPath.length];
    StringJoiner pathSoFar = new StringJoiner(".");
    String joinAlias = alias;
    for (int i = 0; i < associationPath.length; i++) {
        Association association = associationPath[i];
        pathSoFar.add(association.getName());
        if (association instanceof Embedded) {
            joinAssociationsPath.add(association);
            continue;
        }
        String currentPath = pathSoFar.toString();
        String existingAlias = appliedJoinPaths.get(currentPath);
        if (existingAlias != null) {
            joinAliases[i] = existingAlias;
            joinAlias = existingAlias;
        } else {
            PersistentEntity associatedEntity = association.getAssociatedEntity();
            int finalI = i;
            JoinPath joinPathToUse = queryState.getQueryModel().getJoinPath(currentPath).orElseGet(() -> new JoinPath(currentPath, Arrays.copyOfRange(associationPath, 0, finalI + 1), joinPath.getJoinType(), joinPath.getAlias().orElse(null)));
            joinAliases[i] = getAliasName(joinPathToUse);
            String currentJoinAlias = joinAliases[i];
            buildJoin(joinType, target, queryState, joinAssociationsPath, joinAlias, association, associatedEntity, findOwner(joinAssociationsPath, association).orElseGet(queryState::getEntity), currentJoinAlias);
            joinAlias = currentJoinAlias;
        }
        joinAssociationsPath.clear();
    }
    return joinAliases;
}
Also used : Association(io.micronaut.data.model.Association) JoinPath(io.micronaut.data.model.query.JoinPath) PersistentEntity(io.micronaut.data.model.PersistentEntity) ArrayList(java.util.ArrayList) Embedded(io.micronaut.data.model.Embedded) StringJoiner(java.util.StringJoiner)

Example 8 with JoinPath

use of io.micronaut.data.model.query.JoinPath in project micronaut-data by micronaut-projects.

the class AbstractSqlLikeQueryBuilder method buildOrderBy.

/**
 * Encode the given query into the encoded query instance.
 *
 * @param query The query
 * @param entity The root entity
 * @param sort The sort
 * @return The encoded query
 */
@NonNull
public QueryResult buildOrderBy(String query, @NonNull PersistentEntity entity, @NonNull Sort sort) {
    ArgumentUtils.requireNonNull("entity", entity);
    ArgumentUtils.requireNonNull("sort", sort);
    List<Sort.Order> orders = sort.getOrderBy();
    if (CollectionUtils.isEmpty(orders)) {
        throw new IllegalArgumentException("Sort is empty");
    }
    StringBuilder buff = new StringBuilder(ORDER_BY_CLAUSE);
    Iterator<Sort.Order> i = orders.iterator();
    while (i.hasNext()) {
        Sort.Order order = i.next();
        String property = order.getProperty();
        PersistentPropertyPath path = entity.getPropertyPath(property);
        if (path == null) {
            throw new IllegalArgumentException("Cannot sort on non-existent property path: " + property);
        }
        boolean ignoreCase = order.isIgnoreCase();
        if (ignoreCase) {
            buff.append("LOWER(");
        }
        if (path.getAssociations().isEmpty()) {
            buff.append(getAliasName(entity));
        } else {
            StringJoiner joiner = new StringJoiner(".");
            for (Association association : path.getAssociations()) {
                joiner.add(association.getName());
            }
            String joinAlias = getAliasName(new JoinPath(joiner.toString(), path.getAssociations().toArray(new Association[0]), Join.Type.DEFAULT, null));
            if (!computePropertyPaths()) {
                if (!query.contains(" " + joinAlias + " ") && !query.endsWith(" " + joinAlias)) {
                    // Special hack case for JPA, Hibernate can join the relation with cross join automatically when referenced by the property path
                    // This probably should be removed in the future major version
                    buff.append(getAliasName(entity)).append(DOT);
                    StringJoiner pathJoiner = new StringJoiner(".");
                    for (Association association : path.getAssociations()) {
                        pathJoiner.add(association.getName());
                    }
                    buff.append(pathJoiner);
                } else {
                    buff.append(joinAlias);
                }
            } else {
                buff.append(joinAlias);
            }
        }
        buff.append(DOT);
        if (!computePropertyPaths()) {
            buff.append(path.getProperty().getName());
        } else {
            buff.append(getColumnName(path.getProperty()));
        }
        if (ignoreCase) {
            buff.append(")");
        }
        buff.append(SPACE).append(order.getDirection());
        if (i.hasNext()) {
            buff.append(",");
        }
    }
    return QueryResult.of(buff.toString(), Collections.emptyList(), Collections.emptyList(), Collections.emptyMap());
}
Also used : JoinPath(io.micronaut.data.model.query.JoinPath) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) Association(io.micronaut.data.model.Association) Sort(io.micronaut.data.model.Sort) StringJoiner(java.util.StringJoiner) NonNull(io.micronaut.core.annotation.NonNull)

Example 9 with JoinPath

use of io.micronaut.data.model.query.JoinPath in project micronaut-data by micronaut-projects.

the class AbstractSqlLikeQueryBuilder method joinInPath.

private String joinInPath(QueryState queryState, String joinStringPath) {
    QueryModel queryModel = queryState.getQueryModel();
    JoinPath joinPath = queryModel.getJoinPath(joinStringPath).orElse(null);
    if (joinPath == null) {
        joinPath = queryModel.join(joinStringPath, Join.Type.DEFAULT, null);
    }
    if (queryState.isAllowJoins()) {
        return queryState.applyJoin(joinPath);
    } else {
        throw new IllegalArgumentException("Joins are not allowed for batch update queries");
    }
}
Also used : JoinPath(io.micronaut.data.model.query.JoinPath) QueryModel(io.micronaut.data.model.query.QueryModel)

Example 10 with JoinPath

use of io.micronaut.data.model.query.JoinPath in project micronaut-data by micronaut-projects.

the class SqlQueryBuilder method selectAllColumns.

@Override
protected void selectAllColumns(QueryState queryState, StringBuilder queryBuffer) {
    PersistentEntity entity = queryState.getEntity();
    selectAllColumns(entity, queryState.getRootAlias(), queryBuffer);
    QueryModel queryModel = queryState.getQueryModel();
    Collection<JoinPath> allPaths = queryModel.getJoinPaths();
    if (CollectionUtils.isNotEmpty(allPaths)) {
        Collection<JoinPath> joinPaths = allPaths.stream().filter(jp -> {
            Join.Type jt = jp.getJoinType();
            return jt.name().contains("FETCH");
        }).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(joinPaths)) {
            for (JoinPath joinPath : joinPaths) {
                Association association = joinPath.getAssociation();
                if (association instanceof Embedded) {
                    // joins on embedded don't make sense
                    continue;
                }
                PersistentEntity associatedEntity = association.getAssociatedEntity();
                NamingStrategy namingStrategy = associatedEntity.getNamingStrategy();
                String aliasName = getAliasName(joinPath);
                String joinPathAlias = getPathOnlyAliasName(joinPath);
                queryBuffer.append(COMMA);
                boolean includeIdentity = false;
                if (association.isForeignKey()) {
                    // in the case of a foreign key association the ID is not in the table
                    // so we need to retrieve it
                    includeIdentity = true;
                }
                traversePersistentProperties(associatedEntity, includeIdentity, true, (propertyAssociations, prop) -> {
                    String columnName;
                    if (computePropertyPaths()) {
                        columnName = namingStrategy.mappedName(propertyAssociations, prop);
                    } else {
                        columnName = asPath(propertyAssociations, prop);
                    }
                    queryBuffer.append(aliasName).append(DOT).append(queryState.shouldEscape() ? quote(columnName) : columnName).append(AS_CLAUSE).append(joinPathAlias).append(columnName).append(COMMA);
                });
                queryBuffer.setLength(queryBuffer.length() - 1);
            }
        }
    }
}
Also used : DataType(io.micronaut.data.model.DataType) SqlMembers(io.micronaut.data.annotation.sql.SqlMembers) Arrays(java.util.Arrays) IDENTITY(io.micronaut.data.annotation.GeneratedValue.Type.IDENTITY) ListIterator(java.util.ListIterator) ArrayUtils(io.micronaut.core.util.ArrayUtils) SEQUENCE(io.micronaut.data.annotation.GeneratedValue.Type.SEQUENCE) MappedProperty(io.micronaut.data.annotation.MappedProperty) GeneratedValue(io.micronaut.data.annotation.GeneratedValue) Locale(java.util.Locale) Map(java.util.Map) QueryResult(io.micronaut.data.model.query.builder.QueryResult) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) PersistentProperty(io.micronaut.data.model.PersistentProperty) Index(io.micronaut.data.annotation.Index) MappingException(io.micronaut.data.exceptions.MappingException) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) AUTO(io.micronaut.data.annotation.GeneratedValue.Type.AUTO) StringUtils(io.micronaut.core.util.StringUtils) AbstractSqlLikeQueryBuilder(io.micronaut.data.model.query.builder.AbstractSqlLikeQueryBuilder) List(java.util.List) Stream(java.util.stream.Stream) UUID(io.micronaut.data.annotation.GeneratedValue.Type.UUID) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Experimental(io.micronaut.core.annotation.Experimental) Pattern(java.util.regex.Pattern) Relation(io.micronaut.data.annotation.Relation) IntStream(java.util.stream.IntStream) QueryParameterBinding(io.micronaut.data.model.query.builder.QueryParameterBinding) Join(io.micronaut.data.annotation.Join) Creator(io.micronaut.core.annotation.Creator) QueryModel(io.micronaut.data.model.query.QueryModel) MappedEntity(io.micronaut.data.annotation.MappedEntity) HashMap(java.util.HashMap) OptionalInt(java.util.OptionalInt) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Embedded(io.micronaut.data.model.Embedded) Pageable(io.micronaut.data.model.Pageable) BiConsumer(java.util.function.BiConsumer) Clob(java.sql.Clob) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Indexes(io.micronaut.data.annotation.Indexes) NonNull(io.micronaut.core.annotation.NonNull) JoinPath(io.micronaut.data.model.query.JoinPath) Association(io.micronaut.data.model.Association) PersistentEntity(io.micronaut.data.model.PersistentEntity) CollectionUtils(io.micronaut.core.util.CollectionUtils) StringJoiner(java.util.StringJoiner) QueryBuilder(io.micronaut.data.model.query.builder.QueryBuilder) Repository(io.micronaut.data.annotation.Repository) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Blob(java.sql.Blob) Collections(java.util.Collections) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) DataType(io.micronaut.data.model.DataType) Association(io.micronaut.data.model.Association) JoinPath(io.micronaut.data.model.query.JoinPath) PersistentEntity(io.micronaut.data.model.PersistentEntity) Embedded(io.micronaut.data.model.Embedded) QueryModel(io.micronaut.data.model.query.QueryModel)

Aggregations

JoinPath (io.micronaut.data.model.query.JoinPath)11 ArrayList (java.util.ArrayList)7 Association (io.micronaut.data.model.Association)6 QueryModel (io.micronaut.data.model.query.QueryModel)5 StringJoiner (java.util.StringJoiner)5 NonNull (io.micronaut.core.annotation.NonNull)4 Embedded (io.micronaut.data.model.Embedded)4 List (java.util.List)4 Map (java.util.Map)4 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)3 StringUtils (io.micronaut.core.util.StringUtils)3 Join (io.micronaut.data.annotation.Join)3 PersistentEntity (io.micronaut.data.model.PersistentEntity)3 PersistentPropertyPath (io.micronaut.data.model.PersistentPropertyPath)3 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)2 Internal (io.micronaut.core.annotation.Internal)2 Nullable (io.micronaut.core.annotation.Nullable)2 ArgumentUtils (io.micronaut.core.util.ArgumentUtils)2 CollectionUtils (io.micronaut.core.util.CollectionUtils)2 Relation (io.micronaut.data.annotation.Relation)2