24282 hai 1 ano
pai
achega
274a47427c
Modificáronse 26 ficheiros con 1160 adicións e 1 borrados
  1. 14 1
      my-test/pom.xml
  2. 23 0
      my-test/src/main/java/org/example/join/JoinConfig.java
  3. 35 0
      my-test/src/main/java/org/example/join/JoinMapper.java
  4. 80 0
      my-test/src/main/java/org/example/join/Test.java
  5. 9 0
      my-test/src/main/java/org/example/join/domain/IFormat.java
  6. 5 0
      my-test/src/main/java/org/example/join/domain/IQueryColumn.java
  7. 4 0
      my-test/src/main/java/org/example/join/domain/ITable.java
  8. 215 0
      my-test/src/main/java/org/example/join/domain/QueryColumn.java
  9. 26 0
      my-test/src/main/java/org/example/join/domain/QueryColumnAlias.java
  10. 22 0
      my-test/src/main/java/org/example/join/domain/QueryColumnCompute.java
  11. 130 0
      my-test/src/main/java/org/example/join/domain/QueryCondition.java
  12. 27 0
      my-test/src/main/java/org/example/join/domain/QueryConditionConnect.java
  13. 25 0
      my-test/src/main/java/org/example/join/domain/QueryConditionOrder.java
  14. 35 0
      my-test/src/main/java/org/example/join/domain/Table.java
  15. 25 0
      my-test/src/main/java/org/example/join/domain/TableJoin.java
  16. 42 0
      my-test/src/main/java/org/example/join/sql/From.java
  17. 49 0
      my-test/src/main/java/org/example/join/sql/Join.java
  18. 85 0
      my-test/src/main/java/org/example/join/sql/JoinSqlProvider.java
  19. 44 0
      my-test/src/main/java/org/example/join/sql/Select.java
  20. 50 0
      my-test/src/main/java/org/example/join/sql/Sql.java
  21. 41 0
      my-test/src/main/java/org/example/join/sql/SqlExecute.java
  22. 51 0
      my-test/src/main/java/org/example/join/sql/Where.java
  23. 42 0
      my-test/src/main/java/org/example/join/util/SqlConstant.java
  24. 23 0
      my-test/src/main/java/org/example/join/util/SqlUtil.java
  25. 7 0
      my-test/src/main/resources/mapper/base/JoinMapper.xml
  26. 51 0
      my-test/src/test/java/MySpringBootTest.java

+ 14 - 1
my-test/pom.xml

@@ -13,11 +13,24 @@
 
     <dependencies>
 
-    <dependency>
+        <dependency>
             <groupId>org.dromara</groupId>
             <artifactId>base-starter</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+
     </dependencies>
 
     <build>

+ 23 - 0
my-test/src/main/java/org/example/join/JoinConfig.java

@@ -0,0 +1,23 @@
+package org.example.join;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.mapper.MapperFactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class JoinConfig {
+
+    @Autowired
+    private SqlSessionFactory sqlSessionFactory;
+
+    @Bean
+    public JoinMapper testMapper() throws Exception {
+        MapperFactoryBean<JoinMapper> mapperFactoryBean = new MapperFactoryBean<>();
+        mapperFactoryBean.setSqlSessionFactory(sqlSessionFactory);
+        mapperFactoryBean.setMapperInterface(JoinMapper.class);
+        return mapperFactoryBean.getObject();
+    }
+
+}

+ 35 - 0
my-test/src/main/java/org/example/join/JoinMapper.java

@@ -0,0 +1,35 @@
+package org.example.join;
+
+import com.baomidou.mybatisplus.core.assist.ISqlRunner;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.example.join.sql.JoinSqlProvider;
+import org.example.join.sql.Sql;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface JoinMapper {
+
+    /**
+     * 列表
+     */
+    @SelectProvider(type = JoinSqlProvider.class, method = "getSql")
+    List<Map<String, Object>> list(@Param(ISqlRunner.SQL) Sql<?> sql);
+
+    /**
+     * 分页
+     */
+    @SelectProvider(type = JoinSqlProvider.class, method = "getSql")
+    Page<Map<String, Object>> page(@Param(ISqlRunner.SQL) Sql<?> sql, @Param(ISqlRunner.PAGE) Page<?> page);
+
+    /**
+     * 单条纪录
+     */
+    @SelectProvider(type = JoinSqlProvider.class, method = "getSql")
+    Map<String, Object> one(@Param(ISqlRunner.SQL) Sql<?> sql);
+
+}

+ 80 - 0
my-test/src/main/java/org/example/join/Test.java

