All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.everit.persistence.querydsl.dtoquery.DTOQuery Maven / Gradle / Ivy
/*
* Copyright © 2011 Everit Kft. (http://www.everit.biz)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.everit.persistence.querydsl.dtoquery;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.SimpleExpression;
import com.querydsl.sql.Configuration;
import com.querydsl.sql.RelationalPathBase;
import com.querydsl.sql.SQLQuery;
/**
* Queries a DTO class.
*
* @param
* Type of the DTO.
* @param
* Type of the foreign key
*/
public class DTOQuery {
/**
* Helper method to create a DTOQuery using setters and selecting all fields from the table as is.
*
* @param
* The type of the foreign key if the dtoQuery is called as a property selector of
* another DTO.
* @param
* The type of the DTO.
* @param configuration
* The Querydsl configuration.
* @param qTable
* The Querydsl Q class of the table.
* @param dtoType
* The type of the DTO that should be instantiated.
* @param foreignKeyPath
* The path to the foreign key in the generated SQL.
* @return The {@link DTOQuery} instance that can be further configured.
*/
public static DTOQuery beanFullTable(Configuration configuration,
RelationalPathBase> qTable, Class dtoType, SimpleExpression foreignKeyPath) {
return DTOQuery.create(
(fks) -> new SQLQuery(configuration).select(Projections.bean(dtoType, qTable.all()))
.from(qTable).where(foreignKeyPath.in(fks)));
}
/**
* Helper method to be able to write simpler code. If the constructor was used, the type
* parameters should be defined. The same as calling {@link DTOQuery#queryGenerator(Function)} on
* a newly created {@link DTOQuery} instance.
*/
public static DTOQuery create(
Function, SQLQuery> queryGenerator) {
return new DTOQuery().queryGenerator(queryGenerator);
}
/**
* Helper method to create a DTOQuery using public member variable access and selecting all fields
* from the table as is.
*
* @param
* The type of the foreign key if the dtoQuery is called as a property selector of
* another DTO.
* @param
* The type of the DTO.
* @param configuration
* The Querydsl configuration.
* @param qTable
* The Querydsl Q class of the table.
* @param dtoType
* The type of the DTO that should be instantiated.
* @param foreignKeyPath
* The path to the foreign key in the generated SQL.
* @return The {@link DTOQuery} instance that can be further configured.
*/
public static DTOQuery dtoFullTable(Configuration configuration,
RelationalPathBase> qTable, Class dtoType, SimpleExpression foreignKeyPath) {
return DTOQuery.create(
(fks) -> new SQLQuery(configuration).select(Projections.fields(dtoType, qTable.all()))
.from(qTable).where(foreignKeyPath.in(fks)));
}
/**
* Helper method to create a {@link DTOQuery} for the root DTO type. In case of root DTO type one
* does not need to handle incoming foreign keys.
*
* @param
* The type of the DTOs that are queried from the database.
* @param query
* The query that is used to select the DTOs.
* @return A DTO query instance that can be further configured.
*/
public static DTOQuery root(SQLQuery query) {
return new DTOQuery().queryGenerator((fks) -> query);
}
/**
* Helper method to create a DTOQuery using setters and selecting all fields from the table as is.
* This function can be used to select the root DTOs.
*
* @param
* The type of the DTO.
* @param configuration
* The Querydsl configuration.
* @param qTable
* The Querydsl Q class of the table.
* @param dtoType
* The type of the DTO that should be instantiated.
* @return The {@link DTOQuery} instance that can be further configured.
*/
public static DTOQuery rootBeanFullTable(
Configuration configuration, RelationalPathBase> qTable,
Class dtoType) {
return DTOQuery
.root(new SQLQuery<>(configuration).select(Projections.bean(dtoType, qTable.all()))
.from(qTable));
}
/**
* Helper method to create a DTOQuery using public member variable access and selecting all fields
* from the table as is. This function can be used to select the root DTOs.
*
* @param
* The type of the DTO.
* @param configuration
* The Querydsl configuration.
* @param qTable
* The Querydsl Q class of the table.
* @param dtoType
* The type of the DTO that should be instantiated.
* @return The {@link DTOQuery} instance that can be further configured.
*/
public static DTOQuery rootDTOFullTable(
Configuration configuration, RelationalPathBase> qTable,
Class dtoType) {
return DTOQuery
.root(new SQLQuery<>(configuration).select(Projections.fields(dtoType, qTable.all()))
.from(qTable));
}
private List> propertyQueries = new ArrayList<>();
private Function, SQLQuery> queryGenerator;
/**
* Adds a property query to this DTO so the given property will be queried after all DTOs by this
* {@link DTOQuery} is selected.
*
* @param
* Type of the property.
* @param
* Type of the key that connects the property and the DTOs selected by this
* {@link DTOQuery}.
* @param propertyQuery
* The query of the property that must be built by the programmer. See
* {@link PropertyQuery}.
* @return This {@link DTOQuery} instance.
*/
public DTOQuery prop(PropertyQuery propertyQuery) {
this.propertyQueries.add(propertyQuery);
return this;
}
/**
* Runs the query on the database.
*
* @param connection
* The database connection.
* @return Collection of DTOs.
*/
public Collection queryDTO(Connection connection) {
return this.queryDTO(connection, Collections.emptySet());
}
/**
* Queries the set of DTOs by filtering the specific foreign keys.
*
* @param connection
* The database connection.
* @param foreignKeys
* The foreign keys to filter in the query.
* @return The collection of DTOs that were pulled out from the database.
*/
Collection queryDTO(Connection connection, Collection foreignKeys) {
SQLQuery query = this.queryGenerator.apply(foreignKeys);
List resultSet = query.clone(connection).fetch();
queryDTOProperties(connection, resultSet);
return resultSet;
}
private void queryDTOProperties(Connection connection, Collection resultSet) {
for (PropertyQuery propertyQuery : this.propertyQueries) {
queryDTOProperty(connection, resultSet, propertyQuery);
}
}
private void queryDTOProperty(Connection connection, Collection dtos,
PropertyQuery propertyQuery) {
Map dtosByForeignKeys = new HashMap<>();
for (T result : dtos) {
Function keyInSourceResolver = propertyQuery.keyInSourceDTOResolver;
PFK keyInSource = keyInSourceResolver.apply(result);
dtosByForeignKeys.put(keyInSource, result);
}
Collection properties =
propertyQuery.dtoQuery.queryDTO(connection, dtosByForeignKeys.keySet());
Map> propertyCollectionByForeignKeyMap = new HashMap<>();
Function keyInPropertyResolver = propertyQuery.keyInPropertyResolver;
for (P prop : properties) {
PFK propertyForeignKey = keyInPropertyResolver.apply(prop);
propertyCollectionByForeignKeyMap.computeIfAbsent(propertyForeignKey, k -> new ArrayList<>())
.add(prop);
}
setPropertiesInDTOs(dtosByForeignKeys, propertyCollectionByForeignKeyMap, propertyQuery);
}
/**
* Specifying the query generator for this DTO.
*
* @param queryGenerator
* The generator of the SQLQuery of this {@link DTOQuery}. The generator is a function
* where the parameter is the list of foreign keys coming from the source DTO and the
* result is the generated SQLQuery.
* @return This {@link DTOQuery} instance.
*/
public DTOQuery queryGenerator(Function, SQLQuery> queryGenerator) {
this.queryGenerator = queryGenerator;
return this;
}
private void setPropertiesInDTOs(Map dtosByForeignKeys,
Map> propertyCollectionByForeignKeyMap,
PropertyQuery propertyQuery) {
for (Entry dtoEntry : dtosByForeignKeys.entrySet()) {
PFK foreignKey = dtoEntry.getKey();
T dto = dtoEntry.getValue();
if (dto == null) {
throw new NullPointerException("No DTO found for foreign key: " + foreignKey.toString());
}
Collection propertyCollection = propertyCollectionByForeignKeyMap.get(foreignKey);
if (propertyCollection != null) {
if (propertyQuery.setter != null) {
// There is at least one element at this point otherwise the propertyCollection would be
// null
if (propertyCollection.size() > 1) {
throw new IllegalArgumentException(
"More than one property found for foreign key: " + foreignKey);
}
P prop = propertyCollection.iterator().next();
propertyQuery.setter.accept(dto, prop);
} else if (propertyQuery.oneToManySetter != null) {
propertyQuery.oneToManySetter.accept(dto, propertyCollection);
} else {
throw new IllegalArgumentException(
"No setter defined for property query: " + propertyQuery.toString());
}
}
}
}
}