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

View File

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

View File

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

View File

@@ -5,14 +5,13 @@
*/ */
package org.redkale.source; package org.redkale.source;
import static org.redkale.source.FilterExpress.*;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import org.redkale.persistence.Transient; import org.redkale.persistence.Transient;
import static org.redkale.source.FilterExpress.*;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
@@ -105,10 +104,6 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
this.string = CharSequence.class.isAssignableFrom(type); this.string = CharSequence.class.isAssignableFrom(type);
} }
private FilterNodeBean or(FilterNodeBean node) {
return any(node, true);
}
private FilterNodeBean and(FilterNodeBean node) { private FilterNodeBean and(FilterNodeBean node) {
return any(node, false); 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) { private static <T extends FilterBean> FilterNodeBean createFilterNodeBean(final Class<T> clazz) {
final Set<String> fields = new HashSet<>(); final Set<String> fields = new HashSet<>();
final Map<String, FilterNodeBean> nodemap = new LinkedHashMap(); 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 { do {
for (final Field field : cltmp.getDeclaredFields()) { for (final Field field : cltmp.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) { if (Modifier.isStatic(field.getModifiers())) {
@@ -267,27 +272,20 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
groups[i] = refs[i].value(); groups[i] = refs[i].value();
} }
if (groups.length == 0) { if (groups.length == 0) {
groups = new String[] {"[AND]"}; groups = new String[] {""};
} }
for (String key : groups) { 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); FilterNodeBean node = nodemap.get(key);
if (node == null) { if (node == null) {
nodemap.put(key, nodeBean); nodemap.put(key, nodeBean);
} else if (nodeBean.joinClass == null && node.joinClass != null) { // 非joinNode 关联 joinNode } else if (nodeBean.joinClass == null && node.joinClass != null) { // 非joinNode 关联 joinNode
nodemap.put( String subKey = key.substring(key.lastIndexOf('.') + 1);
key, boolean or = orItems.contains(subKey) || subKey.contains("[OR]");
nodeBean.any( nodemap.put(key, nodeBean.any(node, or));
node,
key.substring(key.lastIndexOf('.') + 1)
.contains("[OR]")));
} else { } else {
node.any( String subKey = key.substring(key.lastIndexOf('.') + 1);
nodeBean, boolean or = orItems.contains(subKey) || subKey.contains("[OR]");
key.substring(key.lastIndexOf('.') + 1).contains("[OR]")); node.any(nodeBean, or);
} }
} }
} }
@@ -297,10 +295,11 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
nodemap.forEach((k, v) -> { nodemap.forEach((k, v) -> {
String[] keys = k.split("\\."); String[] keys = k.split("\\.");
LinkNode link = linkes.get(keys[0]); LinkNode link = linkes.get(keys[0]);
boolean or = orItems.contains(keys[0]) || keys[0].contains("[OR]");
if (link == null) { if (link == null) {
linkes.put(keys[0], new LinkNode(k, v)); linkes.put(keys[0], new LinkNode(keys, or, 0, v));
} else { } else {
link.put(keys, 0, v); link.put(keys, or, 0, v);
} }
}); });
FilterNodeBean rs = null; 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 final Map<String, LinkNode> nexts = new LinkedHashMap<>();
public LinkNode(String keyString, FilterNodeBean node) { public LinkNode(String[] keyStrings, boolean or, int pos, 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) {
this.key = keyStrings[pos]; this.key = keyStrings[pos];
this.or = this.key.contains("[OR]"); this.or = or;
put(keyStrings, pos, node); put(keyStrings, or, pos, node);
} }
public FilterNodeBean createFilterNodeBean() { public FilterNodeBean createFilterNodeBean() {
@@ -366,16 +358,16 @@ public final class FilterNodeBean<T extends FilterBean> implements Comparable<Fi
return node; 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])) { if (keys.length == pos + 1 && this.key.equals(keys[pos])) {
this.beans.add(node); this.beans.add(node);
return; return;
} }
LinkNode link = nexts.get(keys[pos + 1]); LinkNode link = nexts.get(keys[pos + 1]);
if (link == null) { 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 { } 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; package org.redkale.util;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import static org.redkale.asm.Opcodes.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.*; import java.util.function.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.redkale.asm.*; import org.redkale.asm.*;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import static org.redkale.asm.Opcodes.*;
import org.redkale.asm.Type; import org.redkale.asm.Type;
/** /**
@@ -26,13 +25,19 @@ import org.redkale.asm.Type;
*/ */
public interface Copier<S, D> extends BiFunction<S, D, D> { 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_NULL_VALUE = 1 << 1; // 2
/** 是否跳过值为空字符串的字段 */ /**
* 是否跳过值为空字符串的字段
*/
public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; // 4 public static final int OPTION_SKIP_EMPTY_STRING = 1 << 2; // 4
/** 同名字段类型强制转换 */ /**
* 同名字段类型强制转换
*/
public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; // 8 public static final int OPTION_ALLOW_TYPE_CAST = 1 << 3; // 8
/** /**

View File

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