Commit c69fbe540ae7d68592abd7ad79215cc106007a70

Authored by YunaiV
1 parent a62399fb

✅ 增加 codegen 模块的单测覆盖率

Showing 22 changed files with 906 additions and 161 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java
@@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
4 import cn.hutool.core.util.ZipUtil; 4 import cn.hutool.core.util.ZipUtil;
5 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; 8 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
@@ -66,7 +67,7 @@ public class CodegenController { @@ -66,7 +67,7 @@ public class CodegenController {
66 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 67 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
67 public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) { 68 public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
68 List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId); 69 List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
69 - return success(CodegenConvert.INSTANCE.convertList05(list)); 70 + return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
70 } 71 }
71 72
72 @GetMapping("/table/page") 73 @GetMapping("/table/page")
@@ -74,7 +75,7 @@ public class CodegenController { @@ -74,7 +75,7 @@ public class CodegenController {
74 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 75 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
75 public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) { 76 public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
76 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO); 77 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
77 - return success(CodegenConvert.INSTANCE.convertPage(pageResult)); 78 + return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
78 } 79 }
79 80
80 @GetMapping("/detail") 81 @GetMapping("/detail")
@@ -82,7 +83,7 @@ public class CodegenController { @@ -82,7 +83,7 @@ public class CodegenController {
82 @Parameter(name = "tableId", description = "表编号", required = true, example = "1024") 83 @Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
83 @PreAuthorize("@ss.hasPermission('infra:codegen:query')") 84 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
84 public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) { 85 public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
85 - CodegenTableDO table = codegenService.getCodegenTablePage(tableId); 86 + CodegenTableDO table = codegenService.getCodegenTable(tableId);
86 List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId); 87 List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
87 // 拼装返回 88 // 拼装返回
88 return success(CodegenConvert.INSTANCE.convert(table, columns)); 89 return success(CodegenConvert.INSTANCE.convert(table, columns));
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java
1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo; 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
2 2
3 -import cn.hutool.core.util.ObjectUtil;  
4 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnBaseVO;  
5 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableBaseVO;  
6 -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;  
7 -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;  
8 -import com.fasterxml.jackson.annotation.JsonIgnore; 3 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
9 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
10 import lombok.Data; 6 import lombok.Data;
11 -import lombok.EqualsAndHashCode;  
12 -import lombok.ToString;  
13 7
14 import javax.validation.Valid; 8 import javax.validation.Valid;
15 -import javax.validation.constraints.AssertTrue;  
16 import javax.validation.constraints.NotNull; 9 import javax.validation.constraints.NotNull;
17 import java.util.List; 10 import java.util.List;
18 11
@@ -22,55 +15,10 @@ public class CodegenUpdateReqVO { @@ -22,55 +15,10 @@ public class CodegenUpdateReqVO {
22 15
23 @Valid // 校验内嵌的字段 16 @Valid // 校验内嵌的字段
24 @NotNull(message = "表定义不能为空") 17 @NotNull(message = "表定义不能为空")
25 - private Table table; 18 + private CodegenTableSaveReqVO table;
26 19
27 @Valid // 校验内嵌的字段 20 @Valid // 校验内嵌的字段
28 @NotNull(message = "字段定义不能为空") 21 @NotNull(message = "字段定义不能为空")
29 - private List<Column> columns;  
30 -  
31 - @Schema(description = "更新表定义")  
32 - @Data  
33 - @EqualsAndHashCode(callSuper = true)  
34 - @ToString(callSuper = true)  
35 - @Valid  
36 - public static class Table extends CodegenTableBaseVO {  
37 -  
38 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
39 - private Long id;  
40 -  
41 - @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")  
42 - @JsonIgnore  
43 - public boolean isParentMenuIdValid() {  
44 - // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的  
45 - return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())  
46 - || getParentMenuId() != null;  
47 - }  
48 -  
49 - @AssertTrue(message = "关联的父表信息不全")  
50 - @JsonIgnore  
51 - public boolean isSubValid() {  
52 - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)  
53 - || (ObjectUtil.isAllNotEmpty(getMasterTableId(), getSubJoinColumnId(), getSubJoinMany()));  
54 - }  
55 -  
56 - @AssertTrue(message = "关联的树表信息不全")  
57 - @JsonIgnore  
58 - public boolean isTreeValid() {  
59 - return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.TREE)  
60 - || (ObjectUtil.isAllNotEmpty(getTreeParentColumnId(), getTreeNameColumnId()));  
61 - }  
62 -  
63 - }  
64 -  
65 - @Schema(description = "更新表定义")  
66 - @Data  
67 - @EqualsAndHashCode(callSuper = true)  
68 - @ToString(callSuper = true)  
69 - public static class Column extends CodegenColumnBaseVO {  
70 -  
71 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
72 - private Long id;  
73 -  
74 - } 22 + private List<CodegenColumnSaveReqVO> columns;
75 23
76 } 24 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnRespVO.java
@@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column; @@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 -import lombok.ToString;  
7 5
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 7
10 @Schema(description = "管理后台 - 代码生成字段定义 Response VO") 8 @Schema(description = "管理后台 - 代码生成字段定义 Response VO")
11 @Data 9 @Data
12 -@EqualsAndHashCode(callSuper = true)  
13 -@ToString(callSuper = true)  
14 -public class CodegenColumnRespVO extends CodegenColumnBaseVO { 10 +public class CodegenColumnRespVO {
15 11
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Long id; 13 private Long id;
18 14
  15 + @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Long tableId;
  17 +
  18 + @Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
  19 + private String columnName;
  20 +
  21 + @Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
  22 + private String dataType;
  23 +
  24 + @Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
  25 + private String columnComment;
  26 +
  27 + @Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  28 + private Boolean nullable;
  29 +
  30 + @Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  31 + private Boolean primaryKey;
  32 +
  33 + @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + private Boolean autoIncrement;
  35 +
  36 + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  37 + private Integer ordinalPosition;
  38 +
  39 + @Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
  40 + private String javaType;
  41 +
  42 + @Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
  43 + private String javaField;
  44 +
  45 + @Schema(description = "字典类型", example = "sys_gender")
  46 + private String dictType;
  47 +
  48 + @Schema(description = "数据示例", example = "1024")
  49 + private String example;
  50 +
  51 + @Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  52 + private Boolean createOperation;
  53 +
  54 + @Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
  55 + private Boolean updateOperation;
  56 +
  57 + @Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  58 + private Boolean listOperation;
  59 +
  60 + @Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
  61 + private String listOperationCondition;
  62 +
  63 + @Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  64 + private Boolean listOperationResult;
  65 +
  66 + @Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
  67 + private String htmlType;
  68 +
19 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 69 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
20 private LocalDateTime createTime; 70 private LocalDateTime createTime;
21 71
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/column/CodegenColumnSaveReqVO.java
@@ -5,12 +5,12 @@ import lombok.Data; @@ -5,12 +5,12 @@ import lombok.Data;
5 5
6 import javax.validation.constraints.NotNull; 6 import javax.validation.constraints.NotNull;
7 7
8 -/**  
9 -* 代码生成字段定义 Base VO,提供给添加、修改、详细的子 VO 使用  
10 -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
11 -*/ 8 +@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
12 @Data 9 @Data
13 -public class CodegenColumnBaseVO { 10 +public class CodegenColumnSaveReqVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Long id;
14 14
15 @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 15 @Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 @NotNull(message = "表编号不能为空") 16 @NotNull(message = "表编号不能为空")
@@ -38,7 +38,7 @@ public class CodegenColumnBaseVO { @@ -38,7 +38,7 @@ public class CodegenColumnBaseVO {
38 38
39 @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") 39 @Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
40 @NotNull(message = "是否自增不能为空") 40 @NotNull(message = "是否自增不能为空")
41 - private String autoIncrement; 41 + private Boolean autoIncrement;
42 42
43 @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 43 @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
44 @NotNull(message = "排序不能为空") 44 @NotNull(message = "排序不能为空")
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableRespVO.java
@@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; @@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 -import lombok.EqualsAndHashCode;  
6 -import lombok.ToString;  
7 5
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 7
10 @Schema(description = "管理后台 - 代码生成表定义 Response VO") 8 @Schema(description = "管理后台 - 代码生成表定义 Response VO")
11 @Data 9 @Data
12 -@EqualsAndHashCode(callSuper = true)  
13 -@ToString(callSuper = true)  
14 -public class CodegenTableRespVO extends CodegenTableBaseVO { 10 +public class CodegenTableRespVO {
15 11
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
17 private Long id; 13 private Long id;
18 14
  15 + @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer scene;
  17 +
  18 + @Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
  19 + private String tableName;
  20 +
  21 + @Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
  22 + private String tableComment;
  23 +
  24 + @Schema(description = "备注", example = "我是备注")
  25 + private String remark;
  26 +
  27 + @Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
  28 + private String moduleName;
  29 +
  30 + @Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
  31 + private String businessName;
  32 +
  33 + @Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
  34 + private String className;
  35 +
  36 + @Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
  37 + private String classComment;
  38 +
  39 + @Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
  40 + private String author;
  41 +
  42 + @Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  43 + private Integer templateType;
  44 +
  45 + @Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  46 + private Integer frontType;
  47 +
  48 + @Schema(description = "父菜单编号", example = "1024")
  49 + private Long parentMenuId;
  50 +
  51 + @Schema(description = "主表的编号", example = "2048")
  52 + private Long masterTableId;
  53 + @Schema(description = "子表关联主表的字段编号", example = "4096")
  54 + private Long subJoinColumnId;
  55 + @Schema(description = "主表与子表是否一对多", example = "4096")
  56 + private Boolean subJoinMany;
  57 +
  58 + @Schema(description = "树表的父字段编号", example = "8192")
  59 + private Long treeParentColumnId;
  60 + @Schema(description = "树表的名字字段编号", example = "16384")
  61 + private Long treeNameColumnId;
  62 +
19 @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 63 @Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
20 private Integer dataSourceConfigId; 64 private Integer dataSourceConfigId;
21 65
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableSaveReqVO.java
1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table; 1 package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
2 2
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  5 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
3 import io.swagger.v3.oas.annotations.media.Schema; 7 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 8 import lombok.Data;
5 9
  10 +import javax.validation.constraints.AssertTrue;
6 import javax.validation.constraints.NotNull; 11 import javax.validation.constraints.NotNull;
7 12
8 -/**  
9 - * 代码生成 Base VO,提供给添加、修改、详细的子 VO 使用  
10 - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成  
11 - */ 13 +@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
12 @Data 14 @Data
13 -public class CodegenTableBaseVO { 15 +public class CodegenTableSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Long id;
14 19
15 @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 20 @Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
16 @NotNull(message = "导入类型不能为空") 21 @NotNull(message = "导入类型不能为空")
@@ -70,4 +75,26 @@ public class CodegenTableBaseVO { @@ -70,4 +75,26 @@ public class CodegenTableBaseVO {
70 @Schema(description = "树表的名字字段编号", example = "16384") 75 @Schema(description = "树表的名字字段编号", example = "16384")
71 private Long treeNameColumnId; 76 private Long treeNameColumnId;
72 77
  78 + @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
  79 + @JsonIgnore
  80 + public boolean isParentMenuIdValid() {
  81 + // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
  82 + return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
  83 + || getParentMenuId() != null;
  84 + }
  85 +
  86 + @AssertTrue(message = "关联的父表信息不全")
  87 + @JsonIgnore
  88 + public boolean isSubValid() {
  89 + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
  90 + || (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
  91 + }
  92 +
  93 + @AssertTrue(message = "关联的树表信息不全")
  94 + @JsonIgnore
  95 + public boolean isTreeValid() {
  96 + return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
  97 + || (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
  98 + }
  99 +
73 } 100 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
1 package cn.iocoder.yudao.module.infra.convert.codegen; 1 package cn.iocoder.yudao.module.infra.convert.codegen;
2 2
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO; 5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO; 6 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO;
6 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;  
7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO; 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
9 -import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;  
10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; 9 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; 10 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
12 import com.baomidou.mybatisplus.generator.config.po.TableField; 11 import com.baomidou.mybatisplus.generator.config.po.TableField;
@@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers; @@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers;
20 19
21 import java.util.List; 20 import java.util.List;
22 import java.util.Map; 21 import java.util.Map;
23 -import java.util.stream.Collectors;  
24 22
25 @Mapper 23 @Mapper
26 public interface CodegenConvert { 24 public interface CodegenConvert {
@@ -54,40 +52,18 @@ public interface CodegenConvert { @@ -54,40 +52,18 @@ public interface CodegenConvert {
54 return jdbcType.name(); 52 return jdbcType.name();
55 } 53 }
56 54
57 - // ========== CodegenTableDO 相关 ==========  
58 -  
59 - List<CodegenTableRespVO> convertList05(List<CodegenTableDO> list);  
60 -  
61 - CodegenTableRespVO convert(CodegenTableDO bean);  
62 -  
63 - PageResult<CodegenTableRespVO> convertPage(PageResult<CodegenTableDO> page);  
64 -  
65 - // ========== CodegenTableDO 相关 ==========  
66 -  
67 - List<CodegenColumnRespVO> convertList02(List<CodegenColumnDO> list);  
68 -  
69 - CodegenTableDO convert(CodegenUpdateReqVO.Table bean);  
70 -  
71 - List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);  
72 -  
73 - List<DatabaseTableRespVO> convertList04(List<TableInfo> list);  
74 -  
75 // ========== 其它 ========== 55 // ========== 其它 ==========
76 56
77 default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) { 57 default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
78 CodegenDetailRespVO respVO = new CodegenDetailRespVO(); 58 CodegenDetailRespVO respVO = new CodegenDetailRespVO();
79 - respVO.setTable(convert(table));  
80 - respVO.setColumns(convertList02(columns)); 59 + respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class));
  60 + respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class));
81 return respVO; 61 return respVO;
82 } 62 }
83 63
84 default List<CodegenPreviewRespVO> convert(Map<String, String> codes) { 64 default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
85 - return codes.entrySet().stream().map(entry -> {  
86 - CodegenPreviewRespVO respVO = new CodegenPreviewRespVO();  
87 - respVO.setFilePath(entry.getKey());  
88 - respVO.setCode(entry.getValue());  
89 - return respVO;  
90 - }).collect(Collectors.toList()); 65 + return CollectionUtils.convertList(codes.entrySet(),
  66 + entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue()));
91 } 67 }
92 68
93 } 69 }
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java
@@ -70,7 +70,7 @@ public interface CodegenService { @@ -70,7 +70,7 @@ public interface CodegenService {
70 * @param id 表编号 70 * @param id 表编号
71 * @return 表定义 71 * @return 表定义
72 */ 72 */
73 - CodegenTableDO getCodegenTablePage(Long id); 73 + CodegenTableDO getCodegenTable(Long id);
74 74
75 /** 75 /**
76 * 获得指定表的字段定义数组 76 * 获得指定表的字段定义数组
@@ -91,7 +91,6 @@ public interface CodegenService { @@ -91,7 +91,6 @@ public interface CodegenService {
91 /** 91 /**
92 * 获得数据库自带的表定义列表 92 * 获得数据库自带的表定义列表
93 * 93 *
94 - *  
95 * @param dataSourceConfigId 数据源的配置编号 94 * @param dataSourceConfigId 数据源的配置编号
96 * @param name 表名称 95 * @param name 表名称
97 * @param comment 表描述 96 * @param comment 表描述
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java
@@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen; @@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO; 7 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO; 8 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO; 9 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO; 10 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
11 -import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;  
12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; 11 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
13 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; 12 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
14 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper; 13 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
@@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService; @@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
22 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 21 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
23 import com.baomidou.mybatisplus.generator.config.po.TableField; 22 import com.baomidou.mybatisplus.generator.config.po.TableField;
24 import com.baomidou.mybatisplus.generator.config.po.TableInfo; 23 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  24 +import com.google.common.annotations.VisibleForTesting;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
26 import org.springframework.transaction.annotation.Transactional; 26 import org.springframework.transaction.annotation.Transactional;
27 27
@@ -31,6 +31,8 @@ import java.util.function.BiPredicate; @@ -31,6 +31,8 @@ import java.util.function.BiPredicate;
31 import java.util.stream.Collectors; 31 import java.util.stream.Collectors;
32 32
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
34 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*; 36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
35 37
36 /** 38 /**
@@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService { @@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService {
69 return ids; 71 return ids;
70 } 72 }
71 73
72 - public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) { 74 + private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
73 // 从数据库中,获得数据库表结构 75 // 从数据库中,获得数据库表结构
74 TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName); 76 TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
75 // 导入 77 // 导入
@@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService { @@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService {
103 return table.getId(); 105 return table.getId();
104 } 106 }
105 107
106 - private void validateTableInfo(TableInfo tableInfo) { 108 + @VisibleForTesting
  109 + void validateTableInfo(TableInfo tableInfo) {
107 if (tableInfo == null) { 110 if (tableInfo == null) {
108 throw exception(CODEGEN_IMPORT_TABLE_NULL); 111 throw exception(CODEGEN_IMPORT_TABLE_NULL);
109 } 112 }
@@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService {
139 } 142 }
140 143
141 // 更新 table 表定义 144 // 更新 table 表定义
142 - CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable()); 145 + CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class);
143 codegenTableMapper.updateById(updateTableObj); 146 codegenTableMapper.updateById(updateTableObj);
144 // 更新 column 字段定义 147 // 更新 column 字段定义
145 - List<CodegenColumnDO> updateColumnObjs = CodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns()); 148 + List<CodegenColumnDO> updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class);
146 updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj)); 149 updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
147 } 150 }
148 151
@@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService { @@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService {
161 } 164 }
162 165
163 private void syncCodegen0(Long tableId, TableInfo tableInfo) { 166 private void syncCodegen0(Long tableId, TableInfo tableInfo) {
164 - // 校验导入的表和字段非空 167 + // 1. 校验导入的表和字段非空
165 validateTableInfo(tableInfo); 168 validateTableInfo(tableInfo);
166 List<TableField> tableFields = tableInfo.getFields(); 169 List<TableField> tableFields = tableInfo.getFields();
167 170
168 - // 构建 CodegenColumnDO 数组,只同步新增的字段 171 + // 2. 构建 CodegenColumnDO 数组,只同步新增的字段
169 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId); 172 List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
170 - Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName); 173 + Set<String> codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName);
171 174
172 - //计算需要修改的字段,插入时重新插入,删除时将原来的删除  
173 - BiPredicate<TableField, CodegenColumnDO> pr = 175 + // 3.1 计算需要【修改】的字段,插入时重新插入,删除时将原来的删除
  176 + Map<String, CodegenColumnDO> codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName);
  177 + BiPredicate<TableField, CodegenColumnDO> primaryKeyPredicate =
174 (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType()) 178 (tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType())
175 && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable() 179 && tableField.getMetaInfo().isNullable() == codegenColumn.getNullable()
176 && tableField.isKeyFlag() == codegenColumn.getPrimaryKey() 180 && tableField.isKeyFlag() == codegenColumn.getPrimaryKey()
177 && tableField.getComment().equals(codegenColumn.getColumnComment()); 181 && tableField.getComment().equals(codegenColumn.getColumnComment());
178 - Map<String, CodegenColumnDO> codegenColumnDOMap = CollectionUtils.convertMap(codegenColumns, CodegenColumnDO::getColumnName);  
179 - //需要修改的字段  
180 Set<String> modifyFieldNames = tableFields.stream() 182 Set<String> modifyFieldNames = tableFields.stream()
181 .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null 183 .filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null
182 - && !pr.test(tableField, codegenColumnDOMap.get(tableField.getColumnName()))) 184 + && !primaryKeyPredicate.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
183 .map(TableField::getColumnName) 185 .map(TableField::getColumnName)
184 .collect(Collectors.toSet()); 186 .collect(Collectors.toSet());
185 - // 计算需要删除的字段  
186 - Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName); 187 + // 3.2 计算需要【删除】的字段
  188 + Set<String> tableFieldNames = convertSet(tableFields, TableField::getName);
187 Set<Long> deleteColumnIds = codegenColumns.stream() 189 Set<Long> deleteColumnIds = codegenColumns.stream()
188 .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName())) 190 .filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName()))
189 .map(CodegenColumnDO::getId).collect(Collectors.toSet()); 191 .map(CodegenColumnDO::getId).collect(Collectors.toSet());
@@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService {
193 throw exception(CODEGEN_SYNC_NONE_CHANGE); 195 throw exception(CODEGEN_SYNC_NONE_CHANGE);
194 } 196 }
195 197
196 - // 插入新增的字段 198 + // 4.1 插入新增的字段
197 List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields); 199 List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
198 codegenColumnMapper.insertBatch(columns); 200 codegenColumnMapper.insertBatch(columns);
199 - // 删除不存在的字段 201 + // 4.2 删除不存在的字段
200 if (CollUtil.isNotEmpty(deleteColumnIds)) { 202 if (CollUtil.isNotEmpty(deleteColumnIds)) {
201 codegenColumnMapper.deleteBatchIds(deleteColumnIds); 203 codegenColumnMapper.deleteBatchIds(deleteColumnIds);
202 } 204 }
@@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService { @@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService {
227 } 229 }
228 230
229 @Override 231 @Override
230 - public CodegenTableDO getCodegenTablePage(Long id) { 232 + public CodegenTableDO getCodegenTable(Long id) {
231 return codegenTableMapper.selectById(id); 233 return codegenTableMapper.selectById(id);
232 } 234 }
233 235
@@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService { @@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService {
277 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) { 279 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
278 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment); 280 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
279 // 移除在 Codegen 中,已经存在的 281 // 移除在 Codegen 中,已经存在的
280 - Set<String> existsTables = CollectionUtils.convertSet( 282 + Set<String> existsTables = convertSet(
281 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName); 283 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
282 tables.removeIf(table -> existsTables.contains(table.getName())); 284 tables.removeIf(table -> existsTables.contains(table.getName()));
283 - return CodegenConvert.INSTANCE.convertList04(tables); 285 + return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
284 } 286 }
285 287
286 } 288 }
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
@@ -269,7 +269,7 @@ const queryParams = reactive({ @@ -269,7 +269,7 @@ const queryParams = reactive({
269 #foreach ($column in $columns) 269 #foreach ($column in $columns)
270 #if ($column.listOperation) 270 #if ($column.listOperation)
271 #if ($column.listOperationCondition != 'BETWEEN') 271 #if ($column.listOperationCondition != 'BETWEEN')
272 - $column.javaField: null, 272 + $column.javaField: undefined,
273 #end 273 #end
274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") 274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
275 $column.javaField: [], 275 $column.javaField: [],
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen;
  2 +
  3 +import cn.hutool.core.collection.ListUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  13 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  14 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
  15 +import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
  16 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
  17 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  18 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  19 +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
  20 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
  21 +import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
  22 +import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
  23 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  24 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  25 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  26 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  27 +import org.junit.jupiter.api.Test;
  28 +import org.springframework.boot.test.mock.mockito.MockBean;
  29 +import org.springframework.context.annotation.Import;
  30 +
  31 +import javax.annotation.Resource;
  32 +import java.util.Arrays;
  33 +import java.util.Collections;
  34 +import java.util.List;
  35 +import java.util.Map;
  36 +
  37 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
  38 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
  39 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  40 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  41 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  42 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  43 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  44 +import static org.junit.jupiter.api.Assertions.*;
  45 +import static org.mockito.ArgumentMatchers.*;
  46 +import static org.mockito.Mockito.mock;
  47 +import static org.mockito.Mockito.when;
  48 +
  49 +/**
  50 + * {@link CodegenServiceImpl} 的单元测试类
  51 + *
  52 + * @author 芋道源码
  53 + */
  54 +@Import(CodegenServiceImpl.class)
  55 +public class CodegenServiceImplTest extends BaseDbUnitTest {
  56 +
  57 + @Resource
  58 + private CodegenServiceImpl codegenService;
  59 +
  60 + @Resource
  61 + private CodegenTableMapper codegenTableMapper;
  62 + @Resource
  63 + private CodegenColumnMapper codegenColumnMapper;
  64 +
  65 + @MockBean
  66 + private DatabaseTableService databaseTableService;
  67 +
  68 + @MockBean
  69 + private AdminUserApi userApi;
  70 +
  71 + @MockBean
  72 + private CodegenBuilder codegenBuilder;
  73 + @MockBean
  74 + private CodegenEngine codegenEngine;
  75 +
  76 + @MockBean
  77 + private CodegenProperties codegenProperties;
  78 +
  79 + @Test
  80 + public void testCreateCodegenList() {
  81 + // 准备参数
  82 + Long userId = randomLongId();
  83 + CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class,
  84 + o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai")));
  85 + // mock 方法(TableInfo)
  86 + TableInfo tableInfo = mock(TableInfo.class);
  87 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  88 + .thenReturn(tableInfo);
  89 + when(tableInfo.getComment()).thenReturn("芋艿");
  90 + // mock 方法(TableInfo fields)
  91 + TableField field01 = mock(TableField.class);
  92 + when(field01.getComment()).thenReturn("主键");
  93 + TableField field02 = mock(TableField.class);
  94 + when(field02.getComment()).thenReturn("名字");
  95 + List<TableField> fields = Arrays.asList(field01, field02);
  96 + when(tableInfo.getFields()).thenReturn(fields);
  97 + // mock 方法(CodegenTableDO)
  98 + CodegenTableDO table = randomPojo(CodegenTableDO.class);
  99 + when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table);
  100 + // mock 方法(AdminUserRespDTO)
  101 + AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头"));
  102 + when(userApi.getUser(eq(userId))).thenReturn(user);
  103 + // mock 方法(CodegenColumnDO)
  104 + List<CodegenColumnDO> columns = randomPojoList(CodegenColumnDO.class);
  105 + when(codegenBuilder.buildColumns(eq(table.getId()), same(fields)))
  106 + .thenReturn(columns);
  107 + // mock 方法(CodegenProperties)
  108 + when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType());
  109 +
  110 + // 调用
  111 + List<Long> result = codegenService.createCodegenList(userId, reqVO);
  112 + // 断言
  113 + assertEquals(1, result.size());
  114 + // 断言(CodegenTableDO)
  115 + CodegenTableDO dbTable = codegenTableMapper.selectList().get(0);
  116 + assertPojoEquals(table, dbTable);
  117 + assertEquals(1L, dbTable.getDataSourceConfigId());
  118 + assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene());
  119 + assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType());
  120 + assertEquals("芋头", dbTable.getAuthor());
  121 + // 断言(CodegenColumnDO)
  122 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  123 + assertEquals(columns.size(), dbColumns.size());
  124 + assertTrue(dbColumns.get(0).getPrimaryKey());
  125 + for (int i = 0; i < dbColumns.size(); i++) {
  126 + assertPojoEquals(columns.get(i), dbColumns.get(i));
  127 + }
  128 + }
  129 +
  130 + @Test
  131 + public void testValidateTableInfo() {
  132 + // 情况一
  133 + assertServiceException(() -> codegenService.validateTableInfo(null),
  134 + CODEGEN_IMPORT_TABLE_NULL);
  135 + // 情况二
  136 + TableInfo tableInfo = mock(TableInfo.class);
  137 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  138 + CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL);
  139 + // 情况三
  140 + when(tableInfo.getComment()).thenReturn("芋艿");
  141 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  142 + CODEGEN_IMPORT_COLUMNS_NULL);
  143 + // 情况四
  144 + TableField field = mock(TableField.class);
  145 + when(field.getName()).thenReturn("name");
  146 + when(tableInfo.getFields()).thenReturn(Collections.singletonList(field));
  147 + assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
  148 + CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName());
  149 + }
  150 +
  151 + @Test
  152 + public void testUpdateCodegen_notExists() {
  153 + // 准备参数
  154 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class);
  155 + // mock 方法
  156 +
  157 + // 调用,并断言
  158 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  159 + CODEGEN_TABLE_NOT_EXISTS);
  160 + }
  161 +
  162 + @Test
  163 + public void testUpdateCodegen_sub_masterNotExists() {
  164 + // mock 数据
  165 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  166 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  167 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  168 + codegenTableMapper.insert(table);
  169 + // 准备参数
  170 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  171 + o -> o.getTable().setId(table.getId())
  172 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()));
  173 +
  174 + // 调用,并断言
  175 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  176 + CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
  177 + }
  178 +
  179 + @Test
  180 + public void testUpdateCodegen_sub_columnNotExists() {
  181 + // mock 数据
  182 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  183 + o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  184 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  185 + codegenTableMapper.insert(subTable);
  186 + // mock 数据(master)
  187 + CodegenTableDO masterTable = randomPojo(CodegenTableDO.class,
  188 + o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType())
  189 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  190 + codegenTableMapper.insert(masterTable);
  191 + // 准备参数
  192 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  193 + o -> o.getTable().setId(subTable.getId())
  194 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  195 + .setMasterTableId(masterTable.getId()));
  196 +
  197 + // 调用,并断言
  198 + assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
  199 + CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
  200 + }
  201 +
  202 + @Test
  203 + public void testUpdateCodegen_success() {
  204 + // mock 数据
  205 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  206 + o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  207 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  208 + codegenTableMapper.insert(table);
  209 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  210 + codegenColumnMapper.insert(column01);
  211 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  212 + codegenColumnMapper.insert(column02);
  213 + // 准备参数
  214 + CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
  215 + o -> o.getTable().setId(table.getId())
  216 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
  217 + .setScene(CodegenSceneEnum.ADMIN.getScene()));
  218 + CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class,
  219 + o -> o.setId(column01.getId()).setTableId(table.getId()));
  220 + CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class,
  221 + o -> o.setId(column02.getId()).setTableId(table.getId()));
  222 + updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02));
  223 +
  224 + // 调用
  225 + codegenService.updateCodegen(updateReqVO);
  226 + // 断言
  227 + CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId());
  228 + assertPojoEquals(updateReqVO.getTable(), dbTable);
  229 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  230 + assertEquals(2, dbColumns.size());
  231 + assertPojoEquals(columnVO01, dbColumns.get(0));
  232 + assertPojoEquals(columnVO02, dbColumns.get(1));
  233 + }
  234 +
  235 + @Test
  236 + public void testSyncCodegenFromDB() {
  237 + // mock 数据(CodegenTableDO)
  238 + CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai")
  239 + .setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene()));
  240 + codegenTableMapper.insert(table);
  241 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  242 + .setColumnName("id"));
  243 + codegenColumnMapper.insert(column01);
  244 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
  245 + .setColumnName("name"));
  246 + codegenColumnMapper.insert(column02);
  247 + // 准备参数
  248 + Long tableId = table.getId();
  249 + // mock 方法(TableInfo)
  250 + TableInfo tableInfo = mock(TableInfo.class);
  251 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  252 + .thenReturn(tableInfo);
  253 + when(tableInfo.getComment()).thenReturn("芋艿");
  254 + // mock 方法(TableInfo fields)
  255 + TableField field01 = mock(TableField.class);
  256 + when(field01.getComment()).thenReturn("主键");
  257 + TableField field03 = mock(TableField.class);
  258 + when(field03.getComment()).thenReturn("分类");
  259 + List<TableField> fields = Arrays.asList(field01, field03);
  260 + when(tableInfo.getFields()).thenReturn(fields);
  261 + when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
  262 + .thenReturn(tableInfo);
  263 + // mock 方法(CodegenTableDO)
  264 + List<CodegenColumnDO> newColumns = randomPojoList(CodegenColumnDO.class);
  265 + when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> {
  266 + assertEquals(2, tableFields.size());
  267 + assertSame(tableInfo.getFields(), tableFields);
  268 + return true;
  269 + }))).thenReturn(newColumns);
  270 +
  271 + // 调用
  272 + codegenService.syncCodegenFromDB(tableId);
  273 + // 断言
  274 + List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
  275 + assertEquals(newColumns.size(), dbColumns.size());
  276 + assertPojoEquals(newColumns.get(0), dbColumns.get(0));
  277 + assertPojoEquals(newColumns.get(1), dbColumns.get(1));
  278 + }
  279 +
  280 + @Test
  281 + public void testDeleteCodegen_notExists() {
  282 + assertServiceException(() -> codegenService.deleteCodegen(randomLongId()),
  283 + CODEGEN_TABLE_NOT_EXISTS);
  284 + }
  285 +
  286 + @Test
  287 + public void testDeleteCodegen_success() {
  288 + // mock 数据
  289 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  290 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  291 + codegenTableMapper.insert(table);
  292 + CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  293 + codegenColumnMapper.insert(column);
  294 + // 准备参数
  295 + Long tableId = table.getId();
  296 +
  297 + // 调用
  298 + codegenService.deleteCodegen(tableId);
  299 + // 断言
  300 + assertNull(codegenTableMapper.selectById(tableId));
  301 + assertEquals(0, codegenColumnMapper.selectList().size());
  302 + }
  303 +
  304 + @Test
  305 + public void testGetCodegenTableList() {
  306 + // mock 数据
  307 + CodegenTableDO table01 = randomPojo(CodegenTableDO.class,
  308 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  309 + codegenTableMapper.insert(table01);
  310 + CodegenTableDO table02 = randomPojo(CodegenTableDO.class,
  311 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  312 + codegenTableMapper.insert(table02);
  313 + // 准备参数
  314 + Long dataSourceConfigId = table01.getDataSourceConfigId();
  315 +
  316 + // 调用
  317 + List<CodegenTableDO> result = codegenService.getCodegenTableList(dataSourceConfigId);
  318 + // 断言
  319 + assertEquals(1, result.size());
  320 + assertPojoEquals(table01, result.get(0));
  321 + }
  322 +
  323 + @Test
  324 + public void testGetCodegenTablePage() {
  325 + // mock 数据
  326 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> {
  327 + o.setTableName("t_yunai");
  328 + o.setTableComment("芋艿");
  329 + o.setClassName("SystemYunai");
  330 + o.setCreateTime(buildTime(2021, 3, 10));
  331 + }).setScene(CodegenSceneEnum.ADMIN.getScene());
  332 + codegenTableMapper.insert(tableDO);
  333 + // 测试 tableName 不匹配
  334 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString())));
  335 + // 测试 tableComment 不匹配
  336 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString())));
  337 + // 测试 className 不匹配
  338 + codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString())));
  339 + // 测试 createTime 不匹配
  340 + codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10))));
  341 + // 准备参数
  342 + CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO();
  343 + reqVO.setTableName("yunai");
  344 + reqVO.setTableComment("芋");
  345 + reqVO.setClassName("Yunai");
  346 + reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31));
  347 +
  348 + // 调用
  349 + PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(reqVO);
  350 + // 断言,只查到了一条符合条件的
  351 + assertEquals(1, pageResult.getTotal());
  352 + assertEquals(1, pageResult.getList().size());
  353 + assertPojoEquals(tableDO, pageResult.getList().get(0));
  354 + }
  355 +
  356 + @Test
  357 + public void testGetCodegenTable() {
  358 + // mock 数据
  359 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
  360 + codegenTableMapper.insert(tableDO);
  361 + // 准备参数
  362 + Long id = tableDO.getId();
  363 +
  364 + // 调用
  365 + CodegenTableDO result = codegenService.getCodegenTable(id);
  366 + // 断言
  367 + assertPojoEquals(tableDO, result);
  368 + }
  369 +
  370 + @Test
  371 + public void testGetCodegenColumnListByTableId() {
  372 + // mock 数据
  373 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class);
  374 + codegenColumnMapper.insert(column01);
  375 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class);
  376 + codegenColumnMapper.insert(column02);
  377 + // 准备参数
  378 + Long tableId = column01.getTableId();
  379 +
  380 + // 调用
  381 + List<CodegenColumnDO> result = codegenService.getCodegenColumnListByTableId(tableId);
  382 + // 断言
  383 + assertEquals(1, result.size());
  384 + assertPojoEquals(column01, result.get(0));
  385 + }
  386 +
  387 + @Test
  388 + public void testGenerationCodes_tableNotExists() {
  389 + assertServiceException(() -> codegenService.generationCodes(randomLongId()),
  390 + CODEGEN_TABLE_NOT_EXISTS);
  391 + }
  392 +
  393 + @Test
  394 + public void testGenerationCodes_columnNotExists() {
  395 + // mock 数据(CodegenTableDO)
  396 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  397 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  398 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  399 + codegenTableMapper.insert(table);
  400 + // 准备参数
  401 + Long tableId = table.getId();
  402 +
  403 + // 调用,并断言
  404 + assertServiceException(() -> codegenService.generationCodes(tableId),
  405 + CODEGEN_COLUMN_NOT_EXISTS);
  406 + }
  407 +
  408 + @Test
  409 + public void testGenerationCodes_sub_tableNotExists() {
  410 + // mock 数据(CodegenTableDO)
  411 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  412 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  413 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  414 + codegenTableMapper.insert(table);
  415 + // mock 数据(CodegenColumnDO)
  416 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  417 + codegenColumnMapper.insert(column01);
  418 + // 准备参数
  419 + Long tableId = table.getId();
  420 +
  421 + // 调用,并断言
  422 + assertServiceException(() -> codegenService.generationCodes(tableId),
  423 + CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
  424 + }
  425 +
  426 + @Test
  427 + public void testGenerationCodes_sub_columnNotExists() {
  428 + // mock 数据(CodegenTableDO)
  429 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  430 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  431 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  432 + codegenTableMapper.insert(table);
  433 + // mock 数据(CodegenColumnDO)
  434 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  435 + codegenColumnMapper.insert(column01);
  436 + // mock 数据(sub CodegenTableDO)
  437 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  438 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  439 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  440 + .setMasterTableId(table.getId()));
  441 + codegenTableMapper.insert(subTable);
  442 + // 准备参数
  443 + Long tableId = table.getId();
  444 +
  445 + // 调用,并断言
  446 + assertServiceException(() -> codegenService.generationCodes(tableId),
  447 + CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
  448 + }
  449 +
  450 + @Test
  451 + public void testGenerationCodes_one_success() {
  452 + // mock 数据(CodegenTableDO)
  453 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  454 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  455 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()));
  456 + codegenTableMapper.insert(table);
  457 + // mock 数据(CodegenColumnDO)
  458 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  459 + codegenColumnMapper.insert(column01);
  460 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  461 + codegenColumnMapper.insert(column02);
  462 + // mock 执行生成
  463 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  464 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  465 + assertEquals(2, columns.size());
  466 + assertEquals(column01, columns.get(0));
  467 + assertEquals(column02, columns.get(1));
  468 + return true;
  469 + }), isNull(), isNull())).thenReturn(codes);
  470 + // 准备参数
  471 + Long tableId = table.getId();
  472 +
  473 + // 调用
  474 + Map<String, String> result = codegenService.generationCodes(tableId);
  475 + // 断言
  476 + assertSame(codes, result);
  477 + }
  478 +
  479 + @Test
  480 + public void testGenerationCodes_master_success() {
  481 + // mock 数据(CodegenTableDO)
  482 + CodegenTableDO table = randomPojo(CodegenTableDO.class,
  483 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  484 + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
  485 + codegenTableMapper.insert(table);
  486 + // mock 数据(CodegenColumnDO)
  487 + CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  488 + codegenColumnMapper.insert(column01);
  489 + CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
  490 + codegenColumnMapper.insert(column02);
  491 + // mock 数据(sub CodegenTableDO)
  492 + CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
  493 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  494 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  495 + .setMasterTableId(table.getId())
  496 + .setSubJoinColumnId(1024L));
  497 + codegenTableMapper.insert(subTable);
  498 + // mock 数据(sub CodegenColumnDO)
  499 + CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId()));
  500 + codegenColumnMapper.insert(subColumn01);
  501 + // mock 执行生成
  502 + Map<String, String> codes = MapUtil.of(randomString(), randomString());
  503 + when(codegenEngine.execute(eq(table), argThat(columns -> {
  504 + assertEquals(2, columns.size());
  505 + assertEquals(column01, columns.get(0));
  506 + assertEquals(column02, columns.get(1));
  507 + return true;
  508 + }), argThat(tables -> {
  509 + assertEquals(1, tables.size());
  510 + assertPojoEquals(subTable, tables.get(0));
  511 + return true;
  512 + }), argThat(columns -> {
  513 + assertEquals(1, columns.size());
  514 + assertPojoEquals(subColumn01, columns.size());
  515 + return true;
  516 + }))).thenReturn(codes);
  517 + // 准备参数
  518 + Long tableId = table.getId();
  519 +
  520 + // 调用
  521 + Map<String, String> result = codegenService.generationCodes(tableId);
  522 + // 断言
  523 + assertSame(codes, result);
  524 + }
  525 +
  526 + @Test
  527 + public void testGetDatabaseTableList() {
  528 + // 准备参数
  529 + Long dataSourceConfigId = randomLongId();
  530 + String name = randomString();
  531 + String comment = randomString();
  532 + // mock 方法
  533 + TableInfo tableInfo01 = mock(TableInfo.class);
  534 + when(tableInfo01.getName()).thenReturn("t_yunai");
  535 + when(tableInfo01.getComment()).thenReturn("芋艿");
  536 + TableInfo tableInfo02 = mock(TableInfo.class);
  537 + when(tableInfo02.getName()).thenReturn("t_yunai_02");
  538 + when(tableInfo02.getComment()).thenReturn("芋艿_02");
  539 + when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment)))
  540 + .thenReturn(ListUtil.toList(tableInfo01, tableInfo02));
  541 + // mock 数据
  542 + CodegenTableDO tableDO = randomPojo(CodegenTableDO.class,
  543 + o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
  544 + .setTableName("t_yunai_02")
  545 + .setDataSourceConfigId(dataSourceConfigId));
  546 + codegenTableMapper.insert(tableDO);
  547 +
  548 + // 调用
  549 + List<DatabaseTableRespVO> result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment);
  550 + // 断言
  551 + assertEquals(1, result.size());
  552 + assertEquals("t_yunai", result.get(0).getName());
  553 + assertEquals("芋艿", result.get(0).getComment());
  554 + }
  555 +
  556 +}