@@ -0,0 +1,80 @@
+package org.example.join;
+
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.Table;
+
+public class Test extends Table {
+
+    public static final Test sys_dept = new Test();
+    public final QueryColumn dept_id = new QueryColumn(this, "dept_id");
+    public final QueryColumn tenant_id = new QueryColumn(this, "tenant_id");
+    public final QueryColumn parent_id = new QueryColumn(this, "parent_id");
+    public final QueryColumn ancestors = new QueryColumn(this, "ancestors");
+
+    public Test() {
+        super("sys_dept");
+    }
+
+
+    //public static void main(String[] args) {
+    //
+    //    Sql.create(SysUser.class)
+    //
+    //            .distinct()
+    //
+    //            .select(
+    //                    test_table.field_1,
+    //                    test_table.field_2.tableAs("tt2").add(test_table.field_3.tableAs("tt3")).add(2).as(SysUser::getEmail),
+    //                    test_table.field_3
+    //            )
+    //
+    //            .from(test_table)
+    //            .leftJoin(test_table.as("tt2")).on(test_table.field_4.eq(test_table.field_3), test_table.id.eq("sss"))
+    //            .leftJoin(test_table.as("tt3")).on(test_table.field_4)
+    //
+    //            .where(
+    //                    test_table.field_1.eq( test_table.field_1),
+    //                    test_table.field_1.eq("6777")
+    //            )
+    //            .list()
+    //
+    //
+    //    //.unionAll()
+    //    //
+    //    //
+    //    //.list()
+    //    //.page()
+    //    //.one()
+    //
+    //    ;
+    //
+    //    HashMap<String, String> map = new HashMap<>();
+    //    map.put("test_table", "t1");
+    //
+    //    QueryColumnAlias add3 = test_table.field_1
+    //            .add(test_table.field_2.subtract(test_table.field_3.divide(222).multiply(test_table.field_3)).add(1))
+    //            .add(test_table.field_3).as(SysUser::getEmail);
+    //    String sql = add3.getQueryColumn().toSql(map);
+    //
+    //    System.out.println(sql);
+    //
+    //    //System.out.println(
+    //    //
+    //    //        test_table.field_1.eq(111)
+    //    //                .and(test_table.field_2.eq(222).or(test_table.field_3.eq(333).and(test_table.field_4.eq(444))))
+    //    //
+    //    //
+    //    //                .toSql()
+    //    //);
+    //    //
+    //    //
+    //    //System.out.println(
+    //    //
+    //    //        test_table.field_1.eq(111)
+    //    //                .toSql()
+    //    //);
+    //
+    //
+    //}
+
+}

+ 9 - 0
my-test/src/main/java/org/example/join/domain/IFormat.java

@@ -0,0 +1,9 @@
+package org.example.join.domain;
+
+import java.util.Map;
+
+public interface IFormat {
+
+    String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap);
+
+}

+ 5 - 0
my-test/src/main/java/org/example/join/domain/IQueryColumn.java

@@ -0,0 +1,5 @@
+package org.example.join.domain;
+
+public interface IQueryColumn extends IFormat {
+
+}

+ 4 - 0
my-test/src/main/java/org/example/join/domain/ITable.java

@@ -0,0 +1,4 @@
+package org.example.join.domain;
+
+public interface ITable extends IFormat {
+}

+ 215 - 0
my-test/src/main/java/org/example/join/domain/QueryColumn.java

