增加FilterOrs功能

This commit is contained in:
redkale
2024-06-04 19:46:46 +08:00
parent e9645e6b05
commit e733980e33
7 changed files with 101 additions and 71 deletions

View File

@@ -46,7 +46,7 @@ public class EntityBuilder<T> {
// key类字段名 value数据库字段名
// 只有field.name 与 Column.name不同才存放在aliasmap里.
@Nullable
private final Map<String, String> aliasmap;
private final Map<String, String> aliasMap;
// Entity构建器参数Attribute 数组个数与constructorParameters相同
@Nullable
@@ -71,7 +71,7 @@ public class EntityBuilder<T> {
EntityBuilder(
Class<T> type,
Creator<T> creator,
Map<String, String> aliasmap,
Map<String, String> aliasMap,
String[] constructorParameters,
Attribute<T, Serializable>[] constructorAttributes,
Attribute<T, Serializable>[] unconstructorAttributes,
@@ -79,7 +79,7 @@ public class EntityBuilder<T> {
Attribute<T, Serializable>[] queryAttributes) {
this.type = type;
this.creator = creator;
this.aliasmap = aliasmap;
this.aliasMap = aliasMap;
this.constructorParameters = constructorParameters;
this.constructorAttributes = constructorAttributes;
this.unconstructorAttributes = unconstructorAttributes;
@@ -127,7 +127,8 @@ public class EntityBuilder<T> {
}
}
} catch (Exception e) {
throw new SourceException(type + " cannot find ConstructorParameters Creator");
throw new SourceException(type + " cannot find "
+ org.redkale.annotation.ConstructorParameters.class.getSimpleName() + " Creator");
}
}
Class cltmp = type;
@@ -569,11 +570,11 @@ public class EntityBuilder<T> {
* @return String
*/
public String getSQLColumn(String tabalis, String fieldname) {
return this.aliasmap == null
return this.aliasMap == null
? (tabalis == null ? fieldname : (tabalis + '.' + fieldname))
: (tabalis == null
? aliasmap.getOrDefault(fieldname, fieldname)
: (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname)));
? aliasMap.getOrDefault(fieldname, fieldname)
: (tabalis + '.' + aliasMap.getOrDefault(fieldname, fieldname)));
}
public boolean hasConstructorAttribute() {
@@ -587,7 +588,7 @@ public class EntityBuilder<T> {
*/
@ConvertDisabled
public boolean isNoAlias() {
return this.aliasmap == null;
return this.aliasMap == null;
}
@ConvertDisabled

View File

@@ -5,11 +5,10 @@
*/
package org.redkale.source;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 过滤字段标记
*

View File

@@ -5,28 +5,27 @@
*/
package org.redkale.source;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 默认情况下FilterBean下的过滤字段之间是AND关系。 <br>
* 当需要使用OR或AND OR组合过滤查询时需要使用 FilterGroup。 <br>
* FilterGroup 的value 必须是[OR]或者[AND]开头, 多级需要用点.分隔。 (注: 暂时不支持多级) <br>
* 当需要使用OR或AND OR组合过滤查询时需要使用 FilterOrs、FilterGroup。 <br>
* 示例一:
*
* <blockquote>
*
* <pre>
* &#64;FilterOrs({"g1"})
* public class TestFilterBean implements FilterBean {
*
* private int id;
*
* &#64;FilterGroup("[OR]g1")
* &#64;FilterGroup("g1")
* private String desc;
*
* &#64;FilterGroup("[OR]g1")
* &#64;FilterGroup("g1")
* private String name;
* }
* </pre>
@@ -40,22 +39,23 @@ import java.lang.annotation.*;
* <blockquote>
*
* <pre>
* &#64;FilterOrs({"g1","subg2"})
* public class TestFilterBean implements FilterBean {
*
* private int id;
*
* &#64;FilterGroup("[OR]g1.[AND]subg1")
* &#64;FilterGroup("g1.subg1")
* &#64;FilterColumn(express = LIKE)
* private String desc;
*
* &#64;FilterGroup("[OR]g1.[AND]subg1")
* &#64;FilterGroup("g1.subg1")
* &#64;FilterColumn(express = LIKE)
* private String name;
*
* &#64;FilterGroup("[OR]g1.[OR]subg2")
* &#64;FilterGroup("g1.subg2")
* private int age;
*
* &#64;FilterGroup("[OR]g1.[OR]subg2")
* &#64;FilterGroup("g1.subg2")
* private int birthday;
* }
* </pre>
@@ -63,14 +63,13 @@ import java.lang.annotation.*;
* </blockquote>
*
* 转换的SQL语句为: WHERE id = ? AND ((desc LIKE ? AND name LIKE ?) OR (age = ? OR birthday = ?)) <br>
* 因为默认是AND关系 &#64;FilterGroup("") 等价于 &#64;FilterGroup("[AND]") <br>
* 所以示例二的&#64;FilterGroup("[OR]g1.[AND]subg1") 可以简化为 &#64;FilterGroup("[OR]g1.subg1") <br>
*/
/**
* 详情见: https://redkale.org
*
* @see org.redkale.source.FilterBean
* @see org.redkale.source.FilterNode
* @see org.redkale.source.FilterOrs
* @author zhangjx
*/
@Documented
@@ -78,5 +77,5 @@ import java.lang.annotation.*;
@Retention(RUNTIME)
public @interface FilterGroup {
String value() default "[AND]";
String value() default "";
}

View File

@@ -5,14 +5,13 @@
*/
package org.redkale.source;
import static org.redkale.source.FilterExpress.*;
import java.io.Serializable;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import org.redkale.persistence.Transient;
import static org.redkale.source.FilterExpress.*;
import org.redkale.util.*;
/**
@@ -105,10 +104,6 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
this.string = CharSequence.class.isAssignableFrom(type);
}
private FilterNodeBean or(FilterNodeBean node) {
return any(node, true);
}
private FilterNodeBean and(FilterNodeBean node) {
return any(node, false);
}
@@ -203,7 +198,17 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
private static <T extends FilterBean> FilterNodeBean createFilterNodeBean(final Class<T> clazz) {
final Set<String> fields = new HashSet<>();
final Map<String, FilterNodeBean> nodemap = new LinkedHashMap();
Class cltmp = clazz;
Set<String> orItems = new HashSet<>();
// 读取FilterOrs
Class<?> cltmp = clazz;
do {
FilterOrs ors = cltmp.getAnnotation(FilterOrs.class);
if (ors != null) {
orItems.addAll(List.of(ors.value()));
}
} while ((cltmp = cltmp.getSuperclass()) != Object.class);
// 读取FilterGroup
cltmp = clazz;
do {
for (final Field field : cltmp.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
@@ -267,27 +272,20 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
groups[i] = refs[i].value();
}
if (groups.length == 0) {
groups = new String[] {"[AND]"};
groups = new String[] {""};
}
for (String key : groups) {
if (!key.startsWith("[AND]") && !key.startsWith("[OR]")) {
throw new SourceException(field + "'s FilterGroup.value(" + key
+ ") illegal, must be [AND] or [OR] startsWith");
}
FilterNodeBean node = nodemap.get(key);
if (node == null) {
nodemap.put(key, nodeBean);
} else if (nodeBean.joinClass == null && node.joinClass != null) { // 非joinNode 关联 joinNode
nodemap.put(
key,
nodeBean.any(
node,
key.substring(key.lastIndexOf('.') + 1)
.contains("[OR]")));
String subKey = key.substring(key.lastIndexOf('.') + 1);
boolean or = orItems.contains(subKey) || subKey.contains("[OR]");
nodemap.put(key, nodeBean.any(node, or));
} else {
node.any(
nodeBean,
key.substring(key.lastIndexOf('.') + 1).contains("[OR]"));
String subKey = key.substring(key.lastIndexOf('.') + 1);
boolean or = orItems.contains(subKey) || subKey.contains("[OR]");
node.any(nodeBean, or);
}
}
}
@@ -297,10 +295,11 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
nodemap.forEach((k, v) -> {
String[] keys = k.split("\\.");
LinkNode link = linkes.get(keys[0]);
boolean or = orItems.contains(keys[0]) || keys[0].contains("[OR]");
if (link == null) {
linkes.put(keys[0], new LinkNode(k, v));
linkes.put(keys[0], new LinkNode(keys, or, 0, v));
} else {
link.put(keys, 0, v);
link.put(keys, or, 0, v);
}
});
FilterNodeBean rs = null;
@@ -338,17 +337,10 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
public final Map<String, LinkNode> nexts = new LinkedHashMap<>();
public LinkNode(String keyString, FilterNodeBean node) {
String[] keys = keyString.split("\\.");
this.key = keys[0];
this.or = this.key.contains("[OR]");
put(keys, 0, node);
}
public LinkNode(String[] keyStrings, int pos, FilterNodeBean node) {
public LinkNode(String[] keyStrings, boolean or, int pos, FilterNodeBean node) {
this.key = keyStrings[pos];
this.or = this.key.contains("[OR]");
put(keyStrings, pos, node);
this.or = or;
put(keyStrings, or, pos, node);
}
public FilterNodeBean createFilterNodeBean() {
@@ -366,16 +358,16 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
return node;
}
public final void put(final String[] keys, int pos, final FilterNodeBean node) {
public final void put(final String[] keys, boolean or, int pos, final FilterNodeBean node) {
if (keys.length == pos + 1 && this.key.equals(keys[pos])) {
this.beans.add(node);
return;
}
LinkNode link = nexts.get(keys[pos + 1]);
if (link == null) {
nexts.put(keys[pos + 1], new LinkNode(keys, pos + 1, node));
nexts.put(keys[pos + 1], new LinkNode(keys, or, pos + 1, node));
} else {
link.put(keys, pos + 1, node);
link.put(keys, or, pos + 1, node);
}
}

View File

@@ -0,0 +1,34 @@
/*
*/
package org.redkale.source;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
/**
* 设置 {@link org.redkale.source.FilterGroup}的<b>OR</b>关系
*
* 详情见: https://redkale.org
*
* @see org.redkale.source.FilterBean
* @see org.redkale.source.FilterNode
* @see org.redkale.source.FilterGroup
* @author zhangjx
* @since 2.8.0
*/
@Documented
@Target({ElementType.TYPE})
@Retention(RUNTIME)
public @interface FilterOrs {
/**
* OR 关系的组名
*
* @return
*/
String[] value();
}

View File

@@ -3,15 +3,14 @@
*/
package org.redkale.util;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import static org.redkale.asm.Opcodes.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.*;
import java.util.stream.Collectors;
import org.redkale.asm.*;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import static org.redkale.asm.Opcodes.*;
import org.redkale.asm.Type;
/**
@@ -26,13 +25,19 @@ import org.redkale.asm.Type;
*/
public interface Copier<S, D> extends BiFunction<S, D, D> {
/** 是否跳过值为null的字段 */
/**
* 是否跳过值为null的字段
*/
public static final int OPTION_SKIP_NULL_VALUE = 1 << 1; // 2
/** 是否跳过值为空字符串的字段 */
/**
* 是否跳过值为空字符串的字段
*/
public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; // 4
/** 同名字段类型强制转换 */
/**
* 同名字段类型强制转换
*/
public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; // 8
/**

View File

@@ -5,8 +5,6 @@
*/
package org.redkale.test.source;
import static org.redkale.source.FilterExpress.*;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -18,6 +16,7 @@ import org.redkale.persistence.Entity;
import org.redkale.persistence.Id;
import org.redkale.persistence.Transient;
import org.redkale.source.*;
import static org.redkale.source.FilterExpress.*;
/** @author zhangjx */
public class FilterNodeTest {
@@ -184,28 +183,29 @@ public class FilterNodeTest {
System.out.println("bean.sheet = " + carEntity.getCache().querySheet(null, new Flipper(), beanNode));
}
@FilterOrs({"r", "c"})
public static class CarTestBean implements FilterBean {
@FilterGroup("[OR].[AND]a")
@FilterGroup("r.a")
@FilterColumn(express = GT)
@Transient
public long carid;
@FilterGroup("[OR].[AND]a.[OR]c")
@FilterGroup("r.a.c")
@FilterColumn(express = LIKE)
@FilterJoinColumn(
table = UserTestTable.class,
columns = {"userid", "username"})
public String username;
@FilterGroup("[OR].[AND]a.[OR]c")
@FilterGroup("r.a.c")
@FilterColumn(express = GT)
@FilterJoinColumn(
table = UserTestTable.class,
columns = {"userid", "username"})
public long createtime;
@FilterGroup("[OR]")
@FilterGroup("r")
@FilterColumn(express = LIKE)
@FilterJoinColumn(
table = CarTypeTable.class,