0 \ No newline at end of file 557 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilderTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen.inner;
  2 +
  3 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  5 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  6 +import com.baomidou.mybatisplus.generator.config.po.TableField;
  7 +import com.baomidou.mybatisplus.generator.config.po.TableInfo;
  8 +import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
  9 +import org.apache.ibatis.type.JdbcType;
  10 +import org.junit.jupiter.api.Test;
  11 +import org.mockito.InjectMocks;
  12 +
  13 +import java.util.Collections;
  14 +import java.util.List;
  15 +
  16 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  17 +import static org.junit.jupiter.api.Assertions.*;
  18 +import static org.mockito.Mockito.mock;
  19 +import static org.mockito.Mockito.when;
  20 +
  21 +public class CodegenBuilderTest extends BaseMockitoUnitTest {
  22 +
  23 + @InjectMocks
  24 + private CodegenBuilder codegenBuilder;
  25 +
  26 + @Test
  27 + public void testBuildTable() {
  28 + // 准备参数
  29 + TableInfo tableInfo = mock(TableInfo.class);
  30 + // mock 方法
  31 + when(tableInfo.getName()).thenReturn("system_user");
  32 + when(tableInfo.getComment()).thenReturn("用户");
  33 +
  34 + // 调用
  35 + CodegenTableDO table = codegenBuilder.buildTable(tableInfo);
  36 + // 断言
  37 + assertEquals("system_user", table.getTableName());
  38 + assertEquals("用户", table.getTableComment());
  39 + assertEquals("system", table.getModuleName());
  40 + assertEquals("user", table.getBusinessName());
  41 + assertEquals("User", table.getClassName());
  42 + assertEquals("用户", table.getClassComment());
  43 + }
  44 +
  45 + @Test
  46 + public void testBuildColumns() {
  47 + // 准备参数
  48 + Long tableId = randomLongId();
  49 + TableField tableField = mock(TableField.class);
  50 + List<TableField> tableFields = Collections.singletonList(tableField);
  51 + // mock 方法
  52 + TableField.MetaInfo metaInfo = mock(TableField.MetaInfo.class);
  53 + when(tableField.getMetaInfo()).thenReturn(metaInfo);
  54 + when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT);
  55 + when(tableField.getComment()).thenReturn("编号");
  56 + when(tableField.isKeyFlag()).thenReturn(true);
  57 + when(tableField.isKeyIdentityFlag()).thenReturn(true);
  58 + IColumnType columnType = mock(IColumnType.class);
  59 + when(tableField.getColumnType()).thenReturn(columnType);
  60 + when(columnType.getType()).thenReturn("Long");
  61 + when(tableField.getName()).thenReturn("id2");
  62 + when(tableField.getPropertyName()).thenReturn("id");
  63 +
  64 + // 调用
  65 + List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
  66 + // 断言
  67 + assertEquals(1, columns.size());
  68 + CodegenColumnDO column = columns.get(0);
  69 + assertEquals(tableId, column.getTableId());
  70 + assertEquals("id2", column.getColumnName());
  71 + assertEquals("BIGINT", column.getDataType());
  72 + assertEquals("编号", column.getColumnComment());
  73 + assertFalse(column.getNullable());
  74 + assertTrue(column.getPrimaryKey());
  75 + assertTrue(column.getAutoIncrement());
  76 + assertEquals(1, column.getOrdinalPosition());
  77 + assertEquals("Long", column.getJavaType());
  78 + assertEquals("id", column.getJavaField());
  79 + assertNull(column.getDictType());
  80 + assertNotNull(column.getExample());
  81 + assertFalse(column.getCreateOperation());
  82 + assertTrue(column.getUpdateOperation());
  83 + assertFalse(column.getListOperation());
  84 + assertEquals("=", column.getListOperationCondition());
  85 + assertTrue(column.getListOperationResult());
  86 + assertEquals("input", column.getHtmlType());
  87 + }
  88 +
  89 +}
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/package-info.java deleted
1 -/**  
2 - * 占位,无其它作用  
3 - */  
4 -package cn.iocoder.yudao.module.infra.service.codegen;  
5 \ No newline at end of file 0 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImplTest.java
@@ -51,13 +51,13 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest { @@ -51,13 +51,13 @@ public class ApiErrorLogServiceImplTest extends BaseDbUnitTest {
51 // 测试 userId 不匹配 51 // 测试 userId 不匹配
52 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L))); 52 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserId(3344L)));
53 // 测试 userType 不匹配 53 // 测试 userType 不匹配
54 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setUserType(UserTypeEnum.MEMBER.getValue()))); 54 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setUserType(UserTypeEnum.MEMBER.getValue())));
55 // 测试 applicationName 不匹配 55 // 测试 applicationName 不匹配
56 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setApplicationName("test"))); 56 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setApplicationName("test")));
57 // 测试 requestUrl 不匹配 57 // 测试 requestUrl 不匹配
58 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setRequestUrl("bar"))); 58 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setRequestUrl("bar")));
59 // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00 59 // 测试 exceptionTime 不匹配:构造一个早期时间 2021-02-06 00:00:00
60 - apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setExceptionTime(buildTime(2021, 2, 6)))); 60 + apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, o -> o.setExceptionTime(buildTime(2021, 2, 6))));
61 // 测试 progressStatus 不匹配 61 // 测试 progressStatus 不匹配
62 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus()))); 62 apiErrorLogMapper.insert(cloneIgnoreId(apiErrorLogDO, logDO -> logDO.setProcessStatus(ApiErrorLogProcessStatusEnum.DONE.getStatus())));
63 // 准备参数 63 // 准备参数
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/index
@@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数 @@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数
197 const queryParams = reactive({ 197 const queryParams = reactive({
198 pageNo: 1, 198 pageNo: 1,
199 pageSize: 10, 199 pageSize: 10,
200 - name: null,  
201 - birthday: null, 200 + name: undefined,
  201 + birthday: undefined,
202 birthday: [], 202 birthday: [],
203 - sex: null,  
204 - enabled: null, 203 + sex: undefined,
  204 + enabled: undefined,
205 createTime: [] 205 createTime: []
206 }) 206 })
207 const queryFormRef = ref() // 搜索的表单 207 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/index
@@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数 @@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数
192 const queryParams = reactive({ 192 const queryParams = reactive({
193 pageNo: 1, 193 pageNo: 1,
194 pageSize: 10, 194 pageSize: 10,
195 - name: null,  
196 - birthday: null, 195 + name: undefined,
  196 + birthday: undefined,
197 birthday: [], 197 birthday: [],
198 - sex: null,  
199 - enabled: null, 198 + sex: undefined,
  199 + enabled: undefined,
200 createTime: [] 200 createTime: []
201 }) 201 })
202 const queryFormRef = ref() // 搜索的表单 202 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/index
@@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数 @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 const queryParams = reactive({ 177 const queryParams = reactive({
178 pageNo: 1, 178 pageNo: 1,
179 pageSize: 10, 179 pageSize: 10,
180 - name: null,  
181 - birthday: null, 180 + name: undefined,
  181 + birthday: undefined,
182 birthday: [], 182 birthday: [],
183 - sex: null,  
184 - enabled: null, 183 + sex: undefined,
  184 + enabled: undefined,
185 createTime: [] 185 createTime: []
186 }) 186 })
187 const queryFormRef = ref() // 搜索的表单 187 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/vue/index
@@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数 @@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
177 const queryParams = reactive({ 177 const queryParams = reactive({
178 pageNo: 1, 178 pageNo: 1,
179 pageSize: 10, 179 pageSize: 10,
180 - name: null,  
181 - birthday: null, 180 + name: undefined,
  181 + birthday: undefined,
182 birthday: [], 182 birthday: [],
183 - sex: null,  
184 - enabled: null, 183 + sex: undefined,
  184 + enabled: undefined,
185 createTime: [] 185 createTime: []
186 }) 186 })
187 const queryFormRef = ref() // 搜索的表单 187 const queryFormRef = ref() // 搜索的表单
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/vue/index
@@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化 @@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化
106 const loading = ref(true) // 列表的加载中 106 const loading = ref(true) // 列表的加载中
107 const list = ref([]) // 列表的数据 107 const list = ref([]) // 列表的数据
108 const queryParams = reactive({ 108 const queryParams = reactive({
109 - name: null 109 + name: undefined
110 }) 110 })
111 const queryFormRef = ref() // 搜索的表单 111 const queryFormRef = ref() // 搜索的表单
112 const exportLoading = ref(false) // 导出的加载中 112 const exportLoading = ref(false) // 导出的加载中
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/clean.sql
@@ -8,3 +8,5 @@ DELETE FROM &quot;infra_api_error_log&quot;; @@ -8,3 +8,5 @@ DELETE FROM &quot;infra_api_error_log&quot;;
8 DELETE FROM "infra_file_config"; 8 DELETE FROM "infra_file_config";
9 DELETE FROM "infra_test_demo"; 9 DELETE FROM "infra_test_demo";
10 DELETE FROM "infra_data_source_config"; 10 DELETE FROM "infra_data_source_config";
  11 +DELETE FROM "infra_codegen_table";
  12 +DELETE FROM "infra_codegen_column";