@@ -0,0 +1,215 @@
+package org.example.join.domain;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.apache.ibatis.reflection.property.PropertyNamer;
+import org.example.join.util.SqlConstant;
+import org.example.join.util.SqlUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+public class QueryColumn implements IFormat, IQueryColumn {
+
+    /**
+     * 表
+     */
+    private final Table table;
+
+    /**
+     * 字段名
+     */
+    private final String name;
+
+    /**
+     * 计算列表
+     */
+    private final List<QueryColumnCompute> queryColumnComputeList;
+
+    public QueryColumn(Table table, String name) {
+        this.table = table;
+        this.name = name;
+        this.queryColumnComputeList = new ArrayList<>();
+    }
+
+    protected QueryColumn(Table table, String name, List<QueryColumnCompute> queryColumnComputeList) {
+        this.table = table;
+        this.name = name;
+        this.queryColumnComputeList = queryColumnComputeList;
+    }
+
+    public <T> QueryColumnAlias as(SFunction<T, ?> function) {
+        LambdaMeta meta = LambdaUtils.extract(function);
+        String alias = StrUtil.toUnderlineCase(PropertyNamer.methodToProperty(meta.getImplMethodName()));
+        return new QueryColumnAlias(alias, this);
+    }
+
+    public QueryColumn tableAs(String tableAs) {
+        Table table = new Table(tableAs, this.table.getName());
+        return new QueryColumn(table, this.name, this.queryColumnComputeList);
+    }
+
+    // ===========================================
+    // 运算 加 减 乘 除 取余 + - * / %
+    // ===========================================
+
+    public QueryColumn add(QueryColumn queryColumn) {
+        return compute(SqlConstant.ADD, queryColumn);
+    }
+
+    public QueryColumn add(Number number) {
+        return compute(SqlConstant.ADD, number);
+    }
+
+    public QueryColumn subtract(QueryColumn queryColumn) {
+        return compute(SqlConstant.SUBTRACT, queryColumn);
+    }
+
+    public QueryColumn subtract(Number number) {
+        return compute(SqlConstant.SUBTRACT, number);
+    }
+
+    public QueryColumn multiply(QueryColumn queryColumn) {
+        return compute(SqlConstant.MULTIPLY, queryColumn);
+    }
+
+    public QueryColumn multiply(Number number) {
+        return compute(SqlConstant.MULTIPLY, number);
+    }
+
+    public QueryColumn divide(QueryColumn queryColumn) {
+        return compute(SqlConstant.DIVIDE, queryColumn);
+    }
+
+    public QueryColumn divide(Number number) {
+        return compute(SqlConstant.DIVIDE, number);
+    }
+
+    public QueryColumn remainder(QueryColumn queryColumn) {
+        return compute(SqlConstant.REMAINDER, queryColumn);
+    }
+
+    public QueryColumn remainder(Number number) {
+        return compute(SqlConstant.REMAINDER, number);
+    }
+
+    public QueryConditionOrder asc() {
+        return new QueryConditionOrder(this, SqlConstant.ASC);
+    }
+
+    public QueryConditionOrder desc() {
+        return new QueryConditionOrder(this, SqlConstant.DESC);
+    }
+
+    public QueryCondition eq(Object object) {
+        return new QueryCondition(this, SqlConstant.EQ, object);
+    }
+
+    public QueryCondition ne(Object object) {
+        return new QueryCondition(this, SqlConstant.NE, object);
+    }
+
+    public QueryCondition gt(Object object) {
+        return new QueryCondition(this, SqlConstant.GT, object);
+    }
+
+    public QueryCondition lt(Object object) {
+        return new QueryCondition(this, SqlConstant.LT, object);
+    }
+
+    public QueryCondition ge(Object object) {
+        return new QueryCondition(this, SqlConstant.GE, object);
+    }
+
+    public QueryCondition le(Object object) {
+        return new QueryCondition(this, SqlConstant.LE, object);
+    }
+
+    public QueryCondition between(Object object1, Object object2) {
+        if (ObjectUtil.isAllNotEmpty(object1, object2)) {
+            return new QueryCondition(this, SqlConstant.BETWEEN, new Object[]{object1, object2});
+        }
+        return new QueryCondition(this, SqlConstant.BETWEEN, null);
+    }
+
+    public QueryCondition notBetween(Object object1, Object object2) {
+        if (ObjectUtil.isAllNotEmpty(object1, object2)) {
+            return new QueryCondition(this, SqlConstant.NOT_BETWEEN, new Object[]{object1, object2});
+        }
+        return new QueryCondition(this, SqlConstant.NOT_BETWEEN, null);
+    }
+
+    public QueryCondition like(Object object) {
+        return new QueryCondition(this, SqlConstant.LIKE, object);
+    }
+
+    public QueryCondition notLike(Object object) {
+        return new QueryCondition(this, SqlConstant.NOT_LIKE, object);
+    }
+
+    public QueryCondition likeLeft(Object object) {
+        return new QueryCondition(this, SqlConstant.LIKE_LEFT, object);
+    }
+
+    public QueryCondition notLikeLeft(Object object) {
+        return new QueryCondition(this, SqlConstant.NOT_LIKE_LEFT, object);
+    }
+
+    public QueryCondition likeRight(Object object) {
+        return new QueryCondition(this, SqlConstant.LIKE_RIGHT, object);
+    }
+
+    public QueryCondition notLikeRight(Object object) {
+        return new QueryCondition(this, SqlConstant.NOT_LIKE_RIGHT, object);
+    }
+
+    public QueryCondition isNull() {
+        return new QueryCondition(this, SqlConstant.IS_NULL, null);
+    }
+
+    public QueryCondition isNotNull() {
+        return new QueryCondition(this, SqlConstant.IS_NOT_NULL, null);
+    }
+
+    private QueryColumn copy() {
+        return new QueryColumn(this.table, this.name, new ArrayList<>(this.queryColumnComputeList));
+    }
+
+    private QueryColumn compute(String symbol, QueryColumn queryColumn) {
+        QueryColumn newQueryColumn = copy();
+        newQueryColumn.queryColumnComputeList.add(new QueryColumnCompute(symbol, queryColumn));
+        return newQueryColumn;
+    }
+
+    private QueryColumn compute(String symbol, Number number) {
+        QueryColumn newQueryColumn = copy();
+        newQueryColumn.queryColumnComputeList.add(new QueryColumnCompute(symbol, number));
+        return newQueryColumn;
+    }
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        StringJoiner joiner;
+        if (ObjectUtil.isEmpty(queryColumnComputeList)) {
+            joiner = new StringJoiner(StringPool.EMPTY);
+        } else {
+            joiner = new StringJoiner(StringPool.EMPTY, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET);
+        }
+
+        String tableAlias = SqlUtil.getTableAlias(table, tableAliasMap);
+        String queryColumnArithmeticStr = queryColumnComputeList
+                .stream()
+                .map(item -> item.toSql(tableAliasMap, paramMap))
+                .collect(Collectors.joining());
+
+        return joiner.add(tableAlias + StringPool.DOT + name).add(queryColumnArithmeticStr).toString();
+    }
+
+}

+ 26 - 0
my-test/src/main/java/org/example/join/domain/QueryColumnAlias.java

