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.
com.landawn.abacus.util.JoinInfo Maven / Gradle / Ivy
package com.landawn.abacus.util;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.annotation.Column;
import com.landawn.abacus.annotation.JoinedBy;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory.CF;
import com.landawn.abacus.core.DirtyMarkerUtil;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.EntityInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.JdbcUtil.BiParametersSetter;
import com.landawn.abacus.util.SQLBuilder.PAC;
import com.landawn.abacus.util.SQLBuilder.PLC;
import com.landawn.abacus.util.SQLBuilder.PSC;
import com.landawn.abacus.util.Tuple.Tuple2;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.stream.Stream;
final class JoinInfo {
final Class> entityClass;
final EntityInfo entityInfo;
final PropInfo joinPropInfo;
final PropInfo[] srcPropInfos;
final PropInfo[] referencedPropInfos;
final Type> referencedEntityType;
final Class> referencedEntityClass;
final EntityInfo referencedEntityInfo;
final Function srcEntityKeyExtractor;
final Function referencedEntityKeyExtractor;
private final Map, Tuple2, String>, BiParametersSetter>> sqlBuilderSetterForSingleEntityMap = new HashMap<>();
private final Map, Tuple2, Integer, String>, BiParametersSetter>>> sqlBuilderSetterForEntitiesMap = new HashMap<>();
JoinInfo(final Class> entityClass, final String joinEntityPropName) {
this.entityClass = entityClass;
entityInfo = ParserUtil.getEntityInfo(entityClass);
this.joinPropInfo = entityInfo.getPropInfo(joinEntityPropName);
if (joinPropInfo == null) {
throw new IllegalArgumentException(
"No property found by name: '" + joinEntityPropName + "' in class: " + ClassUtil.getCanonicalClassName(entityClass));
} else if (!joinPropInfo.isAnnotationPresent(JoinedBy.class)) {
throw new IllegalArgumentException("Property '" + joinPropInfo.name + "' in class: " + entityClass + " is not annotated by @JoinedBy");
} else if (joinPropInfo.isAnnotationPresent(Column.class)) {
throw new IllegalArgumentException("Property '" + joinPropInfo.name + "' in class: " + entityClass + " is annotated by @Column");
}
referencedEntityType = joinPropInfo.type.isCollection() ? joinPropInfo.type.getElementType() : joinPropInfo.type;
if (!referencedEntityType.isEntity() || joinPropInfo.isAnnotationPresent(Column.class)) {
throw new IllegalArgumentException(
"Property '" + joinPropInfo.name + "' in class: " + entityClass + " is not an entity type or annotated by @Column");
}
referencedEntityClass = referencedEntityType.clazz();
final String joinByVal = joinPropInfo.getAnnotation(JoinedBy.class).value();
if (N.isNullOrEmpty(joinByVal)) {
throw new IllegalArgumentException(
"Invalid value: " + joinByVal + " for annotation @JoinBy on property '" + joinPropInfo.name + "' in class: " + entityClass);
}
referencedEntityInfo = ParserUtil.getEntityInfo(referencedEntityClass);
final String[] joinColumnPairs = StringUtil.split(joinByVal, ',', true);
srcPropInfos = new PropInfo[joinColumnPairs.length];
referencedPropInfos = new PropInfo[joinColumnPairs.length];
final List conds = new ArrayList<>(joinColumnPairs.length);
for (int i = 0, len = joinColumnPairs.length; i < len; i++) {
final String[] tmp = StringUtil.split(joinColumnPairs[i], '=', true);
if (tmp.length > 2) {
throw new IllegalArgumentException(
"Invalid value: " + joinByVal + " for annotation @JoinBy on property '" + joinPropInfo.name + "' in class: " + entityClass);
}
if ((srcPropInfos[i] = entityInfo.getPropInfo(tmp[0])) == null) {
throw new IllegalArgumentException("Invalid value: " + joinByVal + " for annotation @JoinBy on property '" + joinPropInfo.name + "' in class: "
+ entityClass + ". No property found with name: '" + tmp[0] + "' in the class: " + entityClass);
}
if ((referencedPropInfos[i] = referencedEntityInfo.getPropInfo(tmp.length == 1 ? tmp[0] : tmp[1])) == null) {
throw new IllegalArgumentException("Invalid value: " + joinByVal + " for annotation @JoinBy on property '" + joinPropInfo.name + "' in class: "
+ entityClass + ". No referenced property found with name: '" + (tmp.length == 1 ? tmp[0] : tmp[1]) + "' in the class: "
+ referencedEntityClass);
}
conds.add(CF.eq(referencedPropInfos[i].name));
}
final Condition cond = joinColumnPairs.length == 1 ? conds.get(0) : CF.and(conds);
final BiParametersSetter paramSetter = srcPropInfos.length == 1
? (stmt, entityParam) -> srcPropInfos[0].dbType.set(stmt, 1, srcPropInfos[0].getPropValue(entityParam))
: (srcPropInfos.length == 2 ? (stmt, entityParam) -> {
srcPropInfos[0].dbType.set(stmt, 1, srcPropInfos[0].getPropValue(entityParam));
srcPropInfos[1].dbType.set(stmt, 2, srcPropInfos[1].getPropValue(entityParam));
} : (stmt, entityParam) -> {
for (int i = 0, len = srcPropInfos.length; i < len; i++) {
srcPropInfos[i].dbType.set(stmt, i + 1, srcPropInfos[i].getPropValue(entityParam));
}
});
final BiParametersSetter> paramSetter2 = srcPropInfos.length == 1 ? (stmt, entities) -> {
int index = 1;
for (Object entity : entities) {
srcPropInfos[0].dbType.set(stmt, index++, srcPropInfos[0].getPropValue(entity));
}
} : (stmt, entities) -> {
int index = 1;
for (Object entity : entities) {
for (int i = 0, len = srcPropInfos.length; i < len; i++) {
srcPropInfos[i].dbType.set(stmt, index++, srcPropInfos[i].getPropValue(entity));
}
}
};
{
final String sql = PSC.selectFrom(referencedEntityClass).where(cond).sql();
final Function, String> sqlBuilder = selectPropNames -> {
if (N.isNullOrEmpty(selectPropNames)) {
return sql;
} else {
return PSC.select(selectPropNames).from(referencedEntityClass).where(cond).sql();
}
};
sqlBuilderSetterForSingleEntityMap.put(PSC.class, Tuple.of(sqlBuilder, paramSetter));
final BiFunction, Integer, String> sqlBuilder2 = (selectPropNames, size) -> {
if (size == 1) {
return sqlBuilder.apply(selectPropNames);
} else {
if (N.isNullOrEmpty(selectPropNames)) {
return PSC.selectFrom(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
} else {
return PSC.select(selectPropNames).from(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
}
}
};
sqlBuilderSetterForEntitiesMap.put(PSC.class, Tuple.of(sqlBuilder2, paramSetter2));
}
{
final String sql = PAC.selectFrom(referencedEntityClass).where(cond).sql();
final Function, String> sqlBuilder = selectPropNames -> {
if (N.isNullOrEmpty(selectPropNames)) {
return sql;
} else {
return PAC.select(selectPropNames).from(referencedEntityClass).where(cond).sql();
}
};
sqlBuilderSetterForSingleEntityMap.put(PAC.class, Tuple.of(sqlBuilder, paramSetter));
final BiFunction, Integer, String> sqlBuilder2 = (selectPropNames, size) -> {
if (size == 1) {
return sqlBuilder.apply(selectPropNames);
} else {
if (N.isNullOrEmpty(selectPropNames)) {
return PAC.selectFrom(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
} else {
return PAC.select(selectPropNames).from(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
}
}
};
sqlBuilderSetterForEntitiesMap.put(PAC.class, Tuple.of(sqlBuilder2, paramSetter2));
}
{
final String sql = PLC.selectFrom(referencedEntityClass).where(cond).sql();
final Function, String> sqlBuilder = selectPropNames -> {
if (N.isNullOrEmpty(selectPropNames)) {
return sql;
} else {
return PLC.select(selectPropNames).from(referencedEntityClass).where(cond).sql();
}
};
sqlBuilderSetterForSingleEntityMap.put(PLC.class, Tuple.of(sqlBuilder, paramSetter));
final BiFunction, Integer, String> sqlBuilder2 = (selectPropNames, size) -> {
if (size == 1) {
return sqlBuilder.apply(selectPropNames);
} else {
if (N.isNullOrEmpty(selectPropNames)) {
return PLC.selectFrom(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
} else {
return PLC.select(selectPropNames).from(referencedEntityClass).where(CF.or(N.repeat(cond, size))).sql();
}
}
};
sqlBuilderSetterForEntitiesMap.put(PLC.class, Tuple.of(sqlBuilder2, paramSetter2));
}
Function srcEntityKeyExtractorTmp = null;
Function referencedEntityKeyExtractorTmp = null;
if (srcPropInfos.length == 1) {
final PropInfo srcPropInfo = srcPropInfos[0];
final PropInfo referencedPropInfo = referencedPropInfos[0];
srcEntityKeyExtractorTmp = entity -> srcPropInfo.getPropValue(entity);
referencedEntityKeyExtractorTmp = entity -> referencedPropInfo.getPropValue(entity);
} else if (srcPropInfos.length == 2) {
final PropInfo srcPropInfo_1 = srcPropInfos[0];
final PropInfo srcPropInfo_2 = srcPropInfos[1];
final PropInfo referencedPropInfo_1 = referencedPropInfos[0];
final PropInfo referencedPropInfo_2 = referencedPropInfos[1];
srcEntityKeyExtractorTmp = entity -> Tuple.of(srcPropInfo_1.getPropValue(entity), srcPropInfo_2.getPropValue(entity));
referencedEntityKeyExtractorTmp = entity -> Tuple.of(referencedPropInfo_1.getPropValue(entity), referencedPropInfo_2.getPropValue(entity));
} else if (srcPropInfos.length == 3) {
final PropInfo srcPropInfo_1 = srcPropInfos[0];
final PropInfo srcPropInfo_2 = srcPropInfos[1];
final PropInfo srcPropInfo_3 = srcPropInfos[2];
final PropInfo referencedPropInfo_1 = referencedPropInfos[0];
final PropInfo referencedPropInfo_2 = referencedPropInfos[1];
final PropInfo referencedPropInfo_3 = referencedPropInfos[2];
srcEntityKeyExtractorTmp = entity -> Tuple.of(srcPropInfo_1.getPropValue(entity), srcPropInfo_2.getPropValue(entity),
srcPropInfo_3.getPropValue(entity));
referencedEntityKeyExtractorTmp = entity -> Tuple.of(referencedPropInfo_1.getPropValue(entity), referencedPropInfo_2.getPropValue(entity),
referencedPropInfo_3.getPropValue(entity));
} else {
srcEntityKeyExtractorTmp = entity -> {
final List keys = new ArrayList<>(srcPropInfos.length);
for (PropInfo srcPropInfo : srcPropInfos) {
keys.add(srcPropInfo.getPropValue(entity));
}
return keys;
};
referencedEntityKeyExtractorTmp = entity -> {
final List keys = new ArrayList<>(referencedPropInfos.length);
for (PropInfo referencedPropInfo : referencedPropInfos) {
keys.add(referencedPropInfo.getPropValue(entity));
}
return keys;
};
}
srcEntityKeyExtractor = srcEntityKeyExtractorTmp;
referencedEntityKeyExtractor = referencedEntityKeyExtractorTmp;
}
public Tuple2, String>, BiParametersSetter> getSQLBuilderSetterForSingleEntity(
final Class extends SQLBuilder> sbc) {
final Tuple2, String>, BiParametersSetter> tp = sqlBuilderSetterForSingleEntityMap.get(sbc);
if (tp == null) {
throw new IllegalArgumentException("Not supported SQLBuilder class: " + ClassUtil.getCanonicalClassName(sbc));
}
return tp;
}
public Tuple2, Integer, String>, BiParametersSetter>> getSQLBuilderSetterForEntities(
final Class extends SQLBuilder> sbc) {
final Tuple2, Integer, String>, BiParametersSetter>> tp = sqlBuilderSetterForEntitiesMap
.get(sbc);
if (tp == null) {
throw new IllegalArgumentException("Not supported SQLBuilder class: " + ClassUtil.getCanonicalClassName(sbc));
}
return tp;
}
public void setJoinPropEntities(final Collection> entities, final Collection> joinPropEntities) {
final Map> groupedPropEntities = Stream.of((Collection) joinPropEntities).groupTo(referencedEntityKeyExtractor);
final boolean isDirtyMarker = DirtyMarkerUtil.isDirtyMarker(entityClass);
final boolean isCollectionProp = joinPropInfo.type.isCollection();
final boolean isListProp = joinPropInfo.clazz.isAssignableFrom(List.class);
List propEntities = null;
for (Object entity : entities) {
propEntities = groupedPropEntities.get(srcEntityKeyExtractor.apply(entity));
if (propEntities != null) {
if (isCollectionProp) {
if (isListProp || joinPropInfo.clazz.isAssignableFrom(propEntities.getClass())) {
joinPropInfo.setPropValue(entity, propEntities);
} else {
final Collection c = (Collection) N.newInstance(joinPropInfo.clazz);
c.addAll(propEntities);
joinPropInfo.setPropValue(entity, c);
}
} else {
joinPropInfo.setPropValue(entity, propEntities.get(0));
}
if (isDirtyMarker) {
DirtyMarkerUtil.markDirty((DirtyMarker) entity, joinPropInfo.name, false);
}
}
}
}
private final static Map, Map> entityJoinInfoPool = new ConcurrentHashMap<>();
public static Map getEntityJoinInfo(final Class> entityClass) {
Map joinInfoMap = entityJoinInfoPool.get(entityClass);
if (joinInfoMap == null) {
final EntityInfo entityInfo = ParserUtil.getEntityInfo(entityClass);
joinInfoMap = new LinkedHashMap<>();
for (PropInfo propInfo : entityInfo.propInfoList) {
if (!propInfo.isAnnotationPresent(JoinedBy.class)) {
continue;
}
joinInfoMap.put(propInfo.name, new JoinInfo(entityClass, propInfo.name));
}
entityJoinInfoPool.put(entityClass, joinInfoMap);
}
return joinInfoMap;
}
public static JoinInfo getPropJoinInfo(final Class> entityClass, final String joinEntityPropName) {
final JoinInfo joinInfo = getEntityJoinInfo(entityClass).get(joinEntityPropName);
if (joinInfo == null) {
throw new IllegalArgumentException(
"No join property found by name '" + joinEntityPropName + "' in class: " + ClassUtil.getCanonicalClassName(entityClass));
}
return joinInfo;
}
private final static Map, Map, List>> joinEntityPropNamesByTypePool = new ConcurrentHashMap<>();
public static List getJoinEntityPropNamesByType(final Class> entityClass, final Class> joinPropEntityClass) {
Map, List> joinEntityPropNamesByTypeMap = joinEntityPropNamesByTypePool.get(entityClass);
if (joinEntityPropNamesByTypeMap == null) {
joinEntityPropNamesByTypeMap = new HashMap<>();
List joinPropNames = null;
for (JoinInfo joinInfo : getEntityJoinInfo(entityClass).values()) {
joinPropNames = joinEntityPropNamesByTypeMap.get(joinInfo.referencedEntityClass);
if (joinPropNames == null) {
joinPropNames = new ArrayList<>(1);
joinEntityPropNamesByTypeMap.put(joinInfo.referencedEntityClass, joinPropNames);
}
joinPropNames.add(joinInfo.joinPropInfo.name);
}
joinEntityPropNamesByTypePool.put(entityClass, joinEntityPropNamesByTypeMap);
}
return joinEntityPropNamesByTypeMap.getOrDefault(joinPropEntityClass, N. emptyList());
}
}