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);
}
}
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;
}
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());
}
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");
}
}
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);
}
}
}
}
Aggregations