@@ -0,0 +1,26 @@
+package org.example.join.domain;
+
+import lombok.AllArgsConstructor;
+import org.example.join.util.SqlConstant;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public class QueryColumnAlias implements IFormat, IQueryColumn {
+
+    /**
+     * 字段别名
+     */
+    private final String alias;
+
+    /**
+     * 查询列
+     */
+    private final QueryColumn queryColumn;
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        return queryColumn.toSql(tableAliasMap, paramMap) + SqlConstant.AS + alias;
+    }
+
+}

+ 22 - 0
my-test/src/main/java/org/example/join/domain/QueryColumnCompute.java

@@ -0,0 +1,22 @@
+package org.example.join.domain;
+
+import lombok.AllArgsConstructor;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public class QueryColumnCompute implements IFormat {
+
+    /**
+     * 计算类型( + - * / % )
+     */
+    private final String computeType;
+
+    private final Object value;
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        return computeType + (value instanceof IFormat ? ((IFormat) value).toSql(tableAliasMap, paramMap) : value.toString());
+    }
+
+}

+ 130 - 0
my-test/src/main/java/org/example/join/domain/QueryCondition.java

@@ -0,0 +1,130 @@
+package org.example.join.domain;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import org.example.join.util.SqlConstant;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+public class QueryCondition implements IFormat {
+
+    private final QueryColumn column;
+    private final String logic;
+    private final Object value;
+    private final List<QueryConditionConnect> queryConditionConnectList;
+
+    public QueryCondition(QueryColumn column, String logic, Object value) {
+        this.column = column;
+        this.logic = logic;
+        this.value = value;
+        this.queryConditionConnectList = new ArrayList<>();
+    }
+
+    public QueryCondition(QueryColumn column, String logic, Object value, List<QueryConditionConnect> queryConditionConnectList) {
+        this.column = column;
+        this.logic = logic;
+        this.value = value;
+        this.queryConditionConnectList = queryConditionConnectList;
+    }
+
+    private static void putParam(Map<String, Object> paramMap, StringJoiner joiner, Object value) {
+        String mapKey = SqlConstant.SQL_PARAM + (paramMap.size() + 1);
+        joiner.add(StringPool.HASH_LEFT_BRACE + mapKey + StringPool.RIGHT_BRACE);
+        paramMap.put(mapKey, value);
+    }
+
+    private static void putValue(Map<String, String> tableAliasMap, Map<String, Object> paramMap, StringJoiner joiner, Object value) {
+        if (value instanceof IQueryColumn) {
+            joiner.add(((IQueryColumn) value).toSql(tableAliasMap, paramMap));
+        } else {
+            putParam(paramMap, joiner, value);
+        }
+    }
+
+    public QueryCondition and(QueryCondition queryCondition) {
+        QueryCondition newQueryCondition = copy();
+        newQueryCondition.queryConditionConnectList.add(new QueryConditionConnect(SqlConstant.AND, queryCondition));
+        return newQueryCondition;
+    }
+
+    public QueryCondition or(QueryCondition queryCondition) {
+        QueryCondition newQueryCondition = copy();
+        newQueryCondition.queryConditionConnectList.add(new QueryConditionConnect(SqlConstant.OR, queryCondition));
+        return newQueryCondition;
+    }
+
+    public QueryCondition copy() {
+        return new QueryCondition(this.column, this.logic, this.value, new ArrayList<>(this.queryConditionConnectList));
+    }
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        StringJoiner joiner;
+        if (ObjectUtil.isEmpty(queryConditionConnectList)) {
+            joiner = new StringJoiner(StringPool.EMPTY);
+            if (ObjectUtil.isEmpty(value)) {
+                return StringPool.EMPTY;
+            }
+        } else {
+            joiner = new StringJoiner(StringPool.EMPTY, StringPool.LEFT_BRACKET, StringPool.RIGHT_BRACKET);
+            if (ObjectUtil.isEmpty(value)) {
+                queryConditionConnectList.forEach(item -> joiner.add(item.toSql(tableAliasMap, paramMap)));
+                String sql = joiner.toString();
+                if (sql.indexOf(SqlConstant.AND) == 0) {
+                    return sql.substring(SqlConstant.AND.length());
+                }
+                if (sql.indexOf(SqlConstant.OR) == 0) {
+                    return sql.substring(SqlConstant.OR.length());
+                }
+                return sql;
+            }
+        }
+
+        joiner.add(column.toSql(tableAliasMap, paramMap));
+
+        if (value instanceof IQueryColumn) {
+            joiner.add(((IQueryColumn) value).toSql(tableAliasMap, paramMap));
+        } else {
+            switch (logic) {
+                case SqlConstant.BETWEEN, SqlConstant.NOT_BETWEEN -> {
+                    joiner.add(logic);
+                    Object[] valueObj = (Object[]) value;
+                    putValue(tableAliasMap, paramMap, joiner, valueObj[0]);
+                    joiner.add(SqlConstant.AND);
+                    putValue(tableAliasMap, paramMap, joiner, valueObj[1]);
+                }
+                case SqlConstant.LIKE, SqlConstant.NOT_LIKE -> {
+                    joiner.add(logic);
+                    joiner.add("concat('%',");
+                    putValue(tableAliasMap, paramMap, joiner, value);
+                    joiner.add(",'%')");
+                }
+                case SqlConstant.LIKE_LEFT, SqlConstant.NOT_LIKE_LEFT -> {
+                    joiner.add(SqlConstant.LIKE);
+                    joiner.add("concat('%',");
+                    putValue(tableAliasMap, paramMap, joiner, value);
+                    joiner.add(")");
+                }
+                case SqlConstant.LIKE_RIGHT, SqlConstant.NOT_LIKE_RIGHT -> {
+                    joiner.add(SqlConstant.LIKE);
+                    joiner.add("concat(");
+                    putValue(tableAliasMap, paramMap, joiner, value);
+                    joiner.add(",'%')");
+                }
+                case SqlConstant.IS_NULL, SqlConstant.IS_NOT_NULL -> joiner.add(logic);
+
+                default -> {
+                    joiner.add(logic);
+                    putParam(paramMap, joiner, value);
+                }
+            }
+        }
+
+        queryConditionConnectList.forEach(item -> joiner.add(item.toSql(tableAliasMap, paramMap)));
+        return joiner.toString();
+    }
+
+}

