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.
shz.core.orm.AbstractOrmService Maven / Gradle / Ivy
package shz.core.orm;
import shz.core.*;
import shz.core.constant.ArrayConstant;
import shz.core.function.ActionRunner;
import shz.core.model.PageInfo;
import shz.core.model.TreeNode;
import shz.core.msg.ClientFailureMsg;
import shz.core.orm.entity.TreeEntity;
import shz.core.orm.param.OrmConsumer;
import shz.core.orm.param.OrmFilter;
import shz.core.orm.param.OrmMapConsumer;
import shz.core.orm.param.OrmMapFilter;
import shz.core.orm.param.OrmMapping;
import shz.core.orm.service.*;
import shz.core.reference.IReference;
import shz.core.reference.LReference;
import shz.core.reference.ZReference;
import shz.core.serializable.SerializableGetter;
import shz.core.serializable.Serializer;
import shz.core.structure.limiter.Limiter;
import shz.core.tag.ixx.ILTag;
import shz.core.orm.enums.Condition;
import shz.core.orm.enums.DataType;
import shz.core.orm.sql.Sql;
import shz.core.orm.sql.ValueType;
import shz.core.orm.sql.WhereSql;
import shz.core.orm.sql.builder.SqlBuilder;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
abstract class AbstractOrmService extends OrmServiceHelper
implements OrmInsertService, OrmUpdateService, OrmInsertOrUpdateService, OrmDeleteService,
OrmCursorService, OrmCountService, OrmSelectListService, OrmPageService, OrmSelectOneService, OrmTreeService {
public final ClassInfo classInfo(Class> entityClass) {
ClassInfo classInfo = ClassInfo.CLASS_INFO_CACHE.get(entityClass);
if (classInfo == null) classInfo = ClassInfo.load(entityClass, this);
return classInfo;
}
public final ClassInfo nonNullClassInfo(Class> entityClass) {
return Objects.requireNonNull(classInfo(entityClass));
}
public final WhereSql whereSql(ClassInfo classInfo, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return WhereInfo.where(classInfo, fieldName, fieldValue, condition, this::builder, logic);
}
public final WhereSql whereSql(ClassInfo classInfo, List fieldNames, List fieldValues, List conditions, Boolean logic) {
return WhereInfo.where(classInfo, fieldNames, fieldValues, conditions, this::builder, logic);
}
public final WhereSql whereSql(ClassInfo classInfo, List fieldNames, List fieldValues, Condition condition, Boolean logic) {
return WhereInfo.where(classInfo, fieldNames, fieldValues, condition, this::builder, logic);
}
public final WhereSql whereSql(ClassInfo classInfo, Object obj, List conditions, Boolean logic, boolean orderBy, String... fieldNames) {
return WhereInfo.where(classInfo, obj, conditions, this::builder, logic, orderBy, fieldNames);
}
public final WhereSql whereSql(ClassInfo classInfo, Object obj, Condition condition, Boolean logic, boolean orderBy, String... fieldNames) {
return WhereInfo.where(classInfo, obj, condition, this::builder, logic, orderBy, fieldNames);
}
public final WhereSql whereSql(ClassInfo classInfo, Object obj, Boolean logic, boolean orderBy) {
return WhereInfo.where(classInfo, obj, this::builder, logic, orderBy);
}
public final WhereSql whereSql(Class> entityClass, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return WhereInfo.where(nonNullClassInfo(entityClass), fieldName, fieldValue, condition, this::builder, logic);
}
public final WhereSql whereSql(Class> entityClass, List fieldNames, List fieldValues, List conditions, Boolean logic) {
return WhereInfo.where(nonNullClassInfo(entityClass), fieldNames, fieldValues, conditions, this::builder, logic);
}
public final WhereSql whereSql(Class> entityClass, List fieldNames, List fieldValues, Condition condition, Boolean logic) {
return WhereInfo.where(nonNullClassInfo(entityClass), fieldNames, fieldValues, condition, this::builder, logic);
}
public final WhereSql whereSql(Class> entityClass, Object obj, List conditions, Boolean logic, boolean orderBy, String... fieldNames) {
return WhereInfo.where(nonNullClassInfo(entityClass), obj, conditions, this::builder, logic, orderBy, fieldNames);
}
public final WhereSql whereSql(Class> entityClass, Object obj, Condition condition, Boolean logic, boolean orderBy, String... fieldNames) {
return WhereInfo.where(nonNullClassInfo(entityClass), obj, condition, this::builder, logic, orderBy, fieldNames);
}
public final WhereSql whereSql(Class> entityClass, Object obj, Boolean logic, boolean orderBy) {
return WhereInfo.where(nonNullClassInfo(entityClass), obj, this::builder, logic, orderBy);
}
public abstract int[] executeBatch(int batchSize, String sql, List values);
public abstract int[] executeBatch(int batchSize, String... sqls);
///////////////////////////////////////////////OrmInsertService
@Override
public final int insert(Tnp tnp, Object entity, List fieldNames) {
return entity == null ? 0 : insert(tnp, MetaObject.of(entity, nonNullClassInfo(entity.getClass()), fieldNames));
}
private int insert(Tnp tnp, MetaObject metaObject) {
insertFill(metaObject);
backId(metaObject);
SqlBuilder builder = builder();
List columns = metaObject.columnsForInsert();
String sql = builder.insert(tnp == null ? metaObject.classInfo.tnp : tnp, columns, columns, ValueType.PLACEHOLDER, false);
return metaObject.classInfo.auto ? insert(metaObject::setId, sql, metaObject.values(columns).toArray()) : update(sql, metaObject.values(columns).toArray());
}
protected abstract int insert(Consumer idSetter, String sql, Object... params);
@Override
public final int[] batchInsert(Tnp tnp, List> entities, List fieldNames, int batchSize) {
if (NullHelp.isAnyNull(entities)) return ArrayConstant.EMPTY_INT_ARRAY;
return batchInsert(tnp, MetaObject.of(entities, nonNullClassInfo(entities.get(0).getClass()), fieldNames), batchSize, NullHelp.nonEmpty(fieldNames));
}
int[] batchInsert(Tnp tnp, List metaObjects, int batchSize, boolean force) {
if (metaObjects.isEmpty()) return ArrayConstant.EMPTY_INT_ARRAY;
metaObjects.forEach(meta -> {
insertFill(meta);
backId(meta);
});
if (force) {
SqlBuilder builder = builder();
MetaObject metaObject = metaObjects.get(0);
List columns = metaObject.columnsForInsert();
String sql = builder.insert(tnp == null ? metaObject.classInfo.tnp : tnp, columns, columns, ValueType.PLACEHOLDER, true);
if (metaObject.classInfo.auto) return batchInsert((idx, id) -> {
MetaObject meta = metaObjects.get(idx);
if (meta != null) meta.setId(id);
}, batchSize, sql, ToList.explicitCollect(metaObjects.stream().map(meta -> meta.values(columns).toArray()), metaObjects.size()));
return executeBatch(batchSize, sql, ToList.explicitCollect(metaObjects.stream().map(meta -> meta.values(columns).toArray()), metaObjects.size()));
}
Tnp tnp1 = tnp == null ? metaObjects.get(0).classInfo.tnp : tnp;
return executeBatch(batchSize, metaObjects.stream().map(meta -> {
SqlBuilder builder = builder();
List columns = meta.columnsForInsert();
return builder.insert(tnp1, columns, meta.values(columns), ValueType.ESCAPE, true);
}).toArray(String[]::new));
}
protected abstract int[] batchInsert(BiConsumer idSetter, int batchSize, String sql, List values);
///////////////////////////////////////////////OrmInsertService
///////////////////////////////////////////////OrmUpdateService
@Override
public final int update(Tnp tnp, Object entity, List fieldNames, WhereSql whereSql) {
return entity == null ? 0 : update(tnp, MetaObject.of(entity, nonNullClassInfo(entity.getClass()), fieldNames), whereSql);
}
private int update(Tnp tnp, MetaObject metaObject, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return 0;
checkVersion(metaObject);
updateFill(metaObject);
List columns = metaObject.columnsForUpdate();
SqlBuilder builder = builder().update(tnp == null ? metaObject.classInfo.tnp : tnp, columns, columns, ValueType.PLACEHOLDER, false);
if (metaObject.classInfo.versionField != null)
builder.comma().wrap(metaObject.classInfo.versionName).eq(metaObject.classInfo.versionName, ValueType.WRAP).plus().append('1');
List params = null;
if (whereSql != null) {
String whereSql0 = whereSql.value();
if (metaObject.classInfo.versionField != null) {
if (NullHelp.isBlank(whereSql0)) builder.where();
else builder.space().append(whereSql0).and();
builder.wrap(metaObject.classInfo.versionName).eq();
List params0 = whereSql.params();
if (NullHelp.isEmpty(params0)) params = ToList.get(1).add(metaObject.getVersion()).build();
else params = ToList.get(params0.size() + 1).add(params0).add(metaObject.getVersion()).build();
} else {
builder.space().append(whereSql0);
params = whereSql.params();
}
} else if (metaObject.classInfo.versionField != null) {
builder.where().wrap(metaObject.classInfo.versionName).eq();
params = ToList.get(1).add(metaObject.getVersion()).build();
}
return update(builder.build(), metaObject.values(columns, params).toArray());
}
private void checkVersion(MetaObject metaObject) {
ClientFailureMsg.requireNon(metaObject.classInfo.versionField != null && NullHelp.isBlank(metaObject.getVersion()), "数据缺失版本号");
}
@Override
public final int updateByColumn(Tnp tnp, Object entity, List fieldNames, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return entity == null ? 0 : update(tnp, entity, fieldNames, whereSql(nonNullClassInfo(entity.getClass()), fieldName, fieldValue, condition, logic));
}
@Override
public final int updateById(Tnp tnp, Object entity, List fieldNames) {
return entity == null ? 0 : updateById(tnp, MetaObject.of(entity, nonNullClassInfo(entity.getClass()), fieldNames));
}
private int updateById(Tnp tnp, MetaObject metaObject) {
if (NullHelp.isBlank(metaObject.getId())) return 0;
checkVersion(metaObject);
updateFill(metaObject);
List columns = metaObject.columnsForUpdate();
String sql = updateByIdSql(tnp, metaObject, columns, columns, ValueType.PLACEHOLDER, false);
Object[] params = updateByIdParams(metaObject, metaObject.values(columns));
return update(sql, params);
}
private String updateByIdSql(Tnp tnp, MetaObject metaObject, List columns, List> values, ValueType type, boolean ignore) {
SqlBuilder builder = builder().update(tnp == null ? metaObject.classInfo.tnp : tnp, columns, values, type, ignore);
if (metaObject.classInfo.versionField != null)
builder.comma().wrap(metaObject.classInfo.versionName).eq(metaObject.classInfo.versionName, ValueType.WRAP).plus().append('1');
builder.where();
if (metaObject.classInfo.versionField != null)
builder.wrap(metaObject.classInfo.versionName).eq(metaObject.getVersion(), type).and();
return builder.wrap(metaObject.classInfo.idName).eq(metaObject.getId(), type).build();
}
private Object[] updateByIdParams(MetaObject metaObject, List> values) {
List result = ToList.get(values.size() + 2).add(values).build();
if (metaObject.classInfo.versionField != null) result.add(metaObject.getVersion());
result.add(metaObject.getId());
return result.toArray();
}
@Override
public final int[] batchUpdateById(Tnp tnp, List> entities, List fieldNames, int batchSize) {
if (NullHelp.isAnyNull(entities)) return ArrayConstant.EMPTY_INT_ARRAY;
return batchUpdateById(tnp, MetaObject.of(entities, nonNullClassInfo(entities.get(0).getClass()), fieldNames), batchSize, NullHelp.nonEmpty(fieldNames));
}
int[] batchUpdateById(Tnp tnp, List metaObjects, int batchSize, boolean force) {
if (metaObjects.isEmpty()) return ArrayConstant.EMPTY_INT_ARRAY;
metaObjects.forEach(meta -> {
checkVersion(meta);
updateFill(meta);
});
if (force) {
MetaObject metaObject = metaObjects.get(0);
List columns = metaObject.columnsForUpdate();
String sql = updateByIdSql(tnp, metaObject, columns, columns, ValueType.PLACEHOLDER, true);
return executeBatch(batchSize, sql, ToList.explicitCollect(metaObjects.stream().map(meta -> updateByIdParams(meta, meta.values(columns))), metaObjects.size()));
}
return executeBatch(batchSize, metaObjects.stream().map(meta -> {
List columns = meta.columnsForUpdate();
return updateByIdSql(tnp, meta, columns, meta.values(columns), ValueType.ESCAPE, true);
}).toArray(String[]::new));
}
///////////////////////////////////////////////OrmUpdateService
///////////////////////////////////////////////OrmInsertOrUpdateService
@Override
public final int insertOrUpdate(Tnp tnp, Object entity, List fieldNames, Boolean logic, String... uniqueFields) {
if (entity == null) return 0;
ClassInfo classInfo = nonNullClassInfo(entity.getClass());
return insertOrUpdate(tnp, MetaObject.of(setId(tnp, classInfo, entity, logic, uniqueFields), classInfo, fieldNames));
}
private int insertOrUpdate(Tnp tnp, MetaObject metaObject) {
return metaObject.existId ? updateById(tnp, metaObject) : insert(tnp, metaObject);
}
private Object setId(Tnp tnp, ClassInfo classInfo, Object entity, Boolean logic, String... uniqueFields) {
if (NullHelp.isEmpty(uniqueFields)) return entity;
Object id = classInfo.getId(entity);
if (NullHelp.nonBlank(id)) return entity;
WhereSql whereSql = null;
if (uniqueFields.length == 1) {
if (!classInfo.idField.getName().equals(uniqueFields[0]))
whereSql = whereSql(classInfo, uniqueFields[0], classInfo.getByName(uniqueFields[0], entity), Condition.EQ, logic);
} else {
List fieldNames = new ArrayList<>(uniqueFields.length);
List fieldValues = new ArrayList<>(uniqueFields.length);
for (String uniqueField : uniqueFields) {
if (classInfo.idField.getName().equals(uniqueField)) continue;
fieldNames.add(uniqueField);
fieldValues.add(classInfo.getByName(uniqueField, entity));
}
if (!fieldNames.isEmpty()) whereSql = whereSql(classInfo, fieldNames, fieldValues, Condition.EQ, logic);
}
if (whereSql != null) {
Object oldEntity = selectOne(tnp, classInfo.cls, true, Collections.singletonList(classInfo.idField.getName()), whereSql);
if (oldEntity != null) classInfo.setId(entity, classInfo.getId(oldEntity));
}
return entity;
}
@Override
public final int insertOrUpdateMultiUnique(Tnp tnp, T entity, List> fieldNames, Boolean logic, List[]> uniqueFields) {
if (entity == null) return 0;
ClassInfo classInfo = nonNullClassInfo(entity.getClass());
if (NullHelp.nonEmpty(uniqueFields)) for (SerializableGetter[] ufs : uniqueFields)
setId(tnp, classInfo, entity, logic, Serializer.getFieldNameArray(ufs));
return insertOrUpdate(tnp, MetaObject.of(entity, classInfo, Serializer.getFieldNames(fieldNames)));
}
@Override
public final int[] batchInsertOrUpdate(Tnp tnp, List> entities, List fieldNames, Boolean logic, int batchSize, String... uniqueFields) {
ClientFailureMsg.requireNonAnyNull(entities, "批量插入集合不允许存在空元素");
ClassInfo classInfo = nonNullClassInfo(entities.get(0).getClass());
return batchInsertOrUpdate(tnp, MetaObject.of(setIds(tnp, classInfo, entities, logic, uniqueFields), classInfo, fieldNames), batchSize, NullHelp.nonEmpty(fieldNames));
}
private int[] batchInsertOrUpdate(Tnp tnp, List metaObjects, int batchSize, boolean force) {
int len = metaObjects.size();
if (len == 0) return ArrayConstant.EMPTY_INT_ARRAY;
int[] result = new int[len];
List inserts = new LinkedList<>(), updates = new LinkedList<>();
for (int i = 0; i < len; ++i) {
MetaObject meta = metaObjects.get(i);
if (meta.existId) {
updates.add(meta);
result[i] = -1;
} else inserts.add(meta);
}
int[] insertResult = batchInsert(tnp, inserts, batchSize, force);
int[] updateResult = batchUpdateById(tnp, updates, batchSize, force);
return merge(result, insertResult, updateResult);
}
private int[] merge(int[] result, int[] insertResult, int[] updateResult) {
int ulen = updateResult.length, ilen = insertResult.length;
if (ulen == 0) return insertResult;
else if (ilen == 0) return updateResult;
int uidx = 0, iidx = 0;
int len = result.length, i = 0;
for (; i < len; ++i) {
if (result[i] == -1) {
result[i] = updateResult[uidx++];
if (uidx == ulen) break;
} else {
result[i] = insertResult[iidx++];
if (iidx == ilen) break;
}
}
if (uidx == ulen) System.arraycopy(insertResult, iidx, result, i + 1, ilen - iidx);
else System.arraycopy(updateResult, uidx, result, i + 1, ulen - uidx);
return result;
}
private List> setIds(Tnp tnp, ClassInfo classInfo, List> entities, Boolean logic, String... uniqueFields) {
if (NullHelp.isEmpty(uniqueFields)) return entities;
List> nonIdEntities = ToList.explicitCollect(entities.stream().filter(entity -> classInfo.getId(entity) == null), entities.size());
int nonIdEntitiesSize = nonIdEntities.size();
if (nonIdEntitiesSize == 0) return entities;
if (uniqueFields.length == 1) {
if (!classInfo.idField.getName().equals(uniqueFields[0])) {
Map> uniqueValEntityMap = ToMap.get(nonIdEntitiesSize, 1).build();
Field uniqueField = classInfo.getFieldByName(uniqueFields[0]);
for (Object entity : nonIdEntities)
uniqueValEntityMap.computeIfAbsent(AccessibleHelp.getField(uniqueField, entity), k -> ToSet.get(nonIdEntitiesSize, 1).build()).add(entity);
if (!uniqueValEntityMap.isEmpty()) {
WhereSql whereSql = whereSql(classInfo, uniqueFields[0], uniqueValEntityMap.keySet(), Condition.IN, logic);
if (whereSql != null) query(tnp, classInfo.cls, null, null, null, entity -> {
Set newEntities = uniqueValEntityMap.get(AccessibleHelp.getField(uniqueField, entity));
if (newEntities != null) {
Object id = classInfo.getId(entity);
newEntities.forEach(newEntity -> classInfo.setId(newEntity, id));
}
}, Integer.MAX_VALUE, Arrays.asList(classInfo.idField.getName(), uniqueFields[0]), whereSql);
}
}
} else {
List uniqueFieldNames = new ArrayList<>(uniqueFields.length);
for (String uniqueField : uniqueFields)
if (!classInfo.idField.getName().equals(uniqueField)) uniqueFieldNames.add(uniqueField);
int uniqueFieldSize = uniqueFieldNames.size();
if (uniqueFieldSize > 0) {
Map> uniqueFieldFieldValesMap = ToMap.get(uniqueFieldSize).build();
Map uniqueValEntityMap = ToMap.get(nonIdEntitiesSize, uniqueFieldSize).build();
for (Object entity : nonIdEntities) {
Map uniqueValEntityMapRef = uniqueValEntityMap;
for (int i = 0; i < uniqueFieldSize - 1; ++i) {
String uniqueField = uniqueFieldNames.get(i);
Object uniqueVal = classInfo.getByName(uniqueField, entity);
uniqueFieldFieldValesMap.computeIfAbsent(uniqueField, k -> ToSet.get(nonIdEntitiesSize, uniqueFieldSize).build()).add(uniqueVal);
uniqueValEntityMapRef = (Map) uniqueValEntityMapRef.computeIfAbsent(uniqueVal, k -> ToMap.get(nonIdEntitiesSize, uniqueFieldSize).build());
}
String uniqueField = uniqueFieldNames.get(uniqueFieldSize - 1);
Object uniqueVal = classInfo.getByName(uniqueField, entity);
uniqueFieldFieldValesMap.computeIfAbsent(uniqueField, k -> ToSet.get(nonIdEntitiesSize, uniqueFieldSize).build()).add(uniqueVal);
uniqueValEntityMapRef.put(uniqueVal, entity);
}
List uniqueFieldValues = ToList.explicitCollect(uniqueFieldNames.stream().map(uniqueFieldFieldValesMap::get), uniqueFieldSize);
WhereSql whereSql = whereSql(classInfo, uniqueFieldNames, uniqueFieldValues, Condition.IN, logic);
if (whereSql != null) {
List fieldNames = new ArrayList<>(uniqueFieldSize + 1);
fieldNames.add(classInfo.idField.getName());
fieldNames.addAll(ToSet.asSet(uniqueFieldNames));
query(tnp, classInfo.cls, null, null, null, entity -> {
Map uniqueValEntityMapRef = uniqueValEntityMap;
for (int i = 0; i < uniqueFieldSize - 1; ++i) {
if (uniqueValEntityMapRef == null) return;
uniqueValEntityMapRef = (Map) uniqueValEntityMapRef.get(classInfo.getByName(uniqueFieldNames.get(i), entity));
}
if (uniqueValEntityMapRef != null) {
Object newEntity = uniqueValEntityMapRef.get(classInfo.getByName(uniqueFieldNames.get(uniqueFieldSize - 1), entity));
if (newEntity != null) classInfo.setId(newEntity, classInfo.getId(entity));
}
}, Integer.MAX_VALUE, fieldNames, whereSql);
}
}
}
return entities;
}
@Override
public final int[] batchInsertOrUpdateMultiUnique(Tnp tnp, List entities, List> fieldNames, Boolean logic, int batchSize, List[]> uniqueFields) {
ClientFailureMsg.requireNonAnyNull(entities, "批量插入集合不允许存在空元素");
ClassInfo classInfo = nonNullClassInfo(entities.get(0).getClass());
if (NullHelp.nonEmpty(uniqueFields)) for (SerializableGetter[] ufs : uniqueFields)
setIds(tnp, classInfo, entities, logic, Serializer.getFieldNameArray(ufs));
return batchInsertOrUpdate(tnp, MetaObject.of(entities, classInfo, Serializer.getFieldNames(fieldNames)), batchSize, NullHelp.nonEmpty(fieldNames));
}
///////////////////////////////////////////////OrmInsertOrUpdateService
///////////////////////////////////////////////OrmDeleteService
@Override
public final int delete(Tnp tnp, Class> entityClass, WhereSql whereSql, Boolean logic) {
return delete(tnp, nonNullClassInfo(entityClass), whereSql, logic);
}
private int delete(Tnp tnp, ClassInfo classInfo, WhereSql whereSql, Boolean logic) {
if (whereSql == WhereSql.EMPTY) return 0;
tnp = tnp == null ? classInfo.tnp : tnp;
SqlBuilder builder = builder();
if (logic == null ? classInfo.logicField != null : logic) {
if (classInfo.logicDelVal == null)
builder.update(tnp, Collections.singletonList(classInfo.logicName), Collections.singletonList(classInfo.idName), ValueType.WRAP, false);
else
builder.update(tnp, Collections.singletonList(classInfo.logicName), Collections.singletonList(classInfo.logicDelVal), ValueType.ESCAPE, false);
} else builder.delete(tnp);
Object[] params = ArrayConstant.EMPTY_OBJECT_ARRAY;
if (whereSql != null) {
builder.space().append(whereSql.value());
List whereParams = whereSql.params();
if (NullHelp.nonEmpty(whereParams)) params = whereParams.toArray();
}
return update(builder.build(), params);
}
@Override
public final int deleteByColumn(Tnp tnp, Class> entityClass, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
ClassInfo classInfo = nonNullClassInfo(entityClass);
return delete(tnp, classInfo, whereSql(classInfo, fieldName, fieldValue, condition, Boolean.FALSE), logic);
}
@Override
public final int deleteByIds(Tnp tnp, Class> entityClass, Collection> ids, Boolean logic) {
ClassInfo classInfo = nonNullClassInfo(entityClass);
return delete(tnp, classInfo, whereSql(classInfo, classInfo.idField.getName(), ids, Condition.IN, Boolean.FALSE), logic);
}
@Override
public final int deleteByIds(Tnp tnp, Collection> entities, Boolean logic) {
if (NullHelp.isAnyNull(entities)) return 0;
ClassInfo classInfo = nonNullClassInfo(entities.iterator().next().getClass());
return delete(tnp, classInfo, whereSql(classInfo, classInfo.idField.getName(), ToSet.explicitCollect(entities.stream().map(classInfo::getId), entities.size()), Condition.IN, Boolean.FALSE), logic);
}
@Override
public final int deleteById(Tnp tnp, Class> entityClass, Object id, Boolean logic) {
return deleteById(tnp, nonNullClassInfo(entityClass), id, logic);
}
private int deleteById(Tnp tnp, ClassInfo classInfo, Object id, Boolean logic) {
return update(deleteByIdSql(tnp, classInfo, logic, false), id);
}
private String deleteByIdSql(Tnp tnp, ClassInfo classInfo, Boolean logic, boolean ignore) {
tnp = tnp == null ? classInfo.tnp : tnp;
SqlBuilder builder = builder();
if (logic == null ? classInfo.logicField != null : logic) {
if (classInfo.logicDelVal == null)
builder.update(tnp, Collections.singletonList(classInfo.logicName), Collections.singletonList(classInfo.idName), ValueType.WRAP, ignore);
else
builder.update(tnp, Collections.singletonList(classInfo.logicName), Collections.singletonList(classInfo.logicDelVal), ValueType.ESCAPE, ignore);
} else builder.delete(tnp);
return builder.where().wrap(classInfo.idName).eq().build();
}
@Override
public final int deleteById(Tnp tnp, Object entity, Boolean logic) {
if (entity == null) return 0;
ClassInfo classInfo = nonNullClassInfo(entity.getClass());
return deleteById(tnp, classInfo, classInfo.getId(entity), logic);
}
@Override
public final int[] batchDeleteById(Tnp tnp, Class> entityClass, List> ids, Boolean logic, int batchSize) {
return batchDeleteById(tnp, nonNullClassInfo(entityClass), ids, logic, batchSize);
}
private int[] batchDeleteById(Tnp tnp, ClassInfo classInfo, List> ids, Boolean logic, int batchSize) {
if (NullHelp.isEmpty(ids)) return ArrayConstant.EMPTY_INT_ARRAY;
return executeBatch(batchSize, deleteByIdSql(tnp, classInfo, logic, true), ToList.explicitCollect(ids.stream().map(id -> new Object[]{id}), ids.size()));
}
@Override
public final int[] batchDeleteById(Tnp tnp, List> entities, Boolean logic, int batchSize) {
if (NullHelp.isAnyNull(entities)) return ArrayConstant.EMPTY_INT_ARRAY;
ClassInfo classInfo = nonNullClassInfo(entities.get(0).getClass());
return batchDeleteById(tnp, classInfo, ToList.explicitCollect(entities.stream().map(classInfo::getId), entities.size()), logic, batchSize);
}
///////////////////////////////////////////////OrmDeleteService
///////////////////////////////////////////////OrmCursorService
@Override
public final void query(OrmMapping mapping, Type type, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> consumer, int fetchSize, String sql, Object... params) {
NullHelp.requireNon(mapFilter == null && filter == null && consumer == null);
OrmMapConsumer mapConsumer;
if (filter == null && consumer == null) mapConsumer = null;
else {
DataType dataType = dataType(type);
mapConsumer = map -> {
if (limiter != null) {
if (limiter.isLimit()) return;
if (filter == null) {
if (!limiter.isLimitBefore()) consumer.accept(dataType.parse(type, map));
} else {
T t = dataType.parse(type, map);
if (filter.test(t) && !limiter.isLimitBefore() && consumer != null) consumer.accept(t);
}
} else {
T t = dataType.parse(type, map);
if ((filter == null || filter.test(t)) && consumer != null) consumer.accept(t);
}
};
}
query(mapping, type, limiter, mapFilter, mapConsumer, fetchSize, sql, params);
}
@Override
public final void query(Tnp tnp, Class> entityClass, Limiter limiter, OrmMapFilter mapFilter, OrmMapConsumer mapConsumer, int fetchSize, List fieldNames, WhereSql whereSql) {
Sql sql = querySql(tnp, nonNullClassInfo(entityClass), fieldNames, whereSql);
if (sql != null)
query(null, entityClass, limiter, mapFilter, mapConsumer, fetchSize, sql.value(), sql.toArray());
}
final Sql querySql(Tnp tnp, ClassInfo classInfo, List fieldNames, WhereSql whereSql) {
return whereSql == WhereSql.EMPTY ? null : sql(builder().select(tnp == null ? classInfo.tnp : tnp, columns(classInfo, fieldNames)), whereSql);
}
private List columns(ClassInfo classInfo, List fieldNames) {
if (NullHelp.isEmpty(fieldNames)) return classInfo.getColumns();
return ToList.explicitCollect(fieldNames.stream().map(classInfo::toColumnName), fieldNames.size());
}
private Sql sql(SqlBuilder builder, WhereSql whereSql) {
if (whereSql == null) return builder::build;
builder.space().append(whereSql.value());
return Sql.of(builder.build(), whereSql.params());
}
@Override
public final void query(Tnp tnp, Class entityClass, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> consumer, int fetchSize, List fieldNames, WhereSql whereSql) {
Sql sql = querySql(tnp, nonNullClassInfo(entityClass), fieldNames, whereSql);
if (sql != null)
query(null, entityClass, limiter, mapFilter, filter, consumer, fetchSize, sql.value(), sql.toArray());
}
@Override
public final void query(Set tnpSet, Class> entityClass, Limiter limiter, OrmMapFilter mapFilter, OrmMapConsumer mapConsumer, int fetchSize, Executor executor, List fieldNames, WhereSql whereSql) {
if (NullHelp.isEmpty(tnpSet)) return;
ClassInfo classInfo = nonNullClassInfo(entityClass);
Consumer action = tnp -> {
Sql sql = querySql(tnp, classInfo, fieldNames, whereSql);
if (sql != null)
query(null, entityClass, limiter, mapFilter, mapConsumer, fetchSize, sql.value(), sql.toArray());
};
if (tnpSet.size() == 1) {
action.accept(tnpSet.iterator().next());
return;
}
Runner.run(ToList.explicitCollect(tnpSet.stream().map(tnp -> () -> action.accept(tnp)), tnpSet.size()), executor);
}
@Override
public final void query(Set tnpSet, Class entityClass, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> consumer, int fetchSize, Executor executor, List fieldNames, WhereSql whereSql) {
if (NullHelp.isEmpty(tnpSet)) return;
DataType dataType = dataType(entityClass);
query(tnpSet, entityClass, limiter, mapFilter, map -> {
if (limiter != null) {
if (limiter.isLimit()) return;
if (filter == null) {
if (!limiter.isLimitBefore()) consumer.accept(dataType.parse(entityClass, map));
} else {
T t = dataType.parse(entityClass, map);
if (filter.test(t) && !limiter.isLimitBefore()) consumer.accept(t);
}
} else {
T t = dataType.parse(entityClass, map);
if (filter == null || filter.test(t)) consumer.accept(t);
}
}, fetchSize, executor, fieldNames, whereSql);
}
@Override
public final void update(ActionRunner runner, List updateFieldNames, Executor executor) {
LReference reference = new LReference<>();
boolean force = NullHelp.nonEmpty(updateFieldNames);
Runner.run(runner, entities -> {
if (reference.get() == null) reference.set(nonNullClassInfo(entities.get(0).getClass()));
batchUpdateById(null, MetaObject.of(entities, reference.get(), updateFieldNames), -1, force);
}, null, 0, executor);
}
@Override
public final void delete(ActionRunner runner, Boolean logic, Executor executor) {
LReference reference = new LReference<>();
Runner.run(runner, entities -> {
if (reference.get() == null) reference.set(nonNullClassInfo(entities.get(0).getClass()));
executeBatch(-1, deleteByIdSql(null, reference.get(), logic, true), ToList.explicitCollect(entities.stream().map(entity -> new Object[]{reference.get().getId(entity)}), entities.size()));
}, null, -1, executor);
}
@Override
public final List collect(ActionRunner runner) {
return ToList.collect(runner);
}
@Override
public final int count(ActionRunner runner) {
AtomicInteger count = new AtomicInteger();
runner.accept(t -> count.incrementAndGet());
return count.get();
}
@Override
public final PageInfo page(PageInfo pageInfo, ActionRunner runner, OrmFilter super T> filter, BiPredicate super T, ? super T> equals, Comparator super T> comparator) {
BiPredicate super T, ? super T> eq;
if (equals == null) {
LReference reference = new LReference<>();
eq = (a, b) -> {
if (reference.get() == null) reference.set(nonNullClassInfo(a.getClass()));
return Objects.equals(reference.get().getId(a), reference.get().getId(b));
};
} else eq = equals;
pageInfo.page(runner, filter, predicate -> {
AtomicInteger count = new AtomicInteger();
runner.accept(t -> {
if (predicate == null || predicate.test(t)) count.incrementAndGet();
});
return count.get();
}, eq, comparator, false);
return pageInfo;
}
@Override
public final List selectTopN(ActionRunner runner, int n, Comparator super T> comparator) {
return ToList.topN(runner, n, null, comparator);
}
@Override
public final Map> selectTopN(ActionRunner runner, Function super T, ILTag extends K>> group, Comparator super T> comparator) {
return ToMap.topN(runner, group, null, comparator);
}
@Override
public final Map selectTopOne(ActionRunner runner, Function super T, ? extends K> group, Comparator super T> comparator) {
return ToMap.topOne(runner, group, null, comparator);
}
@Override
public final Map selectMerge(ActionRunner runner, Function super T, ? extends K> group, BinaryOperator merger, Function, ? extends R> mapper) {
return ToMap.merge(runner, group, null, merger, mapper);
}
///////////////////////////////////////////////OrmCursorService
///////////////////////////////////////////////OrmCountService
@Override
public final int count(Tnp tnp, Class> entityClass, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return 0;
Sql sql = sql(builder().count(tnp == null ? nonNullClassInfo(entityClass).tnp : tnp), whereSql);
return count(sql.value(), sql.toArray());
}
@Override
public final int countByColumn(Tnp tnp, Class> entityClass, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return count(tnp, entityClass, whereSql(nonNullClassInfo(entityClass), fieldName, fieldValue, condition, logic));
}
@Override
public final Double maxColumn(Tnp tnp, Class> entityClass, String fieldName, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return null;
Sql sql = sql(builder().max(tnp == null ? nonNullClassInfo(entityClass).tnp : tnp, humpToUnderline(fieldName)), whereSql);
return selectOne(Double.class, true, sql.value(), sql.toArray());
}
@Override
public final Double minColumn(Tnp tnp, Class> entityClass, String fieldName, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return null;
Sql sql = sql(builder().min(tnp == null ? nonNullClassInfo(entityClass).tnp : tnp, humpToUnderline(fieldName)), whereSql);
return selectOne(Double.class, true, sql.value(), sql.toArray());
}
@Override
public final Double avgColumn(Tnp tnp, Class> entityClass, String fieldName, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return null;
Sql sql = sql(builder().avg(tnp == null ? nonNullClassInfo(entityClass).tnp : tnp, humpToUnderline(fieldName)), whereSql);
return selectOne(Double.class, true, sql.value(), sql.toArray());
}
@Override
public final Double randColumn(Tnp tnp, Class> entityClass, String fieldName, WhereSql whereSql) {
if (whereSql == WhereSql.EMPTY) return null;
String sql = builder().rand(tnp == null ? nonNullClassInfo(entityClass).tnp : tnp, humpToUnderline(fieldName), whereSql);
return selectOne(Double.class, true, sql, whereSql == null ? ArrayConstant.EMPTY_OBJECT_ARRAY : whereSql.params().toArray());
}
///////////////////////////////////////////////OrmCountService
///////////////////////////////////////////////OrmSelectListService
@Override
public final List selectList(Type type, String sql, Object... params) {
List> maps = new LinkedList<>();
query(null, type, null, null, maps::add, Integer.MAX_VALUE, sql, params);
return dataType(type).parse(type, maps);
}
@Override
public final List selectList(Tnp tnp, Class entityClass, List fieldNames, WhereSql whereSql) {
Sql sql = querySql(tnp, nonNullClassInfo(entityClass), fieldNames, whereSql);
return sql == null ? Collections.emptyList() : selectList(entityClass, sql.value(), sql.toArray());
}
@Override
public final List selectListByColumn(Tnp tnp, Class entityClass, List fieldNames, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return selectList(tnp, entityClass, fieldNames, whereSql(nonNullClassInfo(entityClass), fieldName, fieldValue, condition, logic));
}
@Override
public final List selectByIds(Tnp tnp, Class entityClass, List fieldNames, Collection> ids, Boolean logic) {
if (NullHelp.isAnyNull(ids)) return Collections.emptyList();
ClassInfo classInfo = nonNullClassInfo(entityClass);
return selectList(tnp, entityClass, fieldNames, whereSql(classInfo, classInfo.idField.getName(), ids, Condition.IN, logic));
}
@Override
public final List selectByIds(Tnp tnp, Collection entities, List fieldNames, Boolean logic) {
if (NullHelp.isAnyNull(entities)) return Collections.emptyList();
Class cls = (Class) entities.iterator().next().getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
return selectByIds(tnp, cls, fieldNames, ToSet.explicitCollect(entities.stream().map(classInfo::getId), entities.size()), logic);
}
@Override
public final Map mapByIds(Class entityClass, Collection> ids) {
if (NullHelp.isEmpty(ids)) return Collections.emptyMap();
List entities = selectByIds(entityClass, ids);
if (NullHelp.isEmpty(entities)) return Collections.emptyMap();
ClassInfo classInfo = nonNullClassInfo(entityClass);
return ToMap.explicitCollect(entities.stream(), classInfo::getId, Function.identity(), entities.size());
}
@Override
public final Map mapByIds(Class entityClass, Collection data, Function idGetter) {
if (NullHelp.isEmpty(data)) return Collections.emptyMap();
return mapByIds(entityClass, ToSet.explicitCollect(data.stream().map(idGetter), data.size()));
}
///////////////////////////////////////////////OrmSelectListService
///////////////////////////////////////////////OrmPageService
@Override
public final PageInfo page(PageInfo pageInfo, Type type, String sql, Object... params) {
if (pageInfo.getSize() == Integer.MAX_VALUE) {
pageInfo.setData(selectList(type, sql, params));
pageInfo.setPage(1);
pageInfo.setTotal(pageInfo.getData().size());
pageInfo.reset();
} else {
pageInfo.setTotal(count(builder().append(sql).count(), params));
pageInfo.reset();
if (pageInfo.getTotal() <= 0 || pageInfo.getPage() > pageInfo.getPages()) return pageInfo.map();
pageInfo.setData(selectList(type, builder().append(sql).page(pageInfo), params));
}
return pageInfo;
}
@Override
public final PageInfo page(PageInfo pageInfo, Tnp tnp, Class entityClass, List fieldNames, WhereSql whereSql) {
Sql sql = querySql(tnp, nonNullClassInfo(entityClass), fieldNames, whereSql);
return sql == null ? pageInfo.map() : page(pageInfo, entityClass, sql.value(), sql.toArray());
}
@Override
public final PageInfo pageByColumn(PageInfo pageInfo, Tnp tnp, Class entityClass, List fieldNames, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return page(pageInfo, tnp, entityClass, fieldNames, whereSql(nonNullClassInfo(entityClass), fieldName, fieldValue, condition, logic));
}
///////////////////////////////////////////////OrmPageService
///////////////////////////////////////////////OrmSelectOneService
@Override
public final T selectOne(Type type, boolean unique, String sql, Object... params) {
List ts;
if (unique) ts = selectList(type, sql, params);
else {
PageInfo> pageInfo = PageInfo.of(1, 1);
pageInfo.setTotal(1);
pageInfo.reset();
ts = selectList(type, builder().append(sql).page(pageInfo), params);
}
if (NullHelp.isEmpty(ts)) return null;
if (unique && ts.size() > 1)
throw new RuntimeException(ToString.format("TooManyResults[size:%d,sql:%s]", ts.size(), sql));
return ts.get(0);
}
@Override
public final T selectOne(Tnp tnp, Class entityClass, boolean unique, List fieldNames, WhereSql whereSql) {
Sql sql = querySql(tnp, nonNullClassInfo(entityClass), fieldNames, whereSql);
return sql == null ? null : selectOne(entityClass, unique, sql.value(), sql.toArray());
}
@Override
public final T selectOneByColumn(Tnp tnp, Class entityClass, boolean unique, List fieldNames, String fieldName, Object fieldValue, Condition condition, Boolean logic) {
return selectOne(tnp, entityClass, unique, fieldNames, whereSql(nonNullClassInfo(entityClass), fieldName, fieldValue, condition, logic));
}
@Override
public final T selectById(Tnp tnp, Class entityClass, List fieldNames, Object id, Boolean logic) {
if (id == null) return null;
ClassInfo classInfo = nonNullClassInfo(entityClass);
return selectOne(tnp, entityClass, true, fieldNames, whereSql(classInfo, classInfo.idField.getName(), id, Condition.EQ, logic));
}
@Override
public final T selectById(Tnp tnp, T entity, List fieldNames, Boolean logic) {
if (entity == null) return null;
Class cls = (Class) entity.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
return selectById(tnp, cls, fieldNames, classInfo.getId(entity), logic);
}
///////////////////////////////////////////////OrmSelectOneService
///////////////////////////////////////////////OrmTreeService
@Override
public final > int insertTree(T tree, TreeNode.SetterFromParent setter, Consumer super T> checker, String name) {
if (tree == null) return 0;
Class cls = (Class) tree.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
Long pId = tree.getParentId();
boolean hasPid = pId != null && pId > 0L;
T pTree;
if (hasPid) ClientFailureMsg.requireNonNull(pTree = selectById(cls, pId), "%s父级ID:%s不存在", name, pId);
else pTree = null;
return apply(() -> {
T updatePTree = null;
if (hasPid) {
tree.setLevel(pTree.getLevel() + 1);
tree.setRootId(pTree.getRootId() == 0L ? pId : pTree.getRootId());
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "parentId", pId, Condition.EQ, Boolean.TRUE));
List lbt = selectTopN(runner, 1, (t, u) -> TreeEntity.lbtCmp(pTree.getTag().length() + 1, t.getTag(), u.getTag()));
T pre = lbt.isEmpty() ? null : lbt.get(0);
tree.setTag(TreeEntity.tag(pTree.getTag(), pre == null ? null : pre.getTag()));
if (tree.getSort() == null) tree.setSort(pre == null ? 0 : pre.getSort() + 1);
if (setter != null) setter.accept(pTree, tree);
if (Help.isTrue(pTree.getLeaf())) {
updatePTree = AccessibleHelp.newInstance(cls);
updatePTree.setId(pTree.getId());
updatePTree.setLeaf(Boolean.FALSE);
}
} else {
tree.setParentId(0L);
tree.setLevel(1);
tree.setRootId(0L);
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "level", 1, Condition.EQ, Boolean.TRUE));
List lbt = selectTopN(runner, 1, (t, u) -> TreeEntity.lbtCmp(0, t.getTag(), u.getTag()));
T pre = lbt.isEmpty() ? null : lbt.get(0);
tree.setTag(TreeEntity.tag(null, pre == null ? null : pre.getTag()));
if (tree.getSort() == null) tree.setSort(pre == null ? 0 : pre.getSort() + 1);
}
if (checker != null) checker.accept(tree);
int row = insert(tree);
NullHelp.requireNon(fail(row) || updatePTree != null && fail(updateById(updatePTree)));
return row;
});
}
@Override
public final > int[] batchInsertTree(List trees, TreeNode.SetterFromParent setter, Consumer> checker, String name) {
if (NullHelp.isEmpty(trees)) return ArrayConstant.EMPTY_INT_ARRAY;
Class cls = (Class) trees.iterator().next().getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
Map> map = trees.stream().collect(Collectors.partitioningBy(tree -> tree.getParentId() == null || tree.getParentId() <= 0L));
List nonParentIdList = map.get(Boolean.TRUE);
List hasParentIdList = map.get(Boolean.FALSE);
Set pIds;
List pTrees;
if (!hasParentIdList.isEmpty()) {
pIds = ToSet.explicitCollect(hasParentIdList.stream().map(TreeEntity::getParentId), hasParentIdList.size());
pTrees = selectByIds(cls, pIds);
if (pTrees.size() != pIds.size()) {
Set ids = ToSet.explicitCollect(pTrees.stream().map(TreeEntity::getId), pTrees.size());
pIds.removeAll(ids);
throw PRException.client("%s父级ID:%s不存在", name, ToString.joining(pIds, ","));
}
} else {
pIds = Collections.emptySet();
pTrees = Collections.emptyList();
}
return apply(() -> {
if (!nonParentIdList.isEmpty()) {
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "level", 1, Condition.EQ, Boolean.TRUE));
List lbt = selectTopN(runner, 1, (t, u) -> TreeEntity.lbtCmp(0, t.getTag(), u.getTag()));
LReference tag = new LReference<>(lbt.isEmpty() ? null : lbt.get(0).getTag());
IReference sort = new IReference(lbt.isEmpty() ? 0 : lbt.get(0).getSort() + 1);
nonParentIdList.forEach(tree -> {
tree.setParentId(0L);
tree.setLevel(1);
tree.setRootId(0L);
tree.setTag(TreeEntity.tag(null, tag.get()));
tag.set(tree.getTag());
if (tree.getSort() == null) tree.setSort(sort.getAndIncrement());
});
}
List updatePTrees = new ArrayList<>(pTrees.size());
if (!hasParentIdList.isEmpty()) {
Map pTreeMap = ToMap.explicitCollect(pTrees.stream(), TreeEntity::getId, Function.identity(), pTrees.size());
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "parentId", pIds, Condition.IN, Boolean.TRUE));
Map pIdMap = selectTopOne(runner, TreeEntity::getParentId, (t, u) -> TreeEntity.lbtCmp(pTreeMap.get(t.getParentId()).getTag().length() + 1, t.getTag(), u.getTag()));
Map tags = ToMap.explicitCollect(pIds.stream(), Function.identity(), pId -> {
T lbt = pIdMap.get(pId);
return lbt == null ? null : lbt.getTag();
}, pIdMap.size());
Map sorts = ToMap.explicitCollect(pIds.stream(), Function.identity(), pId -> {
T lbt = pIdMap.get(pId);
return new IReference(lbt == null ? 0 : lbt.getSort() + 1);
}, pIdMap.size());
hasParentIdList.forEach(tree -> {
Long pId = tree.getParentId();
T pTree = pTreeMap.get(pId);
tree.setLevel(pTree.getLevel() + 1);
tree.setRootId(pTree.getRootId() == 0L ? pId : pTree.getRootId());
tree.setTag(TreeEntity.tag(pTree.getTag(), tags.get(pId)));
tags.put(pId, tree.getTag());
if (tree.getSort() == null) tree.setSort(sorts.get(pId).getAndIncrement());
if (setter != null) setter.accept(pTree, tree);
if (Help.isTrue(pTree.getLeaf())) {
T updatePTree = AccessibleHelp.newInstance(cls);
updatePTree.setId(pTree.getId());
updatePTree.setLeaf(Boolean.FALSE);
updatePTrees.add(updatePTree);
}
});
}
if (checker != null) checker.accept(trees);
int[] rows = batchInsert(trees);
NullHelp.requireNon(batchFail(rows) || !updatePTrees.isEmpty() && batchFail(batchUpdateById(updatePTrees)));
return rows;
});
}
@Override
public final > int updateTree(T tree, T oldTree, TreeNode.SetterFromParent setter, Consumer super T> checker, String name) {
if (tree == null) return 0;
Class cls = (Class) tree.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
if (oldTree == null) oldTree = selectById(cls, tree.getId());
ClientFailureMsg.requireNonNull(oldTree, "%sID:%s不存在", name, tree.getId());
Long oldPid = oldTree.getParentId();
String oldTag = oldTree.getTag();
int oldLevel = oldTree.getLevel();
T oldPTree;
if (oldPid > 0L)
ClientFailureMsg.requireNonNull(oldPTree = selectById(cls, oldPid), "%s父级ID:%s不存在", name, oldPid);
else oldPTree = null;
Long newPid = tree.getParentId();
boolean hasPid = newPid != null && newPid > 0L;
T newPTree;
if (hasPid) {
if (Objects.equals(oldPid, newPid)) newPTree = oldPTree;
else ClientFailureMsg.requireNonNull(newPTree = selectById(cls, newPid), "%s父级ID:%s不存在", name, newPid);
} else newPTree = null;
return apply(() -> {
ZReference change = new ZReference();
if (hasPid && !Objects.equals(oldPid, newPid)) {
//根菜单变子菜单或子菜单变更父级
change.set(true);
tree.setLevel(newPTree.getLevel() + 1);
tree.setRootId(newPTree.getRootId() == 0L ? newPid : newPTree.getRootId());
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "parentId", newPid, Condition.EQ, Boolean.TRUE));
List lbt = selectTopN(runner, 1, (t, u) -> TreeEntity.lbtCmp(newPTree.getTag().length() + 1, t.getTag(), u.getTag()));
T pre = lbt.isEmpty() ? null : lbt.get(0);
tree.setTag(TreeEntity.tag(newPTree.getTag(), pre == null ? null : pre.getTag()));
if (setter != null) setter.accept(newPTree, tree);
} else if (!hasPid && oldPid > 0L) {
//子菜单变根菜单
change.set(true);
tree.setParentId(0L);
tree.setLevel(1);
tree.setRootId(0L);
ActionRunner runner = runner(null, cls, null, null, null, 0, null, whereSql(classInfo, "parentId", 0L, Condition.EQ, Boolean.TRUE));
List lbt = selectTopN(runner, 1, (t, u) -> TreeEntity.lbtCmp(0, t.getTag(), u.getTag()));
T pre = lbt.isEmpty() ? null : lbt.get(0);
tree.setTag(TreeEntity.tag(null, pre == null ? null : pre.getTag()));
}
if (!change.get()) tree.setParentId(oldPid);
if (checker != null) checker.accept(tree);
int row = updateById(tree);
NullHelp.requireNon(fail(row));
if (change.get()) {
//获取所有子节点变更子节点tag
List children = children(cls, oldTag);
if (!children.isEmpty()) {
int delta = tree.getLevel() - oldLevel;
Long newRootId = tree.getRootId() == 0L ? tree.getId() : tree.getRootId();
String newTag = tree.getTag();
int idx = oldTag.length();
children.forEach(e -> {
e.setLevel(e.getLevel() + delta);
e.setRootId(newRootId);
e.setTag(newTag + e.getTag().substring(idx));
});
if (setter != null) TreeNode.setFromParent(TreeEntity.group(children), tree, setter);
NullHelp.requireNon(batchFail(batchUpdateById(children)));
}
if (newPTree != null && Help.isTrue(newPTree.getLeaf())) {
T updatePTree = AccessibleHelp.newInstance(cls);
updatePTree.setId(newPTree.getId());
updatePTree.setLeaf(Boolean.FALSE);
NullHelp.requireNon(fail(updateById(updatePTree)));
}
if (oldPTree != null) {
List ts = nextChildren(cls, oldPTree.getTag());
if (ts.isEmpty() || ts.size() == 1 && Objects.equals(ts.get(0).getId(), tree.getId())) {
T updatePTree = AccessibleHelp.newInstance(cls);
updatePTree.setId(oldPTree.getId());
updatePTree.setLeaf(Boolean.TRUE);
NullHelp.requireNon(fail(updateById(updatePTree)));
}
}
}
return row;
});
}
@Override
public final > int insertOrUpdateTree(T tree, TreeNode.SetterFromParent setter, List> uniqueFields) {
if (tree == null) return 0;
Class cls = (Class) tree.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
WhereSql whereSql = WhereInfo.uniqueWhere(classInfo, tree, this::builder, Serializer.getFieldNameArray(uniqueFields));
T oldTree = selectOne(cls, true, null, whereSql);
if (oldTree == null) return insertTree(tree, setter, null, null);
tree.setId(oldTree.getId());
return updateTree(tree, oldTree, setter, null, null);
}
@Override
public final > int deleteTree(Collection entities) {
if (NullHelp.isEmpty(entities)) return 0;
Class cls = (Class) entities.iterator().next().getClass();
Map> map = entities.stream().filter(t -> t.getParentId() > 0L).collect(Collectors.groupingBy(TreeEntity::getParentId, Collectors.mapping(TreeEntity::getId, Collectors.toSet())));
if (map.isEmpty()) return deleteByIds(entities);
return apply(() -> {
int row = deleteByIds(entities);
NullHelp.requireNon(row != entities.size());
Set pIds = map.keySet();
List pTrees = selectByIds(cls, pIds);
if (pTrees.size() != pIds.size()) {
Set ids = ToSet.explicitCollect(pTrees.stream().map(TreeEntity::getId), pTrees.size());
pIds.removeAll(ids);
throw PRException.client("父级ID:%s不存在", ToString.joining(pIds, ","));
}
for (T pTree : pTrees) {
List ts = nextChildren(cls, pTree.getTag());
if (ts.isEmpty() || ts.size() == 1 && map.get(pTree.getId()).contains(ts.get(0).getId())) {
T updatePTree = AccessibleHelp.newInstance(cls);
updatePTree.setId(pTree.getId());
updatePTree.setLeaf(Boolean.TRUE);
NullHelp.requireNon(fail(updateById(updatePTree)));
}
}
return row;
});
}
@Override
public final > int deleteTree(Class cls, Collection> ids) {
return deleteTree(selectByIds(cls, ids));
}
@Override
public final > List parents(Class cls, String tag, Integer levelDelta) {
return selectByTags(cls, TreeEntity.dpTags(tag, levelDelta));
}
private > List selectByTags(Class cls, Collection tags) {
if (tags.isEmpty()) return Collections.emptyList();
return selectListByColumn(cls, null, "tag", tags, Condition.IN, Boolean.TRUE);
}
@Override
public final > List children(Class cls, String tag, Integer levelDelta) {
if (NullHelp.isBlank(tag)) return Collections.emptyList();
if (levelDelta == null || levelDelta <= 0)
return selectListByColumn(cls, null, "tag", tag + ".", Condition.LIKE_RIGHT, Boolean.TRUE);
return selectList(cls, whereSql(cls,
Arrays.asList("tag", "level"),
Arrays.asList(tag + ".", tag.split("\\.").length + levelDelta),
Arrays.asList(Condition.LIKE_RIGHT, Condition.LE),
Boolean.TRUE
));
}
@Override
public final > List completion(Class cls, Collection tags, Integer levelDelta) {
if (NullHelp.isEmpty(tags)) return Collections.emptyList();
return selectByTags(cls, ToSet.collect(tags.stream().flatMap(tag -> TreeEntity.dpTags(tag, true, levelDelta).stream())));
}
///////////////////////////////////////////////OrmTreeService
}