yudao-module-infra/yudao-module-infra-biz/src/test/resources/sql/create_tables.sql
@@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS &quot;infra_data_source_config&quot; ( @@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS &quot;infra_data_source_config&quot; (
170 "deleted" bit NOT NULL DEFAULT FALSE, 170 "deleted" bit NOT NULL DEFAULT FALSE,
171 PRIMARY KEY ("id") 171 PRIMARY KEY ("id")
172 ) COMMENT '数据源配置表'; 172 ) COMMENT '数据源配置表';
  173 +
  174 +CREATE TABLE IF NOT EXISTS "infra_codegen_table" (
  175 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  176 + "data_source_config_id" bigint not null,
  177 + "scene" tinyint not null DEFAULT 1,
  178 + "table_name" varchar(200) NOT NULL,
  179 + "table_comment" varchar(500) NOT NULL,
  180 + "remark" varchar(500) NOT NULL,
  181 + "module_name" varchar(30) NOT NULL,
  182 + "business_name" varchar(30) NOT NULL,
  183 + "class_name" varchar(100) NOT NULL,
  184 + "class_comment" varchar(50) NOT NULL,
  185 + "author" varchar(50) NOT NULL,
  186 + "template_type" tinyint not null DEFAULT 1,
  187 + "front_type" tinyint not null,
  188 + "parent_menu_id" bigint not null,
  189 + "master_table_id" bigint not null,
  190 + "sub_join_column_id" bigint not null,
  191 + "sub_join_many" bit not null,
  192 + "tree_parent_column_id" bigint not null,
  193 + "tree_name_column_id" bigint not null,
  194 + "creator" varchar(64) DEFAULT '',
  195 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  196 + "updater" varchar(64) DEFAULT '',
  197 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  198 + "deleted" bit NOT NULL DEFAULT FALSE,
  199 + PRIMARY KEY ("id")
  200 +) COMMENT '代码生成表定义表';
  201 +
  202 +CREATE TABLE IF NOT EXISTS "infra_codegen_column" (
  203 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  204 + "table_id" bigint not null,
  205 + "column_name" varchar(200) NOT NULL,
  206 + "data_type" varchar(100) NOT NULL,
  207 + "column_comment" varchar(500) NOT NULL,
  208 + "nullable" tinyint not null,
  209 + "primary_key" tinyint not null,
  210 + "auto_increment" varchar(5) not null,
  211 + "ordinal_position" int not null,
  212 + "java_type" varchar(32) NOT NULL,
  213 + "java_field" varchar(64) NOT NULL,
  214 + "dict_type" varchar(200) NOT NULL,
  215 + "example" varchar(64) NOT NULL,
  216 + "create_operation" bit not null,
  217 + "update_operation" bit not null,
  218 + "list_operation" bit not null,
  219 + "list_operation_condition" varchar(32) not null,
  220 + "list_operation_result" bit not null,
  221 + "html_type" varchar(32) NOT NULL,
  222 + "creator" varchar(64) DEFAULT '',
  223 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  224 + "updater" varchar(64) DEFAULT '',
  225 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  226 + "deleted" bit NOT NULL DEFAULT FALSE,
  227 + PRIMARY KEY ("id")
  228 +) COMMENT '代码生成表字段定义表';
173 \ No newline at end of file 229 \ No newline at end of file
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserSaveReqVO.java
@@ -14,8 +14,7 @@ import java.util.Set; @@ -14,8 +14,7 @@ import java.util.Set;
14 @Data 14 @Data
15 public class UserSaveReqVO { 15 public class UserSaveReqVO {
16 16
17 - @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
18 - @NotNull(message = "用户编号不能为空") 17 + @Schema(description = "用户编号", example = "1024")
19 private Long id; 18 private Long id;
20 19
21 @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao") 20 @Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")