+ 27 - 0
my-test/src/main/java/org/example/join/domain/QueryConditionConnect.java

@@ -0,0 +1,27 @@
+package org.example.join.domain;
+
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import lombok.AllArgsConstructor;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public class QueryConditionConnect implements IFormat {
+
+    /**
+     * 连接方式( and or )
+     */
+    private final String connectType;
+
+    private final QueryCondition queryCondition;
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        String sql = queryCondition.toSql(tableAliasMap, paramMap);
+        if (StringPool.EMPTY.equals(sql)) {
+            return StringPool.EMPTY;
+        }
+        return connectType + sql;
+    }
+
+}

+ 25 - 0
my-test/src/main/java/org/example/join/domain/QueryConditionOrder.java

@@ -0,0 +1,25 @@
+package org.example.join.domain;
+
+import lombok.AllArgsConstructor;
+
+import java.util.Map;
+
+@AllArgsConstructor
+public class QueryConditionOrder implements IFormat {
+
+    /**
+     * 查询列
+     */
+    private final QueryColumn queryColumn;
+
+    /**
+     * 排序方式 ( asc desc )
+     */
+    private final String orderType;
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        return queryColumn.toSql(tableAliasMap, paramMap) + orderType;
+    }
+
+}

+ 35 - 0
my-test/src/main/java/org/example/join/domain/Table.java

@@ -0,0 +1,35 @@
+package org.example.join.domain;
+
+import lombok.Getter;
+import org.example.join.util.SqlConstant;
+import org.example.join.util.SqlUtil;
+
+import java.util.Map;
+
+@Getter
+public class Table implements IFormat, ITable {
+
+    public final QueryColumn id = new QueryColumn(this, "id");
+    private final String alias;
+    private final String name;
+
+    public Table(String name) {
+        this.alias = null;
+        this.name = name;
+    }
+
+    protected Table(String alias, String name) {
+        this.alias = alias;
+        this.name = name;
+    }
+
+    public Table as(String alias) {
+        return new Table(alias, this.name);
+    }
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        return name + SqlConstant.AS + SqlUtil.getTableAlias(this, tableAliasMap);
+    }
+
+}

+ 25 - 0
my-test/src/main/java/org/example/join/domain/TableJoin.java

@@ -0,0 +1,25 @@
+package org.example.join.domain;
+
+import lombok.AllArgsConstructor;
+import org.example.join.util.SqlConstant;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@AllArgsConstructor
+public class TableJoin implements IFormat, ITable {
+
+    private final String joinType;
+    private final Table table;
+    private final List<QueryCondition> queryConditionList;
+
+    @Override
+    public String toSql(Map<String, String> tableAliasMap, Map<String, Object> paramMap) {
+        return joinType + table.toSql(tableAliasMap, paramMap) + SqlConstant.ON +
+                queryConditionList.stream()
+                        .map(item -> item.toSql(tableAliasMap, paramMap))
+                        .collect(Collectors.joining(SqlConstant.AND));
+    }
+
+}

+ 42 - 0
my-test/src/main/java/org/example/join/sql/From.java

@@ -0,0 +1,42 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.ObjectUtil;
+import org.example.join.domain.QueryCondition;
+import org.example.join.domain.Table;
+import org.example.join.util.SqlConstant;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+public class From<R> extends SqlExecute<R> {
+
+    private final Sql<R> sql;
+
+    protected From(Sql<R> sql) {
+        super(sql);
+        this.sql = sql;
+    }
+
+    public Join<R> innerJoin(Table table) {
+        sql.putTableAliasMap(table);
+        return new Join<>(sql, SqlConstant.INNER_JOIN, table);
+    }
+
+    public Join<R> leftJoin(Table table) {
+        sql.putTableAliasMap(table);
+        return new Join<>(sql, SqlConstant.LEFT_JOIN, table);
+    }
+
+    public Join<R> rightJoin(Table table) {
+        sql.putTableAliasMap(table);
+        return new Join<>(sql, SqlConstant.RIGHT_JOIN, table);
+    }
+
+    public Where<R> where(QueryCondition... queryCondition) {
+        if (ObjectUtil.isNotEmpty(queryCondition)) {
+            sql.queryConditionList.addAll(Arrays.stream(queryCondition).filter(Objects::nonNull).toList());
+        }
+        return new Where<>(sql);
+    }
+
+}

