فهرست منبع

优化"自动拼接'and'"以及"优化掉第一个'and'或'or'"以及 "多个拼接重复自动去重,只保留最后一个",

miemie 7 سال پیش
والد
کامیت
c2a1cebe40

+ 2 - 3
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/AbstractWrapper.java

@@ -39,11 +39,9 @@ import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiPredicate;
@@ -56,6 +54,7 @@ import com.baomidou.mybatisplus.core.conditions.interfaces.Nested;
 import com.baomidou.mybatisplus.core.enums.SqlKeyword;
 import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.ISqlSegmentList;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 
 
@@ -92,7 +91,7 @@ public abstract class AbstractWrapper<T, R, This extends AbstractWrapper<T, R, T
      * 数据库表映射实体类
      */
     protected T entity;
-    private List<ISqlSegment> expression = new ArrayList<>();
+    private ISqlSegmentList expression = new ISqlSegmentList();
     private boolean didOrderBy = false;
 
     @Override

+ 94 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/ISqlSegmentList.java

@@ -0,0 +1,94 @@
+package com.baomidou.mybatisplus.core.toolkit;
+
+import static com.baomidou.mybatisplus.core.enums.SqlKeyword.AND;
+import static com.baomidou.mybatisplus.core.enums.SqlKeyword.GROUP_BY;
+import static com.baomidou.mybatisplus.core.enums.SqlKeyword.NOT;
+import static com.baomidou.mybatisplus.core.enums.SqlKeyword.OR;
+import static com.baomidou.mybatisplus.core.enums.SqlKeyword.ORDER_BY;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
+
+import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
+
+/**
+ * @author miemie
+ * @since 2018-06-26
+ */
+public class ISqlSegmentList extends ArrayList<ISqlSegment> {
+
+    private static final long serialVersionUID = 8205969915086959490L;
+    //验证策略 只验证 group by
+    private final Predicate<ISqlSegment> predicateGroupBy = i -> i == GROUP_BY;
+    //验证策略 只验证 order by
+    private final Predicate<ISqlSegment> predicateOrderBy = i -> i == ORDER_BY;
+    //验证策略 只验证 and
+    private final Predicate<ISqlSegment> predicateNot = i -> i == NOT;
+    //验证策略 只验证 and
+    private final Predicate<ISqlSegment> predicateAnd = i -> i == AND;
+    //验证策略 只验证 or
+    private final Predicate<ISqlSegment> predicateOr = i -> i == OR;
+    //验证策略 全部验证 and 和 or
+    private final Predicate<ISqlSegment> predicateAll = i -> i == AND || i == OR;
+    //开启优化 and
+    private boolean automaticAnd = true;
+    //最后一个值
+    private ISqlSegment lastValue = null;
+
+    public ISqlSegmentList() {
+    }
+
+    public ISqlSegmentList(boolean automaticAnd) {
+        this.automaticAnd = automaticAnd;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends ISqlSegment> c) {
+        if (automaticAnd) {
+            ArrayList<? extends ISqlSegment> list = new ArrayList<>(c);
+            if (list.size() == 1) {//只有一个元素
+                /**
+                 * 只有 and() 以及 or() 以及 not() 会进入
+                 */
+                ISqlSegment sqlSegment = list.get(0);
+                if (!match(predicateNot, sqlSegment)) {//不是 not
+                    if (isEmpty()) { //sqlSegment是 and 或者 or 并且在第一位,不继续执行
+                        return false;
+                    }
+                    if (match(predicateAll, lastValue)) {//上次最后一个值是 and 或者 or
+                        if (match(predicateAnd, lastValue) && match(predicateAnd, sqlSegment)) {
+                            return false;
+                        } else if (match(predicateOr, sqlSegment) && match(predicateOr, lastValue)) {
+                            return false;
+                        } else {//和上次的不一样
+                            removeLast();
+                        }
+                    }
+                }
+            } else {//多个元素
+                if (!match(predicateAll, lastValue) && !isEmpty()) {
+                    add(AND);
+                }
+            }
+            //后置处理
+            this.flushLastValue(list);
+            return super.addAll(list);
+        } else {
+            return super.addAll(c);
+        }
+    }
+
+    private void flushLastValue(List<? extends ISqlSegment> list) {
+        lastValue = list.get(list.size() - 1);
+    }
+
+    private boolean match(Predicate<ISqlSegment> predicate, ISqlSegment value) {
+        return predicate.test(value);
+    }
+
+    private void removeLast() {//todo
+        remove(size() - 1);
+    }
+}

+ 32 - 2
mybatis-plus-core/src/test/java/com/baomidou/mybatisplus/core/test/WrapperTest.java

@@ -1,17 +1,23 @@
 package com.baomidou.mybatisplus.core.test;
 
+import org.junit.Test;
+
+import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 
-import org.junit.Test;
-
 public class WrapperTest {
 
     private void log(String message) {
         System.out.println(message);
     }
 
+    private void logSqlSegment(String explain, ISqlSegment sqlSegment) {
+        System.out.println(String.format(" ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓   ->(%s)<-   ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓", explain));
+        System.out.println(sqlSegment.getSqlSegment());
+    }
+
     @Test
     public void test() {
         Wrapper<User> wrapper = new QueryWrapper<User>().lambda().eq(User::getName, 123)
@@ -50,6 +56,30 @@ public class WrapperTest {
         log(ew.getSqlSegment());
     }
 
+    @Test
+    public void testQueryWrapper() {
+        logSqlSegment("去除第一个 and,以及自动拼接 and,以及手动拼接 and", new QueryWrapper<User>().and()
+            .ge("age", 3).and().ge("age", 3).ge("age", 3));
+
+        logSqlSegment("去除第一个 or,以及自动拼接 and,以及手动拼接 or", new QueryWrapper<User>().or()
+            .ge("age", 3).or().ge("age", 3).ge("age", 3));
+
+        logSqlSegment("多个 and 相连接,去除多余的 and", new QueryWrapper<User>()
+            .ge("age", 3).and().and().and().ge("age", 3).and().and().ge("age", 3));
+
+        logSqlSegment("多个 or 相连接,去除多余的 or", new QueryWrapper<User>()
+            .ge("age", 3).or().or().or().ge("age", 3).or().or().ge("age", 3));
+
+        logSqlSegment("多个 and或者 or 相连接,取最后一个", new QueryWrapper<User>()
+            .ge("age", 3).and().or().and().ge("age", 3).and().or().ge("age", 3));
+
+        logSqlSegment("嵌套测试,套内外自动拼接 and,去除套内第一个 and", new QueryWrapper<User>()
+            .eq("id", 11).and(i -> i.and().eq("id", 1)).eq("id", 1));
+
+        logSqlSegment("嵌套测试,套内外手动拼接 or,去除套内第一个 or", new QueryWrapper<User>()
+            .eq("id", 11).or(i -> i.or().eq("id", 1)).or().eq("id", 1));
+    }
+
 //    public void test() {
 //        String sql = new QueryWrapper()
 //            .where("b.age > 18", condition ->