filter 改版中……

This commit is contained in:
kamhung
2015-11-19 17:50:38 +08:00
parent 61050e7d00
commit ef17090446
6 changed files with 561 additions and 425 deletions

View File

@@ -641,7 +641,9 @@ public final class DataDefaultSource implements DataSource, Nameable {
private <T> void delete(final Connection conn, final EntityInfo<T> info, final FilterNode node) {
try {
if (!info.isVirtualEntity()) {
String sql = "DELETE FROM " + info.getTable() + node.createFilterSQLExpress(info, null);
CharSequence join = node.createSQLJoin(info);
CharSequence where = node.createSQLExpress(info, null);
String sql = "DELETE FROM " + info.getTable() + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get()) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql);
final Statement stmt = conn.createStatement();
stmt.execute(sql);
@@ -1081,12 +1083,14 @@ public final class DataDefaultSource implements DataSource, Nameable {
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
final EntityCache<T> cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (node == null || node.isJoinAllCached()) {
if (node == null || node.isCacheUseable()) {
return cache.getNumberResult(reckon, column, node, bean);
}
}
final CharSequence join = node == null ? null : node.createSQLJoin(info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, bean);
final String sql = "SELECT " + reckon.getColumn((column == null || column.isEmpty() ? "*" : ("a." + column))) + " FROM " + info.getTable() + " a"
+ (node == null ? "" : node.createFilterSQLExpress(info, bean));
+ (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where));
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
final PreparedStatement prestmt = conn.prepareStatement(sql);
Number rs = null;
@@ -1127,13 +1131,15 @@ public final class DataDefaultSource implements DataSource, Nameable {
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
final EntityCache cache = info.getCache();
if (cache != null && (info.isVirtualEntity() || cache.isFullLoaded())) {
if (node == null || node.isJoinAllCached()) {
if (node == null || node.isCacheUseable()) {
return cache.getMapResult(keyColumn, reckon, reckonColumn, node, bean);
}
}
final String sqlkey = info.getSQLColumn(keyColumn);
final CharSequence join = node == null ? null : node.createSQLJoin(info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, bean);
final String sql = "SELECT a." + sqlkey + ", " + reckon.getColumn((reckonColumn == null || reckonColumn.isEmpty() ? "*" : ("a." + reckonColumn)))
+ " FROM " + info.getTable() + " a" + (node == null ? "" : node.createFilterSQLExpress(info, bean)) + " GROUP BY a." + sqlkey;
+ " FROM " + info.getTable() + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + sqlkey;
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(entityClass.getSimpleName() + " single sql=" + sql);
final PreparedStatement prestmt = conn.prepareStatement(sql);
Map<K, V> rs = new LinkedHashMap<>();
@@ -1433,8 +1439,8 @@ public final class DataDefaultSource implements DataSource, Nameable {
final EntityCache<T> cache = info.getCache();
if (node == null && bean != null) node = loadFilterBeanNode(bean.getClass());
if (readcache && cache != null) {
if (node == null || node.isJoinAllCached()) {
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createFilterPredicate(info, bean)));
if (node == null || node.isCacheUseable()) {
if (debug.get() && info.isLoggable(Level.FINEST)) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : node.createPredicate(cache, bean)));
Sheet<T> sheet = cache.querySheet(needtotal, selects, flipper, node, bean);
if (!sheet.isEmpty() || info.isVirtualEntity() || cache.isFullLoaded()) return sheet;
}
@@ -1443,8 +1449,10 @@ public final class DataDefaultSource implements DataSource, Nameable {
try {
final SelectColumn sels = selects;
final List<T> list = new ArrayList();
final String sql = "SELECT a.* FROM " + info.getTable() + " a"
+ (node == null ? "" : node.createFilterSQLExpress(info, bean)) + createFilterSQLOrderBy(info, flipper);
final CharSequence join = node == null ? null : node.createSQLJoin(info);
final CharSequence where = node == null ? null : node.createSQLExpress(info, bean);
final String sql = "SELECT a.* FROM " + info.getTable() + " a" + (join == null ? "" : join)
+ ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper);
if (debug.get() && info.isLoggable(Level.FINEST))
logger.finest(clazz.getSimpleName() + " query sql=" + sql + (flipper == null ? "" : (" LIMIT " + flipper.index() + "," + flipper.getSize())));
final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

View File

@@ -25,81 +25,11 @@ import java.util.stream.*;
*/
public final class EntityCache<T> {
private static class UniqueSequence implements Serializable {
private final Serializable[] value;
public UniqueSequence(Serializable[] val) {
this.value = val;
}
@Override
public int hashCode() {
return Arrays.deepHashCode(this.value);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final UniqueSequence other = (UniqueSequence) obj;
if (value.length != other.value.length) return false;
for (int i = 0; i < value.length; i++) {
if (!value[i].equals(other.value[i])) return false;
}
return true;
}
}
private static interface UniqueAttribute<T> extends Predicate<FilterNode> {
public Serializable getValue(T bean);
@Override
public boolean test(FilterNode node);
public static <T> UniqueAttribute<T> create(final Attribute<T, Serializable>[] attributes) {
if (attributes.length == 1) {
final Attribute<T, Serializable> attribute = attributes[0];
return new UniqueAttribute<T>() {
@Override
public Serializable getValue(T bean) {
return attribute.get(bean);
}
@Override
public boolean test(FilterNode node) {
return true;
}
};
} else {
return new UniqueAttribute<T>() {
@Override
public Serializable getValue(T bean) {
final Serializable[] rs = new Serializable[attributes.length];
for (int i = 0; i < rs.length; i++) {
rs[i] = attributes[i].get(bean);
}
return new UniqueSequence(rs);
}
@Override
public boolean test(FilterNode node) {
return true;
}
};
}
}
}
private static final Logger logger = Logger.getLogger(EntityCache.class.getName());
private final ConcurrentHashMap<Serializable, T> map = new ConcurrentHashMap();
private final CopyOnWriteArrayList<T> list = new CopyOnWriteArrayList(); // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%;
private final Collection<T> list = new CopyOnWriteArrayList(); // CopyOnWriteArrayList 插入慢、查询快; 10w数据插入需要3.2秒; ConcurrentLinkedQueue 插入快、查询慢10w数据查询需要 0.062秒, 查询慢40%;
private final HashMap<UniqueAttribute<T>, ConcurrentHashMap<Serializable, Collection<T>>> uniques = new HashMap<>();
@@ -180,14 +110,19 @@ public final class EntityCache<T> {
}
public boolean exists(final Predicate<T> filter) {
return (filter != null) && listStream().filter(filter).findFirst().isPresent();
return (filter != null) && this.list.stream().filter(filter).findFirst().isPresent();
}
public <K, V> Map<Serializable, Number> getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, final FilterNode node, final FilterBean bean) {
public <K, V> Map<Serializable, Number> getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, final FilterNode node) {
return getMapResult(keyColumn, reckon, reckonColumn, node, null);
}
public <K, V> Map<Serializable, Number> getMapResult(final String keyColumn, final Reckon reckon, final String reckonColumn, FilterNode node, final FilterBean bean) {
if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass());
final Attribute<T, Serializable> keyAttr = info.getAttribute(keyColumn);
final Predicate filter = node == null ? null : node.createFilterPredicate(this.info, bean);
final Predicate filter = node == null ? null : node.createPredicate(this, bean);
final Attribute reckonAttr = reckonColumn == null ? null : info.getAttribute(reckonColumn);
Stream<T> stream = listStream();
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
Collector<T, Map, ?> collector = null;
final Class valtype = reckonAttr == null ? null : reckonAttr.type();
@@ -232,10 +167,15 @@ public final class EntityCache<T> {
return rs;
}
public <V> Number getNumberResult(final Reckon reckon, final String column, final FilterNode node, final FilterBean bean) {
public <V> Number getNumberResult(final Reckon reckon, final String column, final FilterNode node) {
return getNumberResult(reckon, column, node, null);
}
public <V> Number getNumberResult(final Reckon reckon, final String column, FilterNode node, final FilterBean bean) {
if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass());
final Attribute<T, Serializable> attr = column == null ? null : info.getAttribute(column);
final Predicate<T> filter = node == null ? null : node.createFilterPredicate(this.info, bean);
Stream<T> stream = listStream();
final Predicate<T> filter = node == null ? null : node.createPredicate(this, bean);
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
switch (reckon) {
case AVG:
@@ -299,21 +239,30 @@ public final class EntityCache<T> {
return -1;
}
public Sheet<T> querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return querySheet(selects, flipper, node, null);
}
public Sheet<T> querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) {
return querySheet(true, selects, flipper, node, bean);
}
public Sheet<T> querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, final FilterNode node, final FilterBean bean) {
final Predicate<T> filter = node == null ? null : node.createFilterPredicate(this.info, bean);
final Comparator<T> comparator = FilterNode.createFilterComparator(this, flipper);
public Sheet<T> querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, final FilterNode node) {
return querySheet(needtotal, selects, flipper, node, null);
}
public Sheet<T> querySheet(final boolean needtotal, final SelectColumn selects, final Flipper flipper, FilterNode node, final FilterBean bean) {
if (node == null && bean != null) node = FilterBeanNode.load(bean.getClass());
final Predicate<T> filter = node == null ? null : node.createPredicate(this, bean);
final Comparator<T> comparator = createComparator(flipper);
long total = 0;
if (needtotal) {
Stream<T> stream = listStream();
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
total = stream.count();
}
if (needtotal && total == 0) return new Sheet<>();
Stream<T> stream = listStream();
Stream<T> stream = this.list.stream();
if (filter != null) stream = stream.filter(filter);
if (comparator != null) stream = stream.sorted(comparator);
if (flipper != null) stream = stream.skip(flipper.index()).limit(flipper.getSize());
@@ -327,9 +276,9 @@ public final class EntityCache<T> {
}
} else {
final List<Attribute<T, Serializable>> attrs = new ArrayList<>();
for (Map.Entry<String, Attribute<T, Serializable>> en : info.attributes.entrySet()) {
if (selects.validate(en.getKey())) attrs.add(en.getValue());
}
info.forEachAttribute((k, v) -> {
if (selects.validate(k)) attrs.add(v);
});
Consumer<? super T> action = x -> {
final T item = creator.create();
for (Attribute attr : attrs) {
@@ -371,7 +320,7 @@ public final class EntityCache<T> {
public Serializable[] delete(final FilterNode node) {
if (node == null || this.list.isEmpty()) return new Serializable[0];
Object[] rms = listStream().filter(node.createFilterPredicate(this.info, null)).toArray();
Object[] rms = this.list.stream().filter(node.createPredicate(this, null)).toArray();
Serializable[] ids = new Serializable[rms.length];
int i = -1;
for (Object o : rms) {
@@ -453,15 +402,237 @@ public final class EntityCache<T> {
return rs;
}
private Stream<T> listStream() {
return this.list.stream();
public Attribute<T, Serializable> getAttribute(String fieldname) {
return info.getAttribute(fieldname);
}
protected Comparator<T> getSortComparator(String sort) {
return this.sortComparators.get(sort);
}
//-------------------------------------------------------------------------------------------------------------------------------
protected Comparator<T> createComparator(Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return null;
final String sort = flipper.getSort();
Comparator<T> comparator = this.sortComparators.get(sort);
if (comparator != null) return comparator;
for (String item : sort.split(",")) {
if (item.trim().isEmpty()) continue;
String[] sub = item.trim().split("\\s+");
int pos = sub[0].indexOf('(');
Attribute<T, Serializable> attr;
if (pos <= 0) {
attr = getAttribute(sub[0]);
} else { //含SQL函数
int pos2 = sub[0].lastIndexOf(')');
final Attribute<T, Serializable> pattr = getAttribute(sub[0].substring(pos + 1, pos2));
final String func = sub[0].substring(0, pos);
if ("ABS".equalsIgnoreCase(func)) {
if (pattr.type() == int.class || pattr.type() == Integer.class) {
attr = new Attribute<T, Serializable>() {
protected void putSortComparator(String sort, Comparator<T> comparator) {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(T obj) {
return Math.abs(((Number) pattr.get(obj)).intValue());
}
@Override
public void set(T obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == long.class || pattr.type() == Long.class) {
attr = new Attribute<T, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(T obj) {
return Math.abs(((Number) pattr.get(obj)).longValue());
}
@Override
public void set(T obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == float.class || pattr.type() == Float.class) {
attr = new Attribute<T, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(T obj) {
return Math.abs(((Number) pattr.get(obj)).floatValue());
}
@Override
public void set(T obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == double.class || pattr.type() == Double.class) {
attr = new Attribute<T, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(T obj) {
return Math.abs(((Number) pattr.get(obj)).doubleValue());
}
@Override
public void set(T obj, Serializable value) {
pattr.set(obj, value);
}
};
} else {
throw new RuntimeException("Flipper not supported sort illegal type by ABS (" + flipper.getSort() + ")");
}
} else if (func.isEmpty()) {
attr = pattr;
} else {
throw new RuntimeException("Flipper not supported sort illegal function (" + flipper.getSort() + ")");
}
}
Comparator<T> c = (sub.length > 1 && sub[1].equalsIgnoreCase("DESC")) ? (T o1, T o2) -> {
Comparable c1 = (Comparable) attr.get(o1);
Comparable c2 = (Comparable) attr.get(o2);
return c2 == null ? -1 : c2.compareTo(c1);
} : (T o1, T o2) -> {
Comparable c1 = (Comparable) attr.get(o1);
Comparable c2 = (Comparable) attr.get(o2);
return c1 == null ? -1 : c1.compareTo(c2);
};
if (comparator == null) {
comparator = c;
} else {
comparator = comparator.thenComparing(c);
}
}
this.sortComparators.put(sort, comparator);
return comparator;
}
private static class UniqueSequence implements Serializable {
private final Serializable[] value;
public UniqueSequence(Serializable[] val) {
this.value = val;
}
@Override
public int hashCode() {
return Arrays.deepHashCode(this.value);
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final UniqueSequence other = (UniqueSequence) obj;
if (value.length != other.value.length) return false;
for (int i = 0; i < value.length; i++) {
if (!value[i].equals(other.value[i])) return false;
}
return true;
}
}
private static interface UniqueAttribute<T> extends Predicate<FilterNode> {
public Serializable getValue(T bean);
@Override
public boolean test(FilterNode node);
public static <T> UniqueAttribute<T> create(final Attribute<T, Serializable>[] attributes) {
if (attributes.length == 1) {
final Attribute<T, Serializable> attribute = attributes[0];
return new UniqueAttribute<T>() {
@Override
public Serializable getValue(T bean) {
return attribute.get(bean);
}
@Override
public boolean test(FilterNode node) {
return true;
}
};
} else {
return new UniqueAttribute<T>() {
@Override
public Serializable getValue(T bean) {
final Serializable[] rs = new Serializable[attributes.length];
for (int i = 0; i < rs.length; i++) {
rs[i] = attributes[i].get(bean);
}
return new UniqueSequence(rs);
}
@Override
public boolean test(FilterNode node) {
return true;
}
};
}
}
}
}

View File

@@ -44,7 +44,7 @@ public final class EntityInfo<T> {
//key是field的name 不是sql字段。
//存放所有与数据库对应的字段, 包括主键
final Map<String, Attribute<T, Serializable>> attributes = new HashMap<>();
private final HashMap<String, Attribute<T, Serializable>> attributes = new HashMap<>();
//key是field的name value是Column的别名即数据库表的字段名
//只有field.name 与 Column.name不同才存放在aliasmap里.
@@ -93,10 +93,12 @@ public final class EntityInfo<T> {
synchronized (entityInfos) {
rs = entityInfos.get(clazz);
if (rs == null) {
if (nodeid < 0) throw new IllegalArgumentException("nodeid(" + nodeid + ") is illegal");
rs = new EntityInfo(clazz, nodeid, cacheForbidden);
entityInfos.put(clazz, rs);
AutoLoad auto = clazz.getAnnotation(AutoLoad.class);
if (rs.cache != null && auto != null && auto.value() && fullloader != null) {
if (rs.cache != null && auto != null && auto.value()) {
if (fullloader == null) throw new IllegalArgumentException(clazz.getName() + " auto loader is illegal");
rs.cache.fullLoad(fullloader.apply(clazz));
}
}
@@ -107,7 +109,7 @@ public final class EntityInfo<T> {
private EntityInfo(Class<T> type, int nodeid, final boolean cacheForbidden) {
this.type = type;
//---------------------------------------------
this.nodeid = nodeid;
this.nodeid = nodeid >= 0 ? nodeid : 0;
DistributeGenerator.DistributeTables dt = type.getAnnotation(DistributeGenerator.DistributeTables.class);
this.distributeTables = dt == null ? null : dt.value();
@@ -267,7 +269,12 @@ public final class EntityInfo<T> {
return this.primary;
}
public void forEachAttribute(BiConsumer<String, Attribute<T, Serializable>> action) {
this.attributes.forEach(action);
}
public Attribute<T, Serializable> getAttribute(String fieldname) {
if (fieldname == null) return null;
return this.attributes.get(fieldname);
}
@@ -279,12 +286,32 @@ public final class EntityInfo<T> {
return this.aliasmap == null;
}
public String getSortOrderbySql(String sort) {
return this.sortOrderbySqls.get(sort);
}
protected void putSortOrderbySql(String sort, String sql) {
protected String createSQLOrderby(Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return "";
final String sort = flipper.getSort();
String sql = this.sortOrderbySqls.get(sort);
if (sql != null) return sql;
final StringBuilder sb = new StringBuilder();
sb.append(" ORDER BY ");
if (isNoAlias()) {
sb.append(sort);
} else {
boolean flag = false;
for (String item : sort.split(",")) {
if (item.isEmpty()) continue;
String[] sub = item.split("\\s+");
if (flag) sb.append(',');
if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) {
sb.append("a.").append(getSQLColumn(sub[0])).append(" ASC");
} else {
sb.append("a.").append(getSQLColumn(sub[0])).append(" DESC");
}
flag = true;
}
}
sql = sb.toString();
this.sortOrderbySqls.put(sort, sql);
return sql;
}
//根据field字段名获取数据库对应的字段名

View File

@@ -26,6 +26,10 @@ final class FilterBeanNode extends FilterNode {
private static final ConcurrentHashMap<Class, FilterBeanNode> beanodes = new ConcurrentHashMap<>();
public static <T extends FilterBean> FilterBeanNode load(Class<T> clazz) {
return load(clazz, -1, true, null);
}
public static <T extends FilterBean> FilterBeanNode load(Class<T> clazz, final int nodeid, final boolean cacheForbidden,
Function<Class, List> fullloader) {
FilterBeanNode rs = beanodes.get(clazz);
@@ -55,17 +59,19 @@ final class FilterBeanNode extends FilterNode {
if (field.getAnnotation(Ignore.class) != null) continue;
if (field.getAnnotation(Transient.class) != null) continue;
final boolean pubmod = Modifier.isPublic(field.getModifiers());
char[] chars = field.getName().toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
final Class t = field.getType();
Method getter;
Method getter = null;
try {
getter = cltmp.getMethod(((t == boolean.class || t == Boolean.class) ? "is" : "get") + new String(chars));
} catch (Exception ex) {
continue;
if (!pubmod) continue;
}
fields.add(field.getName());
FilterBeanNode newnode = new FilterBeanNode(field.getName(), true, Attribute.create(getter, null));
FilterBeanNode newnode = new FilterBeanNode(field.getName(), true, pubmod ? Attribute.create(field) : Attribute.create(getter, null));
newnode.setField(field);
//------------------------------------
{
@@ -163,7 +169,7 @@ final class FilterBeanNode extends FilterNode {
protected FilterBeanNode(String col, boolean sign, Attribute beanAttr) {
this.column = col;
this.signand = sign;
this.and = sign;
this.beanAttribute = beanAttr;
}
@@ -195,7 +201,7 @@ final class FilterBeanNode extends FilterNode {
@Override
protected void append(FilterNode node, boolean sign) {
FilterBeanNode newnode = new FilterBeanNode(this.column, this.signand, this.beanAttribute);
FilterBeanNode newnode = new FilterBeanNode(this.column, this.and, this.beanAttribute);
newnode.express = this.express;
newnode.nodes = this.nodes;
newnode.foreignEntity = this.foreignEntity;
@@ -211,7 +217,7 @@ final class FilterBeanNode extends FilterNode {
this.nodes = new FilterNode[]{newnode};
this.column = node.column;
this.express = node.express;
this.signand = sign;
this.and = sign;
this.setValue(node.getValue());
if (node instanceof FilterBeanNode) {
FilterBeanNode beanNode = ((FilterBeanNode) node);
@@ -230,29 +236,27 @@ final class FilterBeanNode extends FilterNode {
}
@Override
protected <T> StringBuilder createFilterSQLExpress(final boolean first, final EntityInfo<T> info, FilterBean bean) {
if (joinSQL == null || !first) return super.createFilterSQLExpress(first, info, bean);
StringBuilder sb = super.createFilterSQLExpress(first, info, bean);
if (joinSQL == null) return sb;
return new StringBuilder(sb.length() + joinSQL.length()).append(joinSQL).append(sb);
protected <T> CharSequence createSQLJoin(final EntityInfo<T> info) {
if (joinSQL == null) return null;
return new StringBuilder(joinSQL);
}
@Override
protected <T> Predicate<T> createFilterPredicate(final EntityInfo<T> info, FilterBean bean) {
//if ((this.joinSQL == null && first) || this.foreignEntity == null) return super.createFilterPredicate(info, bean);
if (this.foreignEntity == null) return super.createFilterPredicate(info, bean);
protected <T> Predicate<T> createPredicate(final EntityCache<T> cache, FilterBean bean) {
if (this.foreignEntity == null) return super.createPredicate(cache, bean);
final Map<EntityInfo, Predicate> foreign = new HashMap<>();
Predicate<T> result = null;
putForeignPredicate(foreign, bean);
putForeignPredicate(cache, foreign, bean);
if (this.nodes != null) {
for (FilterNode n : this.nodes) {
FilterBeanNode node = (FilterBeanNode) n;
if (node.foreignEntity == null) {
Predicate<T> f = node.createFilterPredicate(info, bean);
Predicate<T> f = node.createPredicate(cache, bean);
if (f == null) continue;
final Predicate<T> one = result;
final Predicate<T> two = f;
result = (result == null) ? f : (signand ? new Predicate<T>() {
result = (result == null) ? f : (and ? new Predicate<T>() {
@Override
public boolean test(T t) {
@@ -276,7 +280,7 @@ final class FilterBeanNode extends FilterNode {
}
});
} else {
putForeignPredicate(foreign, bean);
putForeignPredicate(cache, foreign, bean);
}
}
}
@@ -284,8 +288,7 @@ final class FilterBeanNode extends FilterNode {
final String byjoinCol = this.byjoinColumn;
final Attribute foreignAttr = this.foreignAttribute;
for (final Map.Entry<EntityInfo, Predicate> en : foreign.entrySet()) {
Attribute<T, Serializable> byjoinAttr = info.getAttribute(byjoinCol);
final EntityCache cache = en.getKey().getCache();
Attribute<T, Serializable> byjoinAttr = cache.getAttribute(byjoinCol);
final Predicate p = en.getValue();
Predicate<T> f = new Predicate<T>() {
@@ -303,7 +306,7 @@ final class FilterBeanNode extends FilterNode {
};
final Predicate<T> one = result;
final Predicate<T> two = f;
result = (result == null) ? f : (signand ? new Predicate<T>() {
result = (result == null) ? f : (and ? new Predicate<T>() {
@Override
public boolean test(T t) {
@@ -330,21 +333,21 @@ final class FilterBeanNode extends FilterNode {
return result;
}
private <T> void putForeignPredicate(final Map<EntityInfo, Predicate> foreign, FilterBean bean) {
private <T> void putForeignPredicate(final EntityCache<T> cache, final Map<EntityInfo, Predicate> foreign, FilterBean bean) {
if (this.foreignEntity == null) return;
final Serializable val = getValue(bean);
final Serializable val = getElementValue(bean);
Predicate filter = (val == null && express != ISNULL && express != ISNOTNULL) ? new Predicate<T>() {
@Override
public boolean test(T t) {
return signand;
return and;
}
@Override
public String toString() {
return "" + signand;
return "" + and;
}
} : super.createFilterPredicate(this.columnAttribute, val);
} : super.createElementPredicate(cache, this.columnAttribute, bean);
if (filter == null) return;
Predicate p = foreign.get(this.foreignEntity);
if (p == null) {
@@ -352,7 +355,7 @@ final class FilterBeanNode extends FilterNode {
} else {
final Predicate<T> one = p;
final Predicate<T> two = filter;
p = signand ? new Predicate<T>() {
p = and ? new Predicate<T>() {
@Override
public boolean test(T t) {
@@ -380,12 +383,12 @@ final class FilterBeanNode extends FilterNode {
}
@Override
protected boolean isJoinAllCached() {
protected boolean isCacheUseable() {
return joinallcached;
}
@Override
protected Serializable getValue(FilterBean bean) {
protected Serializable getElementValue(FilterBean bean) {
if (bean == null || beanAttribute == null) return null;
Serializable rs = (Serializable) beanAttribute.get(bean);
if (rs == null) return null;

View File

@@ -0,0 +1,66 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.source;
import java.util.*;
/**
*
* @author zhangjx
*/
public final class FilterJoinNode extends FilterNode {
private Class joinClass;
private String joinColumn;
private String foreignColumn;
public FilterJoinNode() {
}
protected FilterJoinNode(Class joinClass, String joinColumn, String foreignColumn) {
this.joinClass = joinClass;
this.joinColumn = joinColumn;
this.foreignColumn = foreignColumn;
}
public static FilterJoinNode create(Class joinClass, String joinColumn) {
return create(joinClass, joinColumn, joinColumn);
}
public static FilterJoinNode create(Class joinClass, String joinColumn, String foreignColumn) {
Objects.requireNonNull(joinClass);
Objects.requireNonNull(joinColumn);
Objects.requireNonNull(foreignColumn);
return new FilterJoinNode(joinClass, joinColumn, foreignColumn);
}
public Class getJoinClass() {
return joinClass;
}
public void setJoinClass(Class joinClass) {
this.joinClass = joinClass;
}
public String getJoinColumn() {
return joinColumn;
}
public void setJoinColumn(String joinColumn) {
this.joinColumn = joinColumn;
}
public String getForeignColumn() {
return foreignColumn;
}
public void setForeignColumn(String foreignColumn) {
this.foreignColumn = foreignColumn;
}
}

View File

@@ -38,12 +38,11 @@ public class FilterNode {
protected Serializable value;
//----------------------------------------------
protected boolean signand = true;
protected boolean and = true;
protected FilterNode[] nodes;
protected FilterNode() {
public FilterNode() {
}
protected FilterNode(String col, FilterExpress exp, Serializable val) {
@@ -69,7 +68,7 @@ public class FilterNode {
}
public final FilterNode and(String column, Serializable value) {
return and(new FilterNode(column, null, value));
return and(column, null, value);
}
public final FilterNode and(String column, FilterExpress express, Serializable value) {
@@ -81,7 +80,7 @@ public class FilterNode {
}
public final FilterNode or(String column, Serializable value) {
return or(new FilterNode(column, null, value));
return or(column, null, value);
}
public final FilterNode or(String column, FilterExpress express, Serializable value) {
@@ -90,12 +89,18 @@ public class FilterNode {
protected final FilterNode any(FilterNode node, boolean sign) {
Objects.requireNonNull(node);
if (nodes == null) {
nodes = new FilterNode[]{node};
this.signand = sign;
if (this.column == null) {
this.column = node.column;
this.express = node.express;
this.value = node.value;
return this;
}
if (signand == sign) {
if (nodes == null) {
nodes = new FilterNode[]{node};
this.and = sign;
return this;
}
if (and == sign) {
FilterNode[] newsiblings = new FilterNode[nodes.length + 1];
System.arraycopy(nodes, 0, newsiblings, 0, nodes.length);
newsiblings[nodes.length] = node;
@@ -106,23 +111,51 @@ public class FilterNode {
return this;
}
/**
* 该方法需要重载
*
* @param node
* @param sign
*/
protected void append(FilterNode node, boolean sign) {
FilterNode newnode = new FilterNode(this.column, this.express, this.value);
newnode.signand = this.signand;
newnode.and = this.and;
newnode.nodes = this.nodes;
this.nodes = new FilterNode[]{newnode, node};
this.tabalis = null;
this.column = null;
this.express = null;
this.signand = sign;
this.and = sign;
this.value = null;
}
protected Serializable getValue(FilterBean bean) {
/**
* 该方法需要重载
*
* @param bean
* @return
*/
protected Serializable getElementValue(final FilterBean bean) {
return value;
}
protected boolean isJoinAllCached() {
/**
* 该方法需要重载
*
* @param <T>
* @param info
* @return
*/
protected <T> CharSequence createSQLJoin(final EntityInfo<T> info) {
return null;
}
/**
* 该方法需要重载
*
* @return
*/
protected boolean isCacheUseable() {
return true;
}
@@ -134,50 +167,42 @@ public class FilterNode {
return new FilterNode(column, express, value);
}
protected final <T> StringBuilder createFilterSQLExpress(final EntityInfo<T> info, FilterBean bean) {
return createFilterSQLExpress(true, info, bean);
}
protected <T> StringBuilder createFilterSQLExpress(final boolean first, final EntityInfo<T> info, FilterBean bean) {
final Serializable val = getValue(bean);
if (val == null && (express == ISNULL || express == ISNOTNULL)) return new StringBuilder(0);
StringBuilder sb0 = createFilterSQLExpress(info, val);
if (this.nodes == null) {
if (sb0 == null) return new StringBuilder(0);
if (!first) return sb0;
return new StringBuilder(sb0.length() + 8).append(" WHERE ").append(sb0);
}
protected final <T> CharSequence createSQLExpress(final EntityInfo<T> info, final FilterBean bean) {
CharSequence sb0 = createElementSQLExpress(info, bean);
if (this.nodes == null) return sb0;
final StringBuilder rs = new StringBuilder();
rs.append(first ? " WHERE (" : " (");
rs.append('(');
boolean more = false;
if (sb0 != null && sb0.length() > 2) {
more = true;
rs.append(sb0);
}
for (FilterNode node : this.nodes) {
StringBuilder f = node.createFilterSQLExpress(false, info, bean);
CharSequence f = node.createSQLExpress(info, bean);
if (f == null || f.length() < 3) continue;
if (more) rs.append(signand ? " AND " : " OR ");
if (more) rs.append(and ? " AND " : " OR ");
rs.append(f);
more = true;
}
rs.append(')');
if (rs.length() < (first ? 10 : 5)) return new StringBuilder(0);
if (rs.length() < 5) return null;
return rs;
}
private <T> StringBuilder createFilterSQLExpress(final EntityInfo<T> info, Serializable val0) {
protected final <T> CharSequence createElementSQLExpress(final EntityInfo<T> info, final FilterBean bean) {
if (column == null) return null;
final StringBuilder val = formatValue(val0);
if (express == ISNULL || express == ISNOTNULL) {
StringBuilder sb = new StringBuilder();
if (tabalis != null) sb.append(tabalis).append('.');
sb.append(info.getSQLColumn(column)).append(' ').append(express.value());
return sb;
}
final StringBuilder val = formatToString(express, getElementValue(bean));
if (val == null) return null;
StringBuilder sb = new StringBuilder();
StringBuilder sb = new StringBuilder(32);
if (tabalis != null) sb.append(tabalis).append('.');
sb.append(info.getSQLColumn(column)).append(' ');
switch (express) {
case ISNULL:
case ISNOTNULL:
sb.append(express.value());
break;
case OPAND:
case OPOR:
sb.append(express.value()).append(' ').append(val).append(" > 0");
@@ -192,45 +217,16 @@ public class FilterNode {
return sb;
}
protected static <E> String createFilterSQLOrderBy(EntityInfo<E> info, Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return "";
final String sort = flipper.getSort();
String sql = info.getSortOrderbySql(sort);
if (sql != null) return sql;
final StringBuilder sb = new StringBuilder();
sb.append(" ORDER BY ");
if (info.isNoAlias()) {
sb.append(sort);
} else {
boolean flag = false;
for (String item : sort.split(",")) {
if (item.isEmpty()) continue;
String[] sub = item.split("\\s+");
if (flag) sb.append(',');
if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) {
sb.append("a.").append(info.getSQLColumn(sub[0])).append(" ASC");
} else {
sb.append("a.").append(info.getSQLColumn(sub[0])).append(" DESC");
}
flag = true;
}
}
sql = sb.toString();
info.putSortOrderbySql(sort, sql);
return sql;
}
protected <T> Predicate<T> createFilterPredicate(final EntityInfo<T> info, FilterBean bean) {
if (info == null || (column == null && this.nodes == null)) return null;
final Serializable val = getValue(bean);
Predicate<T> filter = createFilterPredicate(column == null ? null : info.getAttribute(column), val);
protected <T> Predicate<T> createPredicate(final EntityCache<T> cache, final FilterBean bean) {
if (cache == null || (column == null && this.nodes == null)) return null;
Predicate<T> filter = createElementPredicate(cache, bean);
if (this.nodes == null) return filter;
for (FilterNode node : this.nodes) {
Predicate<T> f = node.createFilterPredicate(info, bean);
Predicate<T> f = node.createPredicate(cache, bean);
if (f == null) continue;
final Predicate<T> one = filter;
final Predicate<T> two = f;
filter = (filter == null) ? f : (signand ? new Predicate<T>() {
filter = (filter == null) ? f : (and ? new Predicate<T>() {
@Override
public boolean test(T t) {
@@ -257,35 +253,39 @@ public class FilterNode {
return filter;
}
protected final <T> Predicate<T> createFilterPredicate(final Attribute<T, Serializable> attr, Serializable val0) {
if (val0 == null) {
if (express == ISNULL) return new Predicate<T>() {
protected final <T> Predicate<T> createElementPredicate(final EntityCache<T> cache, final FilterBean bean) {
return createElementPredicate(cache, cache.getAttribute(column), bean);
}
@Override
public boolean test(T t) {
return attr.get(t) == null;
}
protected final <T> Predicate<T> createElementPredicate(final EntityCache<T> cache, final Attribute<T, Serializable> attr, final FilterBean bean) {
@Override
public String toString() {
return attr.field() + " = null";
}
};
if (express == ISNOTNULL) return new Predicate<T>() {
if (express == ISNULL) return new Predicate<T>() {
@Override
public boolean test(T t) {
return attr.get(t) != null;
}
@Override
public boolean test(T t) {
return attr.get(t) == null;
}
@Override
public String toString() {
return attr.field() + " != null";
}
};
return null;
}
@Override
public String toString() {
return attr.field() + " = null";
}
};
if (express == ISNOTNULL) return new Predicate<T>() {
@Override
public boolean test(T t) {
return attr.get(t) != null;
}
@Override
public String toString() {
return attr.field() + " != null";
}
};
if (attr == null) return null;
Serializable val0 = getElementValue(bean);
if (val0 == null) return null;
final Class atype = attr.type();
final Class valtype = val0.getClass();
@@ -743,174 +743,51 @@ public class FilterNode {
return null;
}
protected static <E> Comparator<E> createFilterComparator(EntityCache<E> cache, Flipper flipper) {
if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty()) return null;
final String sort = flipper.getSort();
Comparator<E> comparator = cache.getSortComparator(sort);
if (comparator != null) return comparator;
for (String item : sort.split(",")) {
if (item.trim().isEmpty()) continue;
String[] sub = item.trim().split("\\s+");
int pos = sub[0].indexOf('(');
Attribute<E, Serializable> attr;
if (pos <= 0) {
attr = cache.info.getAttribute(sub[0]);
} else { //含SQL函数
int pos2 = sub[0].lastIndexOf(')');
final Attribute<E, Serializable> pattr = cache.info.getAttribute(sub[0].substring(pos + 1, pos2));
final String func = sub[0].substring(0, pos);
if ("ABS".equalsIgnoreCase(func)) {
if (pattr.type() == int.class || pattr.type() == Integer.class) {
attr = new Attribute<E, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(E obj) {
return Math.abs(((Number) pattr.get(obj)).intValue());
}
@Override
public void set(E obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == long.class || pattr.type() == Long.class) {
attr = new Attribute<E, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(E obj) {
return Math.abs(((Number) pattr.get(obj)).longValue());
}
@Override
public void set(E obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == float.class || pattr.type() == Float.class) {
attr = new Attribute<E, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(E obj) {
return Math.abs(((Number) pattr.get(obj)).floatValue());
}
@Override
public void set(E obj, Serializable value) {
pattr.set(obj, value);
}
};
} else if (pattr.type() == double.class || pattr.type() == Double.class) {
attr = new Attribute<E, Serializable>() {
@Override
public Class type() {
return pattr.type();
}
@Override
public Class declaringClass() {
return pattr.declaringClass();
}
@Override
public String field() {
return pattr.field();
}
@Override
public Serializable get(E obj) {
return Math.abs(((Number) pattr.get(obj)).doubleValue());
}
@Override
public void set(E obj, Serializable value) {
pattr.set(obj, value);
}
};
} else {
throw new RuntimeException("Flipper not supported sort illegal type by ABS (" + flipper.getSort() + ")");
}
} else if (func.isEmpty()) {
attr = pattr;
} else {
throw new RuntimeException("Flipper not supported sort illegal function (" + flipper.getSort() + ")");
}
}
Comparator<E> c = (sub.length > 1 && sub[1].equalsIgnoreCase("DESC")) ? (E o1, E o2) -> {
Comparable c1 = (Comparable) attr.get(o1);
Comparable c2 = (Comparable) attr.get(o2);
return c2 == null ? -1 : c2.compareTo(c1);
} : (E o1, E o2) -> {
Comparable c1 = (Comparable) attr.get(o1);
Comparable c2 = (Comparable) attr.get(o2);
return c1 == null ? -1 : c1.compareTo(c2);
};
if (comparator == null) {
comparator = c;
} else {
comparator = comparator.thenComparing(c);
}
}
cache.putSortComparator(sort, comparator);
return comparator;
@Override
public String toString() {
return toString(null);
}
protected StringBuilder formatValue(Object value) {
return formatValue(express, value);
public String toString(final FilterBean bean) {
StringBuilder sb = new StringBuilder();
if (nodes == null) {
if (column != null) {
Serializable ev = getElementValue(bean);
if (express == ISNULL || express == ISNOTNULL) {
sb.append(column).append(' ').append(express.value());
} else if (ev != null) {
sb.append(column).append(' ').append(express.value()).append(' ').append(formatToString(express, ev));
}
}
} else {
boolean more = false;
if (column != null) {
Serializable ev = getElementValue(bean);
if (express == ISNULL || express == ISNOTNULL) {
sb.append('(').append(column).append(' ').append(express.value());
more = true;
} else if (ev != null) {
sb.append('(').append(column).append(' ').append(express.value()).append(' ').append(formatToString(express, ev));
more = true;
}
}
for (FilterNode node : this.nodes) {
String s = node.toString();
if (s.isEmpty()) continue;
if (sb.length() > 0) sb.append(and ? " AND " : " OR ");
sb.append(s);
}
if (more) sb.append(')');
}
return sb.toString();
}
protected static String formatToString(Object value) {
StringBuilder sb = formatValue(null, value);
StringBuilder sb = formatToString(null, value);
return sb == null ? null : sb.toString();
}
private static StringBuilder formatValue(FilterExpress express, Object value) {
private static StringBuilder formatToString(FilterExpress express, Object value) {
if (value == null) return null;
if (value instanceof Number) return new StringBuilder().append(value);
if (value instanceof CharSequence) {
@@ -937,7 +814,7 @@ public class FilterNode {
if (len == 0) return express == NOTIN ? null : new StringBuilder("(NULL)");
if (len == 1) {
Object firstval = Array.get(value, 0);
if (firstval != null && firstval.getClass().isArray()) return formatValue(express, firstval);
if (firstval != null && firstval.getClass().isArray()) return formatToString(express, firstval);
}
StringBuilder sb = new StringBuilder();
sb.append('(');
@@ -969,67 +846,51 @@ public class FilterNode {
return new StringBuilder().append(value);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (nodes == null) {
sb.append(column).append(' ').append(express.value()).append(' ').append(formatValue(value));
} else {
if (column != null) sb.append('(').append(column).append(' ').append(express.value()).append(' ').append(formatValue(value));
for (FilterNode node : this.nodes) {
if (sb.length() > 0) sb.append(signand ? " AND " : " OR ");
sb.append(node.toString());
}
sb.append(')');
}
return sb.toString();
}
public Serializable getValue() {
public final Serializable getValue() {
return value;
}
public void setValue(Serializable value) {
public final void setValue(Serializable value) {
this.value = value;
}
public boolean isSignand() {
return signand;
public final boolean isAnd() {
return and;
}
public void setSignand(boolean signand) {
this.signand = signand;
public final void setAnd(boolean and) {
this.and = and;
}
public String getTabalis() {
public final String getTabalis() {
return tabalis;
}
public void setTabalis(String tabalis) {
public final void setTabalis(String tabalis) {
this.tabalis = tabalis;
}
public String getColumn() {
public final String getColumn() {
return column;
}
public void setColumn(String column) {
public final void setColumn(String column) {
this.column = column;
}
public FilterExpress getExpress() {
public final FilterExpress getExpress() {
return express;
}
public void setExpress(FilterExpress express) {
public final void setExpress(FilterExpress express) {
this.express = express;
}
public FilterNode[] getNodes() {
public final FilterNode[] getNodes() {
return nodes;
}
public void setNodes(FilterNode[] nodes) {
public final void setNodes(FilterNode[] nodes) {
this.nodes = nodes;
}