+ 49 - 0
my-test/src/main/java/org/example/join/sql/Join.java

@@ -0,0 +1,49 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.ObjectUtil;
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.QueryCondition;
+import org.example.join.domain.Table;
+import org.example.join.domain.TableJoin;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class Join<R> {
+
+    private final Sql<R> sql;
+    private final String join;
+    private final Table table;
+
+    protected Join(Sql<R> sql, String join, Table table) {
+        this.sql = sql;
+        this.join = join;
+        this.table = table;
+    }
+
+    /**
+     * 默认关联主表id
+     */
+    public From<R> on(QueryColumn queryColumn) {
+        QueryCondition queryCondition = table.id.eq(queryColumn);
+        return on(queryCondition);
+    }
+
+    public From<R> on(QueryCondition... queryConditions) {
+        if (ObjectUtil.isEmpty(queryConditions)) {
+            throw new IllegalArgumentException("on不能为空");
+        }
+
+        List<QueryCondition> queryConditionList = Arrays.stream(queryConditions).filter(Objects::nonNull).toList();
+
+        if (queryConditionList.isEmpty()) {
+            throw new IllegalArgumentException("on不能为空");
+        }
+
+        TableJoin tableJoin = new TableJoin(join, table, queryConditionList);
+        sql.queryTableList.add(tableJoin);
+        return new From<>(sql);
+    }
+
+}

+ 85 - 0
my-test/src/main/java/org/example/join/sql/JoinSqlProvider.java

@@ -0,0 +1,85 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.assist.ISqlRunner;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import org.example.join.domain.IFormat;
+import org.example.join.domain.IQueryColumn;
+import org.example.join.domain.ITable;
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.QueryCondition;
+import org.example.join.domain.QueryConditionOrder;
+import org.example.join.domain.Table;
+import org.example.join.domain.TableJoin;
+import org.example.join.util.SqlConstant;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class JoinSqlProvider {
+
+    public static String getSql(Map<String, Object> paramMap) {
+        Sql<?> sql = (Sql<?>) paramMap.get(ISqlRunner.SQL);
+        Map<String, String> tableAliasMap = sql.tableAliasMap;
+        List<IQueryColumn> queryFieldsList = sql.queryFieldsList;
+        List<ITable> queryTableList = sql.queryTableList;
+        List<QueryCondition> queryConditionList = sql.queryConditionList;
+        List<QueryColumn> groupByList = sql.groupByList;
+        List<QueryConditionOrder> orderByList = sql.orderByList;
+
+        StringBuilder sqlBuilder = new StringBuilder();
+        sqlBuilder
+                .append(SqlConstant.SELECT)
+                .append(listFormatSql(queryFieldsList, tableAliasMap, paramMap, StringPool.COMMA))
+                .append(SqlConstant.FROM)
+                .append(getQueryTablesSql(queryTableList, tableAliasMap, paramMap));
+
+        String where = listFormatSql(queryConditionList, tableAliasMap, paramMap, SqlConstant.AND);
+        if (StrUtil.isNotEmpty(where)) {
+            sqlBuilder.append(SqlConstant.WHERE).append(where);
+        }
+
+        String groupBy = listFormatSql(groupByList, tableAliasMap, paramMap, StringPool.COMMA);
+        if (StrUtil.isNotEmpty(groupBy)) {
+            sqlBuilder.append(SqlConstant.GROUP_BY).append(groupBy);
+        }
+
+        String orderBy = listFormatSql(orderByList, tableAliasMap, paramMap, StringPool.COMMA);
+        if (StrUtil.isNotEmpty(orderBy)) {
+            sqlBuilder.append(SqlConstant.ORDER_BY).append(orderBy);
+        }
+
+        return sqlBuilder.toString();
+    }
+
+    private static String getQueryTablesSql(List<ITable> queryTableList,
+                                            Map<String, String> tableAliasMap,
+                                            Map<String, Object> paramMap) {
+
+        String from = queryTableList.stream()
+                .filter(item -> item instanceof Table)
+                .map(item -> item.toSql(tableAliasMap, paramMap))
+                .collect(Collectors.joining(StringPool.COMMA));
+
+        String join = queryTableList.stream()
+                .filter(item -> item instanceof TableJoin)
+                .map(item -> item.toSql(tableAliasMap, paramMap))
+                .collect(Collectors.joining(StringPool.EMPTY));
+
+        return from + join;
+    }
+
+    private static String listFormatSql(List<? extends IFormat> list,
+                                        Map<String, String> tableAliasMap,
+                                        Map<String, Object> paramMap,
+                                        String joinStr) {
+
+        return list.stream()
+                .map(item -> item.toSql(tableAliasMap, paramMap))
+                .filter(item -> ObjectUtil.notEqual(item, StringPool.EMPTY))
+                .collect(Collectors.joining(joinStr));
+    }
+
+}

+ 44 - 0
my-test/src/main/java/org/example/join/sql/Select.java

