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.OrmService Maven / Gradle / Ivy
package shz.core.orm;
import shz.core.*;
import shz.core.function.ActionRunner;
import shz.core.model.PageInfo;
import shz.core.orm.annotation.*;
import shz.core.orm.param.OrmConsumer;
import shz.core.orm.param.OrmFilter;
import shz.core.orm.param.OrmMapFilter;
import shz.core.orm.param.OrmMapping;
import shz.core.orm.param.OrmParam;
import shz.core.serializable.SerializableGetter;
import shz.core.serializable.Serializer;
import shz.core.st.tst.LTST;
import shz.core.structure.BloomFilter;
import shz.core.structure.FilterContainer;
import shz.core.structure.UnInfo;
import shz.core.structure.config.BigMapConfig;
import shz.core.structure.config.MapConfig;
import shz.core.structure.limiter.Limiter;
import shz.core.type.TypeHelp;
import shz.core.orm.enums.Condition;
import shz.core.orm.enums.ValueStrategy;
import shz.core.orm.param.OrmMapActionRunner;
import shz.core.orm.sql.Sql;
import shz.core.orm.sql.WhereSql;
import shz.core.orm.sql.builder.SqlBuilder;
import shz.core.orm.sql.segment.Segment;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.function.Function;
@SuppressWarnings("unchecked")
public abstract class OrmService extends AbstractDefaultOrmService {
public static OrmService get() {
return Container.get(OrmService.class);
}
public static OrmService get(String dsName) {
OrmService service = get();
return NullHelp.isEmpty(dsName) ? service : service.service(dsName);
}
protected abstract OrmService service(String dsName);
public final Object proxyExecute(Method method, Object[] args) {
return ActionRunner.class.isAssignableFrom(method.getReturnType()) ? proxyExecuteRunner(method, args) : proxyExecute0(method, args);
}
private Object proxyExecute0(Method method, Object[] args) {
Class> returnType = method.getReturnType();
NullHelp.requireNon(returnType == void.class || returnType == Void.class);
Parameter[] parameters = method.getParameters();
Update update = method.getAnnotation(Update.class);
if (update != null) {
Sql sql = sql(parameters, args, update.value());
return update(sql.value(), sql.toArray());
}
Delete delete = method.getAnnotation(Delete.class);
if (delete != null) {
Sql sql = sql(parameters, args, delete.value());
return delete(sql.value(), sql.toArray());
}
PageInfo pageInfo = null;
Type type = null;
for (int i = 0; i < parameters.length; ++i) {
Param param = parameters[i].getAnnotation(Param.class);
if (param == null && PageInfo.class.isAssignableFrom(parameters[i].getType())) {
pageInfo = (PageInfo) args[i];
Objects.requireNonNull(pageInfo);
type = getType(parameters[i]);
break;
}
}
if (type == null) type = getType(method);
Query query = method.getAnnotation(Query.class);
if (query != null) {
Sql sql = sql(parameters, args, query.value());
if (pageInfo != null) return page(pageInfo, type, sql.value(), sql.toArray());
if (List.class.isAssignableFrom(returnType)) return selectList(type, sql.value(), sql.toArray());
return selectOne(type, query.unique(), sql.value(), sql.toArray());
}
Class entityClass = TypeHelp.toClass(type);
WhereSql whereSql = whereSql(nonNullClassInfo(entityClass), parameters, args);
List fieldNames;
Fields fa = method.getAnnotation(Fields.class);
if (fa != null && fa.value().length > 0) fieldNames = Arrays.asList(fa.value());
else fieldNames = null;
if (pageInfo != null) return page(pageInfo, entityClass, fieldNames, whereSql);
if (List.class.isAssignableFrom(returnType)) return selectList(entityClass, fieldNames, whereSql);
return selectOne(entityClass, false, fieldNames, whereSql);
}
private Sql sql(Parameter[] parameters, Object[] args, String sql) {
if (parameters.length == 0) return () -> humpToUnderlineSql(sql);
Segment.Input input = new Segment.Input();
input.map = new HashMap<>();
for (int i = 0; i < parameters.length; ++i) {
Param param = parameters[i].getAnnotation(Param.class);
if (param == null) continue;
ValueStrategy strategy = param.strategy();
if (strategy == ValueStrategy.NOT_NULL) {
if (args[i] == null) continue;
} else if (strategy == ValueStrategy.NOT_EMPTY) {
if (NullHelp.isEmpty(args[i])) continue;
} else if (strategy == ValueStrategy.NOT_BLANK) {
if (NullHelp.isBlank(args[i])) continue;
}
String key = param.value();
Class> pt = parameters[i].getType();
if (Collection.class.isAssignableFrom(pt) || pt.isArray() || TypeHelp.likeCommon(pt))
input.map.put(key, args[i]);
else fieldValueMap(input.map, args[i], key);
}
input.params = new LinkedList<>();
SqlBuilder builder = builder();
for (Segment segment : segments(sql)) segment.fill(builder, input);
return Sql.of(builder.build(), input.params.isEmpty() ? Collections.emptyList() : input.params);
}
private static final LTST UNDERLINE_SQL_CACHE = LTST.of();
private String humpToUnderlineSql(String sql) {
char[] chars = sql.toCharArray();
String underlineSql = UNDERLINE_SQL_CACHE.get(chars);
if (underlineSql == null) {
underlineSql = sqlHandler.humpToUnderlineSql(sql);
UNDERLINE_SQL_CACHE.put(chars, underlineSql);
}
return underlineSql;
}
protected abstract Map> tableSchemaNameMap();
private void fieldValueMap(Map map, Object obj, String mapField) {
if (obj == null) {
map.put(mapField, null);
return;
}
if (obj instanceof PageInfo) {
PageInfo> pageInfo = (PageInfo>) obj;
pageInfo.reset();
map.put(mapField + ".page", pageInfo.getPage());
map.put(mapField + ".size", pageInfo.getSize());
map.put(mapField + ".min", pageInfo.getMin());
map.put(mapField + ".max", pageInfo.getMax());
return;
}
Class> cls = obj.getClass();
if (Limiter.class.isAssignableFrom(cls) || OrmParam.class.isAssignableFrom(cls)) return;
if (Collection.class.isAssignableFrom(cls) || cls.isArray() || TypeHelp.likeCommon(cls)) map.put(mapField, obj);
else if (Map.class.isAssignableFrom(cls))
((Map, ?>) obj).forEach((k, v) -> fieldValueMap(map, v, mapField + "." + k));
else AccessibleHelp.fields(cls).forEach(f -> {
Object val = AccessibleHelp.getField(f, obj);
Where where = f.getAnnotation(Where.class);
if (where != null) {
ValueStrategy strategy = where.strategy();
if (strategy == ValueStrategy.NOT_NULL) {
if (val == null) return;
} else if (strategy == ValueStrategy.NOT_EMPTY) {
if (NullHelp.isEmpty(val)) return;
} else if (strategy == ValueStrategy.NOT_BLANK) {
if (NullHelp.isBlank(val)) return;
}
} else if (NullHelp.isBlank(val)) return;
fieldValueMap(map, val, mapField + "." + f.getName());
});
}
private static final LTST> SQL_SEGMENTS_CACHE = LTST.of();
private List segments(String sql) {
char[] chars = sql.toCharArray();
List segments = SQL_SEGMENTS_CACHE.get(chars);
if (segments == null) {
segments = sqlHandler.segments(sqlHandler.humpToUnderlineSql(sql));
NullHelp.requireNonEmpty(segments, "sql异常:%s", sql);
SQL_SEGMENTS_CACHE.put(chars, segments);
}
return segments;
}
private WhereSql whereSql(ClassInfo classInfo, Parameter[] parameters, Object[] args) {
return WhereInfo.where(classInfo, parameters, args, this::builder);
}
private Type getType(Parameter parameter) {
Type type = parameter.getParameterizedType();
if (type instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
if (actualTypeArguments.length > 0) return actualTypeArguments[0];
}
return type;
}
private Type getType(Method method) {
Type type = method.getGenericReturnType();
Class> returnType = method.getReturnType();
if (OrmMapActionRunner.class.isAssignableFrom(returnType)) return Map.class;
if (type instanceof ParameterizedType &&
(PageInfo.class.isAssignableFrom(returnType)
|| List.class.isAssignableFrom(returnType)
|| ActionRunner.class.isAssignableFrom(returnType))
) {
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
if (actualTypeArguments.length > 0) return actualTypeArguments[0];
}
return type;
}
private ActionRunner proxyExecuteRunner(Method method, Object[] args) {
Class> returnType = method.getReturnType();
Parameter[] parameters = method.getParameters();
Limiter limiter = null;
boolean limiterMark = false;
OrmMapping mapping = null;
boolean mappingMark = false;
OrmMapFilter mapFilter = null;
boolean mapFilterMark = false;
OrmFilter filter = null;
boolean filterMark = false;
int count = 0;
Type type = null;
for (int i = 0; i < parameters.length; ++i) {
if (count == 4) break;
Class> pType = parameters[i].getType();
if (!limiterMark && Limiter.class.isAssignableFrom(pType)) {
limiter = (Limiter) args[i];
limiterMark = true;
++count;
} else if (OrmParam.class.isAssignableFrom(pType)) {
if (!mappingMark && OrmMapping.class.isAssignableFrom(pType)) {
mapping = (OrmMapping) args[i];
mappingMark = true;
++count;
} else if (!mapFilterMark && OrmMapFilter.class.isAssignableFrom(pType)) {
mapFilter = (OrmMapFilter) args[i];
mapFilterMark = true;
++count;
} else if (!filterMark && OrmFilter.class.isAssignableFrom(pType)) {
filter = (OrmFilter) args[i];
filterMark = true;
++count;
type = getType(parameters[i]);
}
}
}
if (type == null) type = getType(method);
Query query = method.getAnnotation(Query.class);
if (query != null) {
Sql sql = sql(parameters, args, query.value());
if (OrmMapActionRunner.class.isAssignableFrom(returnType))
return (ActionRunner) runner(mapping, type, limiter, mapFilter, query.fetchSize(), sql.value(), sql.toArray());
return runner(mapping, type, limiter, mapFilter, filter, query.fetchSize(), sql.value(), sql.toArray());
}
Class entityClass = TypeHelp.toClass(type);
WhereSql whereSql = whereSql(nonNullClassInfo(entityClass), parameters, args);
List fieldNames;
Fields fa = method.getAnnotation(Fields.class);
if (fa != null && fa.value().length > 0) fieldNames = Arrays.asList(fa.value());
else fieldNames = null;
if (OrmMapActionRunner.class.isAssignableFrom(returnType))
return (ActionRunner) runner(null, entityClass, limiter, mapFilter, 0, fieldNames, whereSql);
return runner(null, entityClass, limiter, mapFilter, filter, 0, fieldNames, whereSql);
}
private static final Map, Object> PROXY = new ConcurrentHashMap<>(128);
public static T getProxy(Class cls, OrmService service) {
if (cls == null || !cls.isInterface() || service == null) return null;
return (T) PROXY.computeIfAbsent(cls, k -> InterfaceProxy.getProxy(k, p -> service.proxyExecute(p.method, p.args)));
}
public static T getProxy(Class cls) {
if (cls == null || !cls.isInterface()) return null;
Repository repository = cls.getAnnotation(Repository.class);
return repository == null ? null : getProxy(cls, get(repository.value()));
}
@SafeVarargs
public final boolean checkUniqueForInsert(T entity, SerializableGetter... uniqueFields) {
Class cls = (Class) entity.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
WhereSql whereSql = WhereInfo.uniqueWhere(classInfo, entity, this::builder, Serializer.getFieldNameArray(uniqueFields));
return selectOne(cls, true, Collections.singletonList(classInfo.idField.getName()), whereSql) != null;
}
@SafeVarargs
public final boolean checkUniqueForUpdate(T entity, SerializableGetter... uniqueFields) {
Class cls = (Class) entity.getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
WhereSql whereSql = WhereInfo.uniqueWhere(classInfo, entity, this::builder, Serializer.getFieldNameArray(uniqueFields));
T oldEntity = selectOne(cls, true, Collections.singletonList(classInfo.idField.getName()), whereSql);
return oldEntity != null && !Objects.equals(classInfo.getId(entity), classInfo.getId(oldEntity));
}
@SafeVarargs
public final boolean batchEdit(List newDataset, List oldDataset, Function super T, ?>... classifiers) {
T entity = null;
if (NullHelp.nonEmpty(newDataset)) entity = newDataset.get(0);
else if (NullHelp.nonEmpty(oldDataset)) entity = oldDataset.get(0);
if (entity == null) return false;
ClassInfo classInfo = nonNullClassInfo(entity.getClass());
UnInfo unInfo = UnInfo.of(newDataset, oldDataset, classInfo::getId, classInfo::setId, classifiers);
return batchFail(batchDeleteById(unInfo.getDelete())) || batchFail(batchUpdateById(unInfo.getUpdate())) || batchFail(batchInsert(unInfo.getInsert()));
}
public final Set existsId(Tnp tnp, Class entityClass, Collection extends ID> ids, Boolean logic) {
if (NullHelp.isEmpty(ids)) return Collections.emptySet();
ClassInfo classInfo = nonNullClassInfo(entityClass);
WhereSql whereSql = whereSql(classInfo, classInfo.idField.getName(), ids, Condition.IN, logic);
Set exists = ToSet.get(ids.size()).build();
query(tnp, entityClass, null, null, map -> exists.add((ID) map.get(classInfo.idField.getName())), Integer.MAX_VALUE, Collections.singletonList(classInfo.idField.getName()), whereSql);
return exists;
}
public final Set existsId(Class entityClass, Collection extends ID> ids, Boolean logic) {
return existsId(null, entityClass, ids, logic);
}
public final Set existsId(Class entityClass, Collection extends ID> ids) {
return existsId(null, entityClass, ids, null);
}
public final Map existsColumn(Tnp tnp, Class entityClass, String fieldName, Collection extends V> fieldValues, Boolean logic) {
if (NullHelp.isBlank(fieldName) || NullHelp.isEmpty(fieldValues)) return Collections.emptyMap();
ClassInfo classInfo = nonNullClassInfo(entityClass);
WhereSql whereSql = whereSql(classInfo, fieldName, fieldValues, Condition.IN, logic);
Map exists = ToMap.get(fieldValues.size()).build();
query(tnp, entityClass, null, null, map -> exists.put((V) map.get(fieldName), (ID) map.get(classInfo.idField.getName())), Integer.MAX_VALUE, Arrays.asList(classInfo.idField.getName(), fieldName), whereSql);
return exists;
}
public final Map existsColumn(Class entityClass, String fieldName, Collection extends V> fieldValues, Boolean logic) {
return existsColumn(null, entityClass, fieldName, fieldValues, logic);
}
public final Map existsColumn(Class entityClass, String fieldName, Collection extends V> fieldValues) {
return existsColumn(null, entityClass, fieldName, fieldValues, null);
}
@SafeVarargs
public final void replace(Tnp tnp, List entities, List insertFieldNames, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> existed, OrmConsumer super T> beforeDelete, int fetchSize, Executor executor, List fieldNames, WhereSql whereSql, Boolean logic, SerializableGetter... uniqueFields) {
if (NullHelp.isAnyNull(entities)) return;
Class cls = (Class) entities.get(0).getClass();
ClassInfo classInfo = nonNullClassInfo(cls);
batchInsertOrUpdate(tnp, entities, insertFieldNames, logic, 0, Serializer.getFieldNameArray(uniqueFields));
Set> ids = ToSet.explicitCollect(entities.stream().map(classInfo::getId), entities.size());
ActionRunner runner = runner(tnp, cls, null, mapFilter, entity -> {
if (filter != null && !filter.test(entity)) return false;
if (ids.contains(classInfo.getId(entity))) {
if (existed != null) existed.accept(entity);
return false;
}
if (beforeDelete != null) beforeDelete.accept(entity);
return true;
}, fetchSize, fieldNames, whereSql);
delete(runner, logic, executor);
}
@SafeVarargs
public final void replace(List entities, List insertFieldNames, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> existed, OrmConsumer super T> beforeDelete, int fetchSize, Executor executor, List fieldNames, WhereSql whereSql, Boolean logic, SerializableGetter... uniqueFields) {
replace(null, entities, insertFieldNames, mapFilter, filter, existed, beforeDelete, fetchSize, executor, fieldNames, whereSql, logic, uniqueFields);
}
@SafeVarargs
public final void replace(List entities, List insertFieldNames, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> existed, OrmConsumer super T> beforeDelete, WhereSql whereSql, SerializableGetter... uniqueFields) {
replace(null, entities, insertFieldNames, mapFilter, filter, existed, beforeDelete, 0, null, null, whereSql, null, uniqueFields);
}
@SafeVarargs
public final void replace(List entities, OrmMapFilter mapFilter, OrmFilter super T> filter, OrmConsumer super T> existed, OrmConsumer super T> beforeDelete, WhereSql whereSql, SerializableGetter... uniqueFields) {
replace(null, entities, null, mapFilter, filter, existed, beforeDelete, 0, null, null, whereSql, null, uniqueFields);
}
public final void copyTo(OrmMapping mapping, OrmService desService, Tnp desTnp, Class desEntityClass, List desFieldNames, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, int fetchSize, Executor executor, boolean hasId, String srcSql, Object... params) {
ClassInfo classInfo = desService.nonNullClassInfo(desEntityClass);
int count = count(builder().append(srcSql).count(), params);
if (count < 1) return;
OrmMapFilter mapFilter0;
if (hasId) {
FilterContainer container;
Class> type = classInfo.idField.getType();
if (type == Long.class || type == long.class) container = new BigMapConfig();
else if (type == Integer.class || type == int.class) container = new MapConfig();
else container = BloomFilter.of(count);
mapFilter0 = map -> {
Object id = map.get(classInfo.idName);
if (id == null) return false;
if (container.contain(id)) return false;
else container.push(id);
return mapFilter == null || mapFilter.test(map);
};
} else mapFilter0 = mapFilter;
boolean force = NullHelp.nonEmpty(desFieldNames);
desService.accept(() -> {
ActionRunner runner = runner(mapping, desEntityClass, limiter, mapFilter0, filter, fetchSize, srcSql, params);
Runner.run(runner, entities -> desService.batchInsert(desTnp, MetaObject.of(entities, classInfo, desFieldNames), -1, force), null, -1, executor);
});
}
public final void copyTo(OrmMapping mapping, OrmService desService, Tnp desTnp, Class desEntityClass, List desFieldNames, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, Tnp srcTnp, Class> srcEntityClass, int fetchSize, Executor executor, boolean hasId, List srcFieldNames, WhereSql srcWhereSql) {
Sql sql = querySql(srcTnp, nonNullClassInfo(srcEntityClass), srcFieldNames, srcWhereSql);
if (sql != null)
copyTo(mapping, desService, desTnp, desEntityClass, desFieldNames, limiter, mapFilter, filter, fetchSize, executor, hasId, sql.value(), sql.toArray());
}
public final void copyOrUpdateTo(OrmMapping mapping, OrmService desService, Tnp desTnp, Class desEntityClass, List desFieldNames, Boolean desLogic, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, String desMatchFieldName, int fetchSize, Executor executor, String srcSql, Object... params) {
ClassInfo classInfo = desService.nonNullClassInfo(desEntityClass);
int count = count(builder().append(srcSql).count(), params);
if (count < 1) return;
boolean hasId = NullHelp.isBlank(desMatchFieldName);
Field matchField;
String matchColumn;
if (hasId) {
matchField = classInfo.idField;
matchColumn = classInfo.idName;
} else {
matchField = classInfo.getFieldByName(desMatchFieldName);
matchColumn = classInfo.toColumnName(desMatchFieldName);
NullHelp.requireNon(matchField == null || matchColumn == null, "匹配的域:%s不存在", desMatchFieldName);
}
boolean force = NullHelp.nonEmpty(desFieldNames);
desService.accept(() -> {
ActionRunner runner = runner(mapping, desEntityClass, limiter, map -> {
Object matchValue = map.get(matchColumn);
if (matchValue == null) return false;
return mapFilter == null || mapFilter.test(map);
}, filter, fetchSize, srcSql, params);
Runner.run(runner, entities -> {
Map, T> map = ToMap.explicitCollect(entities.stream(), entity -> AccessibleHelp.getField(matchField, entity), Function.identity(), entities.size());
if (hasId) {
Set> ids = desService.existsId(desTnp, desEntityClass, map.keySet(), desLogic);
if (ids.isEmpty())
desService.batchInsert(desTnp, MetaObject.of(entities, classInfo, desFieldNames), -1, force);
else {
desService.batchUpdateById(desTnp, MetaObject.of(ToList.explicitCollect(ids.stream().map(map::get), ids.size()), classInfo, desFieldNames), -1, force);
int delta = map.size() - ids.size();
if (delta > 0)
desService.batchInsert(desTnp, MetaObject.of(ToList.explicitCollect(map.keySet().stream().filter(id -> !ids.contains(id)).map(map::get), delta), classInfo, desFieldNames), -1, force);
}
} else {
Map, ?> columnIds = desService.existsColumn(desTnp, desEntityClass, desMatchFieldName, map.keySet(), desLogic);
if (columnIds.isEmpty())
desService.batchInsert(desTnp, MetaObject.of(entities, classInfo, desFieldNames), -1, force);
else {
desService.batchUpdateById(desTnp, MetaObject.of(ToList.explicitCollect(columnIds.keySet().stream().map(column -> {
T entity = map.get(column);
classInfo.setId(entity, columnIds.get(column));
return entity;
}), columnIds.size()), classInfo, desFieldNames), -1, force);
int delta = map.size() - columnIds.size();
if (delta > 0)
desService.batchInsert(desTnp, MetaObject.of(ToList.explicitCollect(map.keySet().stream().filter(column -> !columnIds.containsKey(column)).map(map::get), delta), classInfo, desFieldNames), -1, force);
}
}
}, null, -1, executor);
});
}
public final void copyOrUpdateTo(OrmMapping mapping, OrmService desService, Tnp desTnp, Class desEntityClass, List desFieldNames, Boolean desLogic, Limiter limiter, OrmMapFilter mapFilter, OrmFilter super T> filter, String desMatchFieldName, Tnp srcTnp, Class> srcEntityClass, int fetchSize, Executor executor, List srcFieldNames, WhereSql srcWhereSql) {
Sql sql = querySql(srcTnp, nonNullClassInfo(srcEntityClass), srcFieldNames, srcWhereSql);
if (sql != null)
copyOrUpdateTo(mapping, desService, desTnp, desEntityClass, desFieldNames, desLogic, limiter, mapFilter, filter, desMatchFieldName, fetchSize, executor, sql.value(), sql.toArray());
}
}