FilterJoinType增加

This commit is contained in:
redkale
2023-12-02 11:12:02 +08:00
parent 31c6ffdd17
commit ed8719c27b
6 changed files with 96 additions and 38 deletions

View File

@@ -323,11 +323,14 @@ public final class EntityInfo<T> {
javax.persistence.Table t2 = type.getAnnotation(javax.persistence.Table.class); javax.persistence.Table t2 = type.getAnnotation(javax.persistence.Table.class);
final String tableName0 = t1 != null ? t1.name() : (t2 != null ? t2.name() : null); final String tableName0 = t1 != null ? t1.name() : (t2 != null ? t2.name() : null);
final String tableCcatalog0 = t1 != null ? t1.catalog() : (t2 != null ? t2.catalog() : null); final String tableCcatalog0 = t1 != null ? t1.catalog() : (t2 != null ? t2.catalog() : null);
String table0 = Utility.isEmpty(tableName0) ? type.getSimpleName().toLowerCase() : tableName0;
if (Utility.isNotEmpty(tableCcatalog0)) {
table0 = tableCcatalog0 + '.' + table0;
}
if (type.getAnnotation(org.redkale.persistence.VirtualEntity.class) != null if (type.getAnnotation(org.redkale.persistence.VirtualEntity.class) != null
|| type.getAnnotation(org.redkale.source.VirtualEntity.class) != null || type.getAnnotation(org.redkale.source.VirtualEntity.class) != null
|| (source == null || "memory".equalsIgnoreCase(source.getType()))) { || (source == null || "memory".equalsIgnoreCase(source.getType()))) {
this.table = null; this.table = source == null && type.getAnnotation(org.redkale.persistence.VirtualEntity.class) == null ? table0 : null;
this.tableOneArray = null; this.tableOneArray = null;
BiFunction<DataSource, EntityInfo, CompletableFuture<List>> loader = null; BiFunction<DataSource, EntityInfo, CompletableFuture<List>> loader = null;
try { try {
@@ -350,7 +353,7 @@ public final class EntityInfo<T> {
if (tableName0 != null && !tableName0.isEmpty() && tableName0.indexOf('.') >= 0) { if (tableName0 != null && !tableName0.isEmpty() && tableName0.indexOf('.') >= 0) {
throw new SourceException(type + " have illegal table.name on @Table"); throw new SourceException(type + " have illegal table.name on @Table");
} }
this.table = (tableCcatalog0 == null) ? type.getSimpleName().toLowerCase() : (tableCcatalog0.isEmpty()) ? (tableName0.isEmpty() ? type.getSimpleName().toLowerCase() : tableName0) : (tableCcatalog0 + '.' + (tableName0.isEmpty() ? type.getSimpleName().toLowerCase() : tableName0)); this.table = table0;
this.tableOneArray = new String[]{this.table}; this.tableOneArray = new String[]{this.table};
} }
DistributeTable dt = type.getAnnotation(DistributeTable.class); DistributeTable dt = type.getAnnotation(DistributeTable.class);

View File

@@ -45,6 +45,13 @@ public @interface FilterJoinColumn {
*/ */
String[] columns(); String[] columns();
/**
* join类别
*
* @return join类别
*/
FilterJoinType type() default FilterJoinType.INNER;
/** /**
* 备注描述 * 备注描述
* *

View File

@@ -22,6 +22,8 @@ import org.redkale.util.*;
*/ */
public class FilterJoinNode extends FilterNode { public class FilterJoinNode extends FilterNode {
private FilterJoinType joinType;
private Class joinClass; private Class joinClass;
private EntityInfo joinEntity; //在调用createSQLJoin和isCacheUseable时会注入 private EntityInfo joinEntity; //在调用createSQLJoin和isCacheUseable时会注入
@@ -31,7 +33,7 @@ public class FilterJoinNode extends FilterNode {
public FilterJoinNode() { public FilterJoinNode() {
} }
protected FilterJoinNode(Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { protected FilterJoinNode(FilterJoinType joinType, Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) {
Objects.requireNonNull(joinClass); Objects.requireNonNull(joinClass);
Objects.requireNonNull(joinColumns); Objects.requireNonNull(joinColumns);
if (express == null && value != null) { if (express == null && value != null) {
@@ -44,6 +46,7 @@ public class FilterJoinNode extends FilterNode {
} }
} }
this.joinClass = joinClass; this.joinClass = joinClass;
this.joinType = joinType;
this.joinColumns = joinColumns; this.joinColumns = joinColumns;
this.column = column; this.column = column;
this.express = express == null ? EQ : FilterNodes.oldExpress(express); this.express = express == null ? EQ : FilterNodes.oldExpress(express);
@@ -51,7 +54,7 @@ public class FilterJoinNode extends FilterNode {
} }
protected FilterJoinNode(FilterJoinNode node) { protected FilterJoinNode(FilterJoinNode node) {
this(node.joinClass, node.joinColumns, node.column, node.express, node.value); this(node.joinType, node.joinClass, node.joinColumns, node.column, node.express, node.value);
this.joinEntity = node.joinEntity; this.joinEntity = node.joinEntity;
this.or = node.or; this.or = node.or;
this.nodes = node.nodes; this.nodes = node.nodes;
@@ -120,11 +123,6 @@ public class FilterJoinNode extends FilterNode {
return this; return this;
} }
@Override
protected <T> CharSequence createSQLExpress(AbstractDataSqlSource source, final EntityInfo<T> info, final Map<Class, String> joinTabalis) {
return super.createSQLExpress(source, this.joinEntity == null ? info : this.joinEntity, joinTabalis);
}
@Override @Override
protected <T, E> Predicate<T> createPredicate(final EntityCache<T> cache) { protected <T, E> Predicate<T> createPredicate(final EntityCache<T> cache) {
if (column == null && this.nodes == null) { if (column == null && this.nodes == null) {
@@ -261,9 +259,14 @@ public class FilterJoinNode extends FilterNode {
return filter; return filter;
} }
@Override
protected <T> CharSequence createSQLExpress(AbstractDataSqlSource source, final EntityInfo<T> info, final Map<Class, String> joinTabalis) {
return super.createSQLExpress(source, this.joinEntity == null ? info : this.joinEntity, joinTabalis);
}
@Override @Override
protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final boolean update, final Map<Class, String> joinTabalis, final Set<String> haset, final EntityInfo<T> info) { protected <T> CharSequence createSQLJoin(final Function<Class, EntityInfo> func, final boolean update, final Map<Class, String> joinTabalis, final Set<String> haset, final EntityInfo<T> info) {
boolean morejoin = false; boolean moreJoin = false;
if (this.joinEntity == null) { if (this.joinEntity == null) {
if (this.joinClass != null) { if (this.joinClass != null) {
this.joinEntity = func.apply(this.joinClass); this.joinEntity = func.apply(this.joinClass);
@@ -275,7 +278,7 @@ public class FilterJoinNode extends FilterNode {
if (joinNode.joinClass != null) { if (joinNode.joinClass != null) {
joinNode.joinEntity = func.apply(joinNode.joinClass); joinNode.joinEntity = func.apply(joinNode.joinClass);
if (this.joinClass != null && this.joinClass != joinNode.joinClass) { if (this.joinClass != null && this.joinClass != joinNode.joinClass) {
morejoin = true; moreJoin = true;
} }
} }
} }
@@ -289,7 +292,7 @@ public class FilterJoinNode extends FilterNode {
sb.append(cs); sb.append(cs);
} }
} }
if (morejoin) { if (moreJoin) {
Set<Class> set = new HashSet<>(); Set<Class> set = new HashSet<>();
if (this.joinClass != null) { if (this.joinClass != null) {
set.add(this.joinClass); set.add(this.joinClass);
@@ -318,7 +321,7 @@ public class FilterJoinNode extends FilterNode {
String[] joinColumns = node.joinColumns; String[] joinColumns = node.joinColumns;
int pos = joinColumns[0].indexOf('='); int pos = joinColumns[0].indexOf('=');
if (update) { if (update) {
sb.append("[").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)).append(']'); sb.append('[').append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)).append(']');
sb.append('{').append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); sb.append('{').append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
for (int i = 1; i < joinColumns.length; i++) { for (int i = 1; i < joinColumns.length; i++) {
pos = joinColumns[i].indexOf('='); pos = joinColumns[i].indexOf('=');
@@ -326,7 +329,7 @@ public class FilterJoinNode extends FilterNode {
} }
sb.append('}'); sb.append('}');
} else { } else {
sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)) sb.append(" ").append(node.joinType).append(" JOIN ").append(node.joinEntity.getTables(node)[0]).append(" ").append(joinTabalis.get(node.joinClass))
.append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); .append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0]));
for (int i = 1; i < joinColumns.length; i++) { for (int i = 1; i < joinColumns.length; i++) {
pos = joinColumns[i].indexOf('='); pos = joinColumns[i].indexOf('=');
@@ -361,7 +364,20 @@ public class FilterJoinNode extends FilterNode {
@Override @Override
protected void putJoinTabalis(Map<Class, String> map) { protected void putJoinTabalis(Map<Class, String> map) {
if (this.joinClass != null && !map.containsKey(this.joinClass)) { if (this.joinClass != null && !map.containsKey(this.joinClass)) {
map.put(joinClass, "jt" + map.size()); //join_table_1 char[] chs = this.joinClass.getSimpleName().toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < chs.length; i++) {
char ch = chs[i];
if (i == 0 || Character.isUpperCase(ch)) {
sb.append(Character.toLowerCase(ch));
}
}
String alis = sb.toString();
if (map.values().contains(alis)) {
map.put(joinClass, "jt" + map.size()); //join_table_1
} else {
map.put(joinClass, alis);
}
} }
if (this.nodes == null) { if (this.nodes == null) {
return; return;
@@ -381,6 +397,10 @@ public class FilterJoinNode extends FilterNode {
return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); return toString(joinClass == null ? null : joinClass.getSimpleName()).toString();
} }
public FilterJoinType getJoinType() {
return joinType;
}
public Class getJoinClass() { public Class getJoinClass() {
return joinClass; return joinClass;
} }

View File

@@ -0,0 +1,17 @@
/*
*
*/
package org.redkale.source;
/**
* JOIN表的类别
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
public enum FilterJoinType {
INNER;
}

View File

@@ -517,7 +517,7 @@ public final class FilterNodes {
} }
public static FilterJoinNode joinInner(Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { public static FilterJoinNode joinInner(Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) {
return new FilterJoinNode(joinClass, joinColumns, column, express, value); return new FilterJoinNode(FilterJoinType.INNER, joinClass, joinColumns, column, express, value);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------

View File

@@ -27,6 +27,12 @@ public class FilterNodeTest {
private static EntityInfo<CarTestTable> carEntity; private static EntityInfo<CarTestTable> carEntity;
public static void main(String[] args) throws Throwable {
FilterNodeTest test = new FilterNodeTest();
test.init();
test.run();
}
@BeforeAll @BeforeAll
public static void init() throws Exception { public static void init() throws Exception {
final Properties props = new Properties(); final Properties props = new Properties();
@@ -34,7 +40,7 @@ public class FilterNodeTest {
func = (Class t) -> loadEntityInfo(t, false, props, null, fullloader); func = (Class t) -> loadEntityInfo(t, false, props, null, fullloader);
carEntity = loadEntityInfo(CarTestTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(CarTestTable.createList())); carEntity = loadEntityInfo(CarTestTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(CarTestTable.createList()));
final EntityInfo<UserTestTable> userEntity = loadEntityInfo(UserTestTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(UserTestTable.createList())); final EntityInfo<UserTestTable> userEntity = loadEntityInfo(UserTestTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(UserTestTable.createList()));
final EntityInfo<CarTypeTestTable> typeEntity = loadEntityInfo(CarTypeTestTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(CarTypeTestTable.createList())); final EntityInfo<CarTypeTable> typeEntity = loadEntityInfo(CarTypeTable.class, false, props, null, (s, t) -> CompletableFuture.completedFuture(CarTypeTable.createList()));
} }
private static <T> EntityInfo<T> loadEntityInfo(Class<T> clazz, final boolean cacheForbidden, final Properties conf, DataSource source, BiFunction<DataSource, EntityInfo, CompletableFuture<List>> fullloader) { private static <T> EntityInfo<T> loadEntityInfo(Class<T> clazz, final boolean cacheForbidden, final Properties conf, DataSource source, BiFunction<DataSource, EntityInfo, CompletableFuture<List>> fullloader) {
@@ -102,24 +108,29 @@ public class FilterNodeTest {
final CarTestBean bean = CarTestBean.create(); final CarTestBean bean = CarTestBean.create();
FilterNode joinNode1 = FilterNodes.joinInner(UserTestTable.class, new String[]{"userid", "username"}, "username", LIKE, bean.username) FilterNode joinNode1 = FilterNodes.joinInner(UserTestTable.class, new String[]{"userid", "username"}, "username", LIKE, bean.username)
.or(FilterNodes.joinInner(UserTestTable.class, new String[]{"userid", "username"}, "createtime", GT, bean.createtime)); .or(FilterNodes.joinInner(UserTestTable.class, new String[]{"userid", "username"}, "createtime", GT, bean.createtime));
FilterNode joinNode2 = FilterNodes.joinInner(CarTypeTestTable.class, "cartype", "typename", LIKE, bean.typename); FilterNode joinNode2 = FilterNodes.joinInner(CarTypeTable.class, "cartype", "typename", LIKE, bean.typename);
final FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNodes.gt("carid", bean.carid).and(joinNode1).or(joinNode2); final FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNodes.gt("carid", bean.carid).and(joinNode1).or(joinNode2);
final FilterNode beanNode = FilterNodeBean.createFilterNode(bean); final FilterNode beanNode = FilterNodeBean.createFilterNode(bean);
System.out.println("node.string = " + node); System.out.println("node.string = " + node);
System.out.println("bean.string = " + beanNode); System.out.println("bean.string = " + beanNode);
Assertions.assertEquals("(CarTypeTestTable.typename LIKE '%法拉利%' OR (UserTestTable.username LIKE '%用户1%' OR UserTestTable.createtime > 500))", node.toString()); Assertions.assertEquals("(CarTypeTable.typename LIKE '%法拉利%' OR (UserTestTable.username LIKE '%用户1%' OR UserTestTable.createtime > 500))", node.toString());
Assertions.assertEquals(node.toString(), beanNode.toString()); Assertions.assertEquals(node.toString(), beanNode.toString());
Map<Class, String> nodeJoinTabalis = getJoinTabalis(node); Map<Class, String> nodeJoinTabalis = getJoinTabalis(node);
Map<Class, String> beanJoinTabalis = getJoinTabalis(beanNode); Map<Class, String> beanJoinTabalis = getJoinTabalis(beanNode);
System.out.println("nodeJoinTabalis: " + nodeJoinTabalis);
System.out.println("beanJoinTabalis: " + beanJoinTabalis);
CharSequence nodeJoinsql = createSQLJoin(node, func, false, nodeJoinTabalis, new HashSet<>(), carEntity); CharSequence nodeJoinsql = createSQLJoin(node, func, false, nodeJoinTabalis, new HashSet<>(), carEntity);
CharSequence beanJoinsql = createSQLJoin(beanNode, func, false, beanJoinTabalis, new HashSet<>(), carEntity); CharSequence beanJoinsql = createSQLJoin(beanNode, func, false, beanJoinTabalis, new HashSet<>(), carEntity);
CharSequence nodeWhere = createSQLExpress(node, null, carEntity, nodeJoinTabalis); CharSequence nodeWhere = createSQLExpress(node, null, carEntity, nodeJoinTabalis);
CharSequence beanWhere = createSQLExpress(beanNode, null, carEntity, beanJoinTabalis); CharSequence beanWhere = createSQLExpress(beanNode, null, carEntity, beanJoinTabalis);
String expect = "SELECT a.* FROM cartesttable a INNER JOIN cartypetable ctt ON a.cartype = ctt.cartype INNER JOIN usertesttable utt ON a.userid = utt.userid AND a.username = utt.username WHERE (ctt.typename LIKE '%法拉利%' OR (utt.username LIKE '%用户1%' OR utt.createtime > 500))";
System.out.println("node.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) + " WHERE " + nodeWhere); System.out.println("node.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (nodeJoinsql == null ? "" : nodeJoinsql) + " WHERE " + nodeWhere);
System.out.println("bean.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (beanJoinsql == null ? "" : beanJoinsql) + " WHERE " + beanWhere); System.out.println("bean.sql = SELECT a.* FROM " + CarTestTable.class.getSimpleName().toLowerCase() + " a" + (beanJoinsql == null ? "" : beanJoinsql) + " WHERE " + beanWhere);
boolean r1 = isCacheUseable(node, func); boolean r1 = isCacheUseable(node, func);
Assertions.assertTrue(r1); Assertions.assertTrue(r1);
if (!r1) System.err.println("node.isCacheUseable 应该是true"); if (!r1) {
System.err.println("node.isCacheUseable 应该是true");
}
boolean r2 = isCacheUseable(beanNode, func); boolean r2 = isCacheUseable(beanNode, func);
Assertions.assertTrue(r2); Assertions.assertTrue(r2);
@@ -148,7 +159,7 @@ public class FilterNodeTest {
@FilterGroup("[OR]") @FilterGroup("[OR]")
@FilterColumn(express = LIKE) @FilterColumn(express = LIKE)
@FilterJoinColumn(table = CarTypeTestTable.class, columns = {"cartype"}) @FilterJoinColumn(table = CarTypeTable.class, columns = {"cartype"})
public String typename; public String typename;
@Override @Override
@@ -270,21 +281,21 @@ public class FilterNodeTest {
@AutoLoad @AutoLoad
@Cacheable @Cacheable
public static class CarTypeTestTable { public static class CarTypeTable {
public static List<CarTypeTestTable> createList() { public static List<CarTypeTable> createList() {
List<CarTypeTestTable> list = new ArrayList<>(); List<CarTypeTable> list = new ArrayList<>();
list.add(new CarTypeTestTable(101, "奥迪A1")); list.add(new CarTypeTable(101, "奥迪A1"));
list.add(new CarTypeTestTable(102, "奥迪A2")); list.add(new CarTypeTable(102, "奥迪A2"));
list.add(new CarTypeTestTable(103, "奥迪A3")); list.add(new CarTypeTable(103, "奥迪A3"));
list.add(new CarTypeTestTable(104, "奥迪A4")); list.add(new CarTypeTable(104, "奥迪A4"));
list.add(new CarTypeTestTable(105, "奥迪A5")); list.add(new CarTypeTable(105, "奥迪A5"));
list.add(new CarTypeTestTable(201, "奔驰S1")); list.add(new CarTypeTable(201, "奔驰S1"));
list.add(new CarTypeTestTable(202, "奔驰S2")); list.add(new CarTypeTable(202, "奔驰S2"));
list.add(new CarTypeTestTable(203, "奔驰S3")); list.add(new CarTypeTable(203, "奔驰S3"));
list.add(new CarTypeTestTable(204, "奔驰S4")); list.add(new CarTypeTable(204, "奔驰S4"));
list.add(new CarTypeTestTable(205, "奔驰S5")); list.add(new CarTypeTable(205, "奔驰S5"));
list.add(new CarTypeTestTable(301, "法拉利")); list.add(new CarTypeTable(301, "法拉利"));
return list; return list;
} }
@@ -293,11 +304,11 @@ public class FilterNodeTest {
private String typename; private String typename;
public CarTypeTestTable() { public CarTypeTable() {
} }
public CarTypeTestTable(int cartype, String typename) { public CarTypeTable(int cartype, String typename) {
this.cartype = cartype; this.cartype = cartype;
this.typename = typename; this.typename = typename;
} }