@@ -0,0 +1,44 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.ObjectUtil;
+import org.example.join.domain.IQueryColumn;
+import org.example.join.domain.Table;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class Select<R> {
+
+    private final Sql<R> sql;
+
+    protected Select(Sql<R> sql) {
+        this.sql = sql;
+    }
+
+    public Select<R> distinct() {
+        sql.distinct = true;
+        return this;
+    }
+
+    public Select<R> select(IQueryColumn... columns) {
+
+        if (ObjectUtil.isEmpty(columns)) {
+            throw new IllegalArgumentException("select不能为空");
+        }
+
+        List<IQueryColumn> list = Arrays.stream(columns).filter(Objects::nonNull).toList();
+        if (list.isEmpty()) {
+            throw new IllegalArgumentException("select不能为空");
+        }
+
+        sql.queryFieldsList.addAll(list);
+        return this;
+    }
+
+    public From<R> from(Table... tables) {
+        sql.queryTableList.addAll(Arrays.stream(tables).peek(sql::putTableAliasMap).toList());
+        return new From<>(sql);
+    }
+
+}

+ 50 - 0
my-test/src/main/java/org/example/join/sql/Sql.java

@@ -0,0 +1,50 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.StrUtil;
+import org.example.join.domain.IQueryColumn;
+import org.example.join.domain.ITable;
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.QueryCondition;
+import org.example.join.domain.QueryConditionOrder;
+import org.example.join.domain.Table;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Sql<R> {
+
+    protected final Class<R> resultCls;
+    protected final Map<String, String> tableAliasMap = new HashMap<>();
+    protected final List<IQueryColumn> queryFieldsList = new ArrayList<>();
+    protected final List<ITable> queryTableList = new ArrayList<>();
+    protected final List<QueryCondition> queryConditionList = new ArrayList<>();
+    protected final List<QueryColumn> groupByList = new ArrayList<>();
+    protected final List<QueryConditionOrder> orderByList = new ArrayList<>();
+
+    protected Boolean distinct = false;
+
+    protected Sql(Class<R> resultCls) {
+        this.resultCls = resultCls;
+    }
+
+    public static <R> Select<R> create(Class<R> cls) {
+        return new Select<>(new Sql<>(cls));
+    }
+
+    protected void putTableAliasMap(Table table) {
+        String alias = table.getAlias();
+        String name = table.getName();
+        if (StrUtil.isNotBlank(alias)) {
+            return;
+        }
+
+        if (StrUtil.isNotBlank(tableAliasMap.get(name))) {
+            throw new IllegalArgumentException(name + " 表已存在,再次连表请取别名");
+        }
+
+        tableAliasMap.put(name, "t" + (tableAliasMap.size() + 1));
+    }
+
+}

+ 41 - 0
my-test/src/main/java/org/example/join/sql/SqlExecute.java

@@ -0,0 +1,41 @@
+package org.example.join.sql;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.AllArgsConstructor;
+import org.example.join.JoinMapper;
+
+import java.util.List;
+import java.util.Map;
+
+@AllArgsConstructor
+public class SqlExecute<R> {
+
+    protected static final JoinMapper mapper = SpringUtil.getBean(JoinMapper.class);
+
+    private final Sql<R> sql;
+
+    public List<R> list() {
+        List<Map<String, Object>> result = mapper.list(sql);
+        return BeanUtil.copyToList(result, sql.resultCls);
+    }
+
+    public Page<R> page(Page<?> page) {
+        Page<Map<String, Object>> result = mapper.page(sql, page);
+
+        Page<R> rPage = new Page<>();
+        rPage.setPages(result.getPages());
+        rPage.setCurrent(result.getCurrent());
+        rPage.setSize(result.getSize());
+        rPage.setTotal(result.getTotal());
+        rPage.setRecords(BeanUtil.copyToList(result.getRecords(), sql.resultCls));
+        return rPage;
+    }
+
+    public R one() {
+        Map<String, Object> result = mapper.one(sql);
+        return BeanUtil.toBean(result, sql.resultCls);
+    }
+
+}

+ 51 - 0
my-test/src/main/java/org/example/join/sql/Where.java

@@ -0,0 +1,51 @@
+package org.example.join.sql;
+
+import cn.hutool.core.util.ObjectUtil;
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.QueryConditionOrder;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+public class Where<R> extends SqlExecute<R> {
+
+    private final Sql<R> sql;
+
+    protected Where(Sql<R> sql) {
+        super(sql);
+        this.sql = sql;
+    }
+
+    public Where<R> groupBy(QueryColumn... queryColumns) {
+        if (ObjectUtil.isEmpty(queryColumns)) {
+            return this;
+        }
+        sql.groupByList.addAll(Arrays.stream(queryColumns).filter(Objects::nonNull).toList());
+        return this;
+    }
+
+    public Where<R> orderBy(QueryConditionOrder... queryConditionOrderBIES) {
+        if (ObjectUtil.isEmpty(queryConditionOrderBIES)) {
+            return this;
+        }
+        sql.orderByList.addAll(Arrays.stream(queryConditionOrderBIES).filter(Objects::nonNull).toList());
+        return this;
+    }
+
+    public Where<R> orderByAsc(QueryColumn... queryColumns) {
+        if (ObjectUtil.isEmpty(queryColumns)) {
+            return this;
+        }
+        sql.orderByList.addAll(Arrays.stream(queryColumns).filter(Objects::nonNull).map(QueryColumn::asc).toList());
+        return this;
+    }
+
+    public Where<R> orderByDesc(QueryColumn... queryColumns) {
+        if (ObjectUtil.isEmpty(queryColumns)) {
+            return this;
+        }
+        sql.orderByList.addAll(Arrays.stream(queryColumns).filter(Objects::nonNull).map(QueryColumn::desc).toList());
+        return this;
+    }
+
+}

+ 42 - 0
my-test/src/main/java/org/example/join/util/SqlConstant.java

@@ -0,0 +1,42 @@
+package org.example.join.util;
+
+public interface SqlConstant {
+
+    String SQL_PARAM = "sqlParam";
+    String SELECT = "select ";
+    String FROM = " from ";
+    String WHERE = " where ";
+    String INNER_JOIN = " inner join ";
+    String LEFT_JOIN = " left join ";
+    String RIGHT_JOIN = " right join ";
+    String GROUP_BY = " group by ";
+    String ORDER_BY = " order by ";
+    String AS = " as ";
+    String AND = " and ";
+    String OR = " or ";
+    String ON = " on ";
+    String ADD = " + ";
+    String SUBTRACT = " - ";
+    String MULTIPLY = " * ";
+    String DIVIDE = " / ";
+    String REMAINDER = " % ";
+    String ASC = " asc";
+    String DESC = " desc";
+    String EQ = " = ";
+    String NE = " <> ";
+    String GT = " > ";
+    String LT = " < ";
+    String GE = " >= ";
+    String LE = " <= ";
+    String BETWEEN = " between ";
+    String NOT_BETWEEN = " not between ";
+    String LIKE = " like ";
+    String NOT_LIKE = " not like ";
+    String LIKE_LEFT = " like left ";
+    String NOT_LIKE_LEFT = " not like left ";
+    String LIKE_RIGHT = " like right ";
+    String NOT_LIKE_RIGHT = " not like right ";
+    String IS_NULL = " is null";
+    String IS_NOT_NULL = " is not null";
+
+}

+ 23 - 0
my-test/src/main/java/org/example/join/util/SqlUtil.java

@@ -0,0 +1,23 @@
+package org.example.join.util;
+
+import cn.hutool.core.util.StrUtil;
+import org.example.join.domain.Table;
+
+import java.util.Map;
+
+public class SqlUtil {
+
+    public static String getTableAlias(Table table, Map<String, String> tableAliasMap) {
+        String tableAlias = table.getAlias();
+        String tableName = table.getName();
+
+        if (StrUtil.isBlank(tableAlias)) {
+            tableAlias = tableAliasMap.get(tableName);
+            if (StrUtil.isBlank(tableAlias)) {
+                throw new IllegalArgumentException("未知连表:" + tableName);
+            }
+        }
+        return tableAlias;
+    }
+
+}

+ 7 - 0
my-test/src/main/resources/mapper/base/JoinMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.example.entity.JoinMapper">
+
+</mapper>

+ 51 - 0
my-test/src/test/java/MySpringBootTest.java

@@ -0,0 +1,51 @@
+import org.dromara.system.domain.SysDept;
+import org.example.DromaraApplication;
+import org.example.join.domain.QueryColumn;
+import org.example.join.domain.Table;
+import org.example.join.sql.Sql;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = DromaraApplication.class)
+public class MySpringBootTest {
+
+    public static final Table sys_dept = new Table("sys_dept");
+    public static final Table sys_user = new Table("sys_user");
+    public final QueryColumn dept_id = new QueryColumn(sys_dept, "dept_id");
+    public final QueryColumn tenant_id = new QueryColumn(sys_dept, "tenant_id");
+    public final QueryColumn parent_id = new QueryColumn(sys_dept, "parent_id");
+    public final QueryColumn ancestors = new QueryColumn(sys_dept, "ancestors");
+    public final QueryColumn create_by = new QueryColumn(sys_dept, "create_by");
+    public final QueryColumn user_id = new QueryColumn(sys_user, "user_id");
+    public final QueryColumn user_name = new QueryColumn(sys_user, "user_name");
+    public final QueryColumn nick_name = new QueryColumn(sys_user, "nick_name");
+    public final QueryColumn sex = new QueryColumn(sys_user, "sex");
+
+    @Test
+    public void testCache() {
+
+        List<SysDept> list = Sql.create(SysDept.class).select(
+                        dept_id,
+                        tenant_id,
+                        dept_id.add(tenant_id.subtract(parent_id.divide(222)
+                                .multiply(parent_id).add(1)).add(parent_id)).as(SysDept::getEmail)
+                )
+                .from(sys_dept)
+                .leftJoin(sys_user).on(user_id.eq(dept_id), user_id.eq("8779"))
+                .leftJoin(sys_user.as("a")).on(user_id.eq(dept_id), user_id.eq("8779"))
+                .where(
+                        create_by.eq(user_id)
+                )
+                .list();
+
+        System.out.println();
+
+    }
+
+}