增加 codegen 模块的单测覆盖率

This commit is contained in:
YunaiV 2023-12-05 20:00:20 +08:00
parent e4c62c34b3
commit 6210bde1de
27 changed files with 1273 additions and 195 deletions

View File

@ -73,6 +73,23 @@ public class CollectionUtils {
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
}
public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
Function<T, ? extends Stream<? extends U>> func) {
if (CollUtil.isEmpty(from)) {
return new ArrayList<>();
}
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
}
public static <T, U, R> List<R> convertListByFlatMap(Collection<T> from,
Function<? super T, ? extends U> mapper,
Function<U, ? extends Stream<? extends R>> func) {
if (CollUtil.isEmpty(from)) {
return new ArrayList<>();
}
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
}
public static <K, V> List<V> mergeValuesFromMap(Map<K, List<V>> map) {
return map.values()
.stream()
@ -101,6 +118,23 @@ public class CollectionUtils {
return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
}
public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
Function<T, ? extends Stream<? extends U>> func) {
if (CollUtil.isEmpty(from)) {
return new HashSet<>();
}
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
}
public static <T, U, R> Set<R> convertSetByFlatMap(Collection<T> from,
Function<? super T, ? extends U> mapper,
Function<U, ? extends Stream<? extends R>> func) {
if (CollUtil.isEmpty(from)) {
return new HashSet<>();
}
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
}
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
if (CollUtil.isEmpty(from)) {
return new HashMap<>();
@ -272,38 +306,4 @@ public class CollectionUtils {
return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
}
public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
Function<T, ? extends Stream<? extends U>> func) {
if (CollUtil.isEmpty(from)) {
return new ArrayList<>();
}
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
}
public static <T, U, R> List<R> convertListByFlatMap(Collection<T> from,
Function<? super T, ? extends U> mapper,
Function<U, ? extends Stream<? extends R>> func) {
if (CollUtil.isEmpty(from)) {
return new ArrayList<>();
}
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
}
public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
Function<T, ? extends Stream<? extends U>> func) {
if (CollUtil.isEmpty(from)) {
return new HashSet<>();
}
return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
}
public static <T, U, R> Set<R> convertSetByFlatMap(Collection<T> from,
Function<? super T, ? extends U> mapper,
Function<U, ? extends Stream<? extends R>> func) {
if (CollUtil.isEmpty(from)) {
return new HashSet<>();
}
return from.stream().map(mapper).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
}
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.common.util.spring;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
@ -25,7 +25,7 @@ import java.util.Map;
public class SpringExpressionUtils {
/**
* spel表达式解析器
* Spring EL 表达式解析器
*/
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
/**
@ -43,7 +43,7 @@ public class SpringExpressionUtils {
* @param expressionString EL 表达式数组
* @return 执行界面
*/
public static Object parseExpression(ProceedingJoinPoint joinPoint, String expressionString) {
public static Object parseExpression(JoinPoint joinPoint, String expressionString) {
Map<String, Object> result = parseExpressions(joinPoint, Collections.singletonList(expressionString));
return result.get(expressionString);
}
@ -55,7 +55,7 @@ public class SpringExpressionUtils {
* @param expressionStrings EL 表达式数组
* @return 结果key 为表达式value 为对应值
*/
public static Map<String, Object> parseExpressions(ProceedingJoinPoint joinPoint, List<String> expressionStrings) {
public static Map<String, Object> parseExpressions(JoinPoint joinPoint, List<String> expressionStrings) {
// 如果为空则不进行解析
if (CollUtil.isEmpty(expressionStrings)) {
return MapUtil.newHashMap();

View File

@ -4,6 +4,7 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
@ -66,7 +67,7 @@ public class CodegenController {
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
return success(CodegenConvert.INSTANCE.convertList05(list));
return success(BeanUtils.toBean(list, CodegenTableRespVO.class));
}
@GetMapping("/table/page")
@ -74,7 +75,7 @@ public class CodegenController {
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
return success(CodegenConvert.INSTANCE.convertPage(pageResult));
return success(BeanUtils.toBean(pageResult, CodegenTableRespVO.class));
}
@GetMapping("/detail")
@ -82,7 +83,7 @@ public class CodegenController {
@Parameter(name = "tableId", description = "表编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('infra:codegen:query')")
public CommonResult<CodegenDetailRespVO> getCodegenDetail(@RequestParam("tableId") Long tableId) {
CodegenTableDO table = codegenService.getCodegenTablePage(tableId);
CodegenTableDO table = codegenService.getCodegenTable(tableId);
List<CodegenColumnDO> columns = codegenService.getCodegenColumnListByTableId(tableId);
// 拼装返回
return success(CodegenConvert.INSTANCE.convert(table, columns));

View File

@ -1,18 +1,11 @@
package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnBaseVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableBaseVO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableSaveReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import java.util.List;
@ -22,55 +15,10 @@ public class CodegenUpdateReqVO {
@Valid // 校验内嵌的字段
@NotNull(message = "表定义不能为空")
private Table table;
private CodegenTableSaveReqVO table;
@Valid // 校验内嵌的字段
@NotNull(message = "字段定义不能为空")
private List<Column> columns;
@Schema(description = "更新表定义")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Valid
public static class Table extends CodegenTableBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
@JsonIgnore
public boolean isParentMenuIdValid() {
// 生成场景为管理后台时必须设置上级菜单不然生成的菜单 SQL 是无父级菜单的
return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
|| getParentMenuId() != null;
}
@AssertTrue(message = "关联的父表信息不全")
@JsonIgnore
public boolean isSubValid() {
return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
|| (ObjectUtil.isAllNotEmpty(getMasterTableId(), getSubJoinColumnId(), getSubJoinMany()));
}
@AssertTrue(message = "关联的树表信息不全")
@JsonIgnore
public boolean isTreeValid() {
return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.TREE)
|| (ObjectUtil.isAllNotEmpty(getTreeParentColumnId(), getTreeNameColumnId()));
}
}
@Schema(description = "更新表定义")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public static class Column extends CodegenColumnBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
}
private List<CodegenColumnSaveReqVO> columns;
}

View File

@ -2,20 +2,70 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成字段定义 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CodegenColumnRespVO extends CodegenColumnBaseVO {
public class CodegenColumnRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long tableId;
@Schema(description = "字段名", requiredMode = Schema.RequiredMode.REQUIRED, example = "user_age")
private String columnName;
@Schema(description = "字段类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "int(11)")
private String dataType;
@Schema(description = "字段描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "年龄")
private String columnComment;
@Schema(description = "是否允许为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean nullable;
@Schema(description = "是否主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean primaryKey;
@Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean autoIncrement;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Integer ordinalPosition;
@Schema(description = "Java 属性类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "userAge")
private String javaType;
@Schema(description = "Java 属性名", requiredMode = Schema.RequiredMode.REQUIRED, example = "Integer")
private String javaField;
@Schema(description = "字典类型", example = "sys_gender")
private String dictType;
@Schema(description = "数据示例", example = "1024")
private String example;
@Schema(description = "是否为 Create 创建操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean createOperation;
@Schema(description = "是否为 Update 更新操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "false")
private Boolean updateOperation;
@Schema(description = "是否为 List 查询操作的字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperation;
@Schema(description = "List 查询操作的条件类型,参见 CodegenColumnListConditionEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "LIKE")
private String listOperationCondition;
@Schema(description = "是否为 List 查询操作的返回字段", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean listOperationResult;
@Schema(description = "显示类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "input")
private String htmlType;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;

View File

@ -5,12 +5,12 @@ import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 代码生成字段定义 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Schema(description = "管理后台 - 代码生成字段定义创建/修改 Request VO")
@Data
public class CodegenColumnBaseVO {
public class CodegenColumnSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "表编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "表编号不能为空")
@ -38,7 +38,7 @@ public class CodegenColumnBaseVO {
@Schema(description = "是否自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否自增不能为空")
private String autoIncrement;
private Boolean autoIncrement;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
@NotNull(message = "排序不能为空")

View File

@ -2,20 +2,64 @@ package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 代码生成表定义 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CodegenTableRespVO extends CodegenTableBaseVO {
public class CodegenTableRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer scene;
@Schema(description = "表名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
private String tableName;
@Schema(description = "表描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String tableComment;
@Schema(description = "备注", example = "我是备注")
private String remark;
@Schema(description = "模块名", requiredMode = Schema.RequiredMode.REQUIRED, example = "system")
private String moduleName;
@Schema(description = "业务名", requiredMode = Schema.RequiredMode.REQUIRED, example = "codegen")
private String businessName;
@Schema(description = "类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CodegenTable")
private String className;
@Schema(description = "类描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "代码生成器的表定义")
private String classComment;
@Schema(description = "作者", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
private String author;
@Schema(description = "模板类型,参见 CodegenTemplateTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer templateType;
@Schema(description = "前端类型,参见 CodegenFrontTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
private Integer frontType;
@Schema(description = "父菜单编号", example = "1024")
private Long parentMenuId;
@Schema(description = "主表的编号", example = "2048")
private Long masterTableId;
@Schema(description = "子表关联主表的字段编号", example = "4096")
private Long subJoinColumnId;
@Schema(description = "主表与子表是否一对多", example = "4096")
private Boolean subJoinMany;
@Schema(description = "树表的父字段编号", example = "8192")
private Long treeParentColumnId;
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Integer dataSourceConfigId;

View File

@ -1,16 +1,21 @@
package cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
/**
* 代码生成 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Schema(description = "管理后台 - 代码生成表定义创建/修改 Response VO")
@Data
public class CodegenTableBaseVO {
public class CodegenTableSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
@Schema(description = "生成场景,参见 CodegenSceneEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "导入类型不能为空")
@ -70,4 +75,26 @@ public class CodegenTableBaseVO {
@Schema(description = "树表的名字字段编号", example = "16384")
private Long treeNameColumnId;
@AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
@JsonIgnore
public boolean isParentMenuIdValid() {
// 生成场景为管理后台时必须设置上级菜单不然生成的菜单 SQL 是无父级菜单的
return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
|| getParentMenuId() != null;
}
@AssertTrue(message = "关联的父表信息不全")
@JsonIgnore
public boolean isSubValid() {
return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
|| (ObjectUtil.isAllNotEmpty(masterTableId, subJoinColumnId, subJoinMany));
}
@AssertTrue(message = "关联的树表信息不全")
@JsonIgnore
public boolean isTreeValid() {
return ObjectUtil.notEqual(templateType, CodegenTemplateTypeEnum.TREE)
|| (ObjectUtil.isAllNotEmpty(treeParentColumnId, treeNameColumnId));
}
}

View File

@ -1,12 +1,11 @@
package cn.iocoder.yudao.module.infra.convert.codegen;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenDetailRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenPreviewRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import com.baomidou.mybatisplus.generator.config.po.TableField;
@ -20,7 +19,6 @@ import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Mapper
public interface CodegenConvert {
@ -54,40 +52,18 @@ public interface CodegenConvert {
return jdbcType.name();
}
// ========== CodegenTableDO 相关 ==========
List<CodegenTableRespVO> convertList05(List<CodegenTableDO> list);
CodegenTableRespVO convert(CodegenTableDO bean);
PageResult<CodegenTableRespVO> convertPage(PageResult<CodegenTableDO> page);
// ========== CodegenTableDO 相关 ==========
List<CodegenColumnRespVO> convertList02(List<CodegenColumnDO> list);
CodegenTableDO convert(CodegenUpdateReqVO.Table bean);
List<CodegenColumnDO> convertList03(List<CodegenUpdateReqVO.Column> columns);
List<DatabaseTableRespVO> convertList04(List<TableInfo> list);
// ========== 其它 ==========
default CodegenDetailRespVO convert(CodegenTableDO table, List<CodegenColumnDO> columns) {
CodegenDetailRespVO respVO = new CodegenDetailRespVO();
respVO.setTable(convert(table));
respVO.setColumns(convertList02(columns));
respVO.setTable(BeanUtils.toBean(table, CodegenTableRespVO.class));
respVO.setColumns(BeanUtils.toBean(columns, CodegenColumnRespVO.class));
return respVO;
}
default List<CodegenPreviewRespVO> convert(Map<String, String> codes) {
return codes.entrySet().stream().map(entry -> {
CodegenPreviewRespVO respVO = new CodegenPreviewRespVO();
respVO.setFilePath(entry.getKey());
respVO.setCode(entry.getValue());
return respVO;
}).collect(Collectors.toList());
return CollectionUtils.convertList(codes.entrySet(),
entry -> new CodegenPreviewRespVO().setFilePath(entry.getKey()).setCode(entry.getValue()));
}
}

View File

@ -70,7 +70,7 @@ public interface CodegenService {
* @param id 表编号
* @return 表定义
*/
CodegenTableDO getCodegenTablePage(Long id);
CodegenTableDO getCodegenTable(Long id);
/**
* 获得指定表的字段定义数组
@ -91,7 +91,6 @@ public interface CodegenService {
/**
* 获得数据库自带的表定义列表
*
*
* @param dataSourceConfigId 数据源的配置编号
* @param name 表名称
* @param comment 表描述

View File

@ -3,12 +3,11 @@ package cn.iocoder.yudao.module.infra.service.codegen;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import cn.iocoder.yudao.module.infra.convert.codegen.CodegenConvert;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
@ -22,6 +21,7 @@ import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -31,6 +31,8 @@ import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
/**
@ -69,7 +71,7 @@ public class CodegenServiceImpl implements CodegenService {
return ids;
}
public Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
private Long createCodegen(Long userId, Long dataSourceConfigId, String tableName) {
// 从数据库中获得数据库表结构
TableInfo tableInfo = databaseTableService.getTable(dataSourceConfigId, tableName);
// 导入
@ -103,7 +105,8 @@ public class CodegenServiceImpl implements CodegenService {
return table.getId();
}
private void validateTableInfo(TableInfo tableInfo) {
@VisibleForTesting
void validateTableInfo(TableInfo tableInfo) {
if (tableInfo == null) {
throw exception(CODEGEN_IMPORT_TABLE_NULL);
}
@ -139,10 +142,10 @@ public class CodegenServiceImpl implements CodegenService {
}
// 更新 table 表定义
CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable());
CodegenTableDO updateTableObj = BeanUtils.toBean(updateReqVO.getTable(), CodegenTableDO.class);
codegenTableMapper.updateById(updateTableObj);
// 更新 column 字段定义
List<CodegenColumnDO> updateColumnObjs = CodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns());
List<CodegenColumnDO> updateColumnObjs = BeanUtils.toBean(updateReqVO.getColumns(), CodegenColumnDO.class);
updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
}
@ -161,29 +164,28 @@ public class CodegenServiceImpl implements CodegenService {
}
private void syncCodegen0(Long tableId, TableInfo tableInfo) {
// 校验导入的表和字段非空
// 1. 校验导入的表和字段非空
validateTableInfo(tableInfo);
List<TableField> tableFields = tableInfo.getFields();
// 构建 CodegenColumnDO 数组只同步新增的字段
// 2. 构建 CodegenColumnDO 数组只同步新增的字段
List<CodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, CodegenColumnDO::getColumnName);
Set<String> codegenColumnNames = convertSet(codegenColumns, CodegenColumnDO::getColumnName);
//计算需要修改的字段插入时重新插入删除时将原来的删除
BiPredicate<TableField, CodegenColumnDO> pr =
// 3.1 计算需要修改的字段插入时重新插入删除时将原来的删除
Map<String, CodegenColumnDO> codegenColumnDOMap = convertMap(codegenColumns, CodegenColumnDO::getColumnName);
BiPredicate<TableField, CodegenColumnDO> primaryKeyPredicate =
(tableField, codegenColumn) -> tableField.getMetaInfo().getJdbcType().name().equals(codegenColumn.getDataType())
&& tableField.getMetaInfo().isNullable() == codegenColumn.getNullable()
&& tableField.isKeyFlag() == codegenColumn.getPrimaryKey()
&& tableField.getComment().equals(codegenColumn.getColumnComment());
Map<String, CodegenColumnDO> codegenColumnDOMap = CollectionUtils.convertMap(codegenColumns, CodegenColumnDO::getColumnName);
//需要修改的字段
Set<String> modifyFieldNames = tableFields.stream()
.filter(tableField -> codegenColumnDOMap.get(tableField.getColumnName()) != null
&& !pr.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
&& !primaryKeyPredicate.test(tableField, codegenColumnDOMap.get(tableField.getColumnName())))
.map(TableField::getColumnName)
.collect(Collectors.toSet());
// 计算需要删除的字段
Set<String> tableFieldNames = CollectionUtils.convertSet(tableFields, TableField::getName);
// 3.2 计算需要删除的字段
Set<String> tableFieldNames = convertSet(tableFields, TableField::getName);
Set<Long> deleteColumnIds = codegenColumns.stream()
.filter(column -> (!tableFieldNames.contains(column.getColumnName())) || modifyFieldNames.contains(column.getColumnName()))
.map(CodegenColumnDO::getId).collect(Collectors.toSet());
@ -193,10 +195,10 @@ public class CodegenServiceImpl implements CodegenService {
throw exception(CODEGEN_SYNC_NONE_CHANGE);
}
// 插入新增的字段
// 4.1 插入新增的字段
List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
codegenColumnMapper.insertBatch(columns);
// 删除不存在的字段
// 4.2 删除不存在的字段
if (CollUtil.isNotEmpty(deleteColumnIds)) {
codegenColumnMapper.deleteBatchIds(deleteColumnIds);
}
@ -227,7 +229,7 @@ public class CodegenServiceImpl implements CodegenService {
}
@Override
public CodegenTableDO getCodegenTablePage(Long id) {
public CodegenTableDO getCodegenTable(Long id) {
return codegenTableMapper.selectById(id);
}
@ -277,10 +279,10 @@ public class CodegenServiceImpl implements CodegenService {
public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
// 移除在 Codegen 已经存在的
Set<String> existsTables = CollectionUtils.convertSet(
Set<String> existsTables = convertSet(
codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
tables.removeIf(table -> existsTables.contains(table.getName()));
return CodegenConvert.INSTANCE.convertList04(tables);
return BeanUtils.toBean(tables, DatabaseTableRespVO.class);
}
}

View File

@ -269,7 +269,7 @@ const queryParams = reactive({
#foreach ($column in $columns)
#if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN')
$column.javaField: null,
$column.javaField: undefined,
#end
#if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
$column.javaField: [],

View File

@ -0,0 +1,557 @@
package cn.iocoder.yudao.module.infra.service.codegen;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenCreateListReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.CodegenUpdateReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnSaveReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTablePageReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.DatabaseTableRespVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
import cn.iocoder.yudao.module.infra.service.db.DatabaseTableService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* {@link CodegenServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(CodegenServiceImpl.class)
public class CodegenServiceImplTest extends BaseDbUnitTest {
@Resource
private CodegenServiceImpl codegenService;
@Resource
private CodegenTableMapper codegenTableMapper;
@Resource
private CodegenColumnMapper codegenColumnMapper;
@MockBean
private DatabaseTableService databaseTableService;
@MockBean
private AdminUserApi userApi;
@MockBean
private CodegenBuilder codegenBuilder;
@MockBean
private CodegenEngine codegenEngine;
@MockBean
private CodegenProperties codegenProperties;
@Test
public void testCreateCodegenList() {
// 准备参数
Long userId = randomLongId();
CodegenCreateListReqVO reqVO = randomPojo(CodegenCreateListReqVO.class,
o -> o.setDataSourceConfigId(1L).setTableNames(Collections.singletonList("t_yunai")));
// mock 方法TableInfo
TableInfo tableInfo = mock(TableInfo.class);
when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
.thenReturn(tableInfo);
when(tableInfo.getComment()).thenReturn("芋艿");
// mock 方法TableInfo fields
TableField field01 = mock(TableField.class);
when(field01.getComment()).thenReturn("主键");
TableField field02 = mock(TableField.class);
when(field02.getComment()).thenReturn("名字");
List<TableField> fields = Arrays.asList(field01, field02);
when(tableInfo.getFields()).thenReturn(fields);
// mock 方法CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class);
when(codegenBuilder.buildTable(same(tableInfo))).thenReturn(table);
// mock 方法AdminUserRespDTO
AdminUserRespDTO user = randomPojo(AdminUserRespDTO.class, o -> o.setNickname("芋头"));
when(userApi.getUser(eq(userId))).thenReturn(success(user));
// mock 方法CodegenColumnDO
List<CodegenColumnDO> columns = randomPojoList(CodegenColumnDO.class);
when(codegenBuilder.buildColumns(eq(table.getId()), same(fields)))
.thenReturn(columns);
// mock 方法CodegenProperties
when(codegenProperties.getFrontType()).thenReturn(CodegenFrontTypeEnum.VUE3.getType());
// 调用
List<Long> result = codegenService.createCodegenList(userId, reqVO);
// 断言
assertEquals(1, result.size());
// 断言CodegenTableDO
CodegenTableDO dbTable = codegenTableMapper.selectList().get(0);
assertPojoEquals(table, dbTable);
assertEquals(1L, dbTable.getDataSourceConfigId());
assertEquals(CodegenSceneEnum.ADMIN.getScene(), dbTable.getScene());
assertEquals(CodegenFrontTypeEnum.VUE3.getType(), dbTable.getFrontType());
assertEquals("芋头", dbTable.getAuthor());
// 断言CodegenColumnDO
List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
assertEquals(columns.size(), dbColumns.size());
assertTrue(dbColumns.get(0).getPrimaryKey());
for (int i = 0; i < dbColumns.size(); i++) {
assertPojoEquals(columns.get(i), dbColumns.get(i));
}
}
@Test
public void testValidateTableInfo() {
// 情况一
assertServiceException(() -> codegenService.validateTableInfo(null),
CODEGEN_IMPORT_TABLE_NULL);
// 情况二
TableInfo tableInfo = mock(TableInfo.class);
assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL);
// 情况三
when(tableInfo.getComment()).thenReturn("芋艿");
assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
CODEGEN_IMPORT_COLUMNS_NULL);
// 情况四
TableField field = mock(TableField.class);
when(field.getName()).thenReturn("name");
when(tableInfo.getFields()).thenReturn(Collections.singletonList(field));
assertServiceException(() -> codegenService.validateTableInfo(tableInfo),
CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL, field.getName());
}
@Test
public void testUpdateCodegen_notExists() {
// 准备参数
CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class);
// mock 方法
// 调用并断言
assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
CODEGEN_TABLE_NOT_EXISTS);
}
@Test
public void testUpdateCodegen_sub_masterNotExists() {
// mock 数据
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table);
// 准备参数
CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
o -> o.getTable().setId(table.getId())
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType()));
// 调用并断言
assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
}
@Test
public void testUpdateCodegen_sub_columnNotExists() {
// mock 数据
CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
o -> o.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(subTable);
// mock 数据master
CodegenTableDO masterTable = randomPojo(CodegenTableDO.class,
o -> o.setTemplateType(CodegenTemplateTypeEnum.MASTER_ERP.getType())
.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(masterTable);
// 准备参数
CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
o -> o.getTable().setId(subTable.getId())
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setMasterTableId(masterTable.getId()));
// 调用并断言
assertServiceException(() -> codegenService.updateCodegen(updateReqVO),
CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
}
@Test
public void testUpdateCodegen_success() {
// mock 数据
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table);
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column01);
CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column02);
// 准备参数
CodegenUpdateReqVO updateReqVO = randomPojo(CodegenUpdateReqVO.class,
o -> o.getTable().setId(table.getId())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType())
.setScene(CodegenSceneEnum.ADMIN.getScene()));
CodegenColumnSaveReqVO columnVO01 = randomPojo(CodegenColumnSaveReqVO.class,
o -> o.setId(column01.getId()).setTableId(table.getId()));
CodegenColumnSaveReqVO columnVO02 = randomPojo(CodegenColumnSaveReqVO.class,
o -> o.setId(column02.getId()).setTableId(table.getId()));
updateReqVO.setColumns(Arrays.asList(columnVO01, columnVO02));
// 调用
codegenService.updateCodegen(updateReqVO);
// 断言
CodegenTableDO dbTable = codegenTableMapper.selectById(table.getId());
assertPojoEquals(updateReqVO.getTable(), dbTable);
List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
assertEquals(2, dbColumns.size());
assertPojoEquals(columnVO01, dbColumns.get(0));
assertPojoEquals(columnVO02, dbColumns.get(1));
}
@Test
public void testSyncCodegenFromDB() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class, o -> o.setTableName("t_yunai")
.setDataSourceConfigId(1L).setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table);
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
.setColumnName("id"));
codegenColumnMapper.insert(column01);
CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId())
.setColumnName("name"));
codegenColumnMapper.insert(column02);
// 准备参数
Long tableId = table.getId();
// mock 方法TableInfo
TableInfo tableInfo = mock(TableInfo.class);
when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
.thenReturn(tableInfo);
when(tableInfo.getComment()).thenReturn("芋艿");
// mock 方法TableInfo fields
TableField field01 = mock(TableField.class);
when(field01.getComment()).thenReturn("主键");
TableField field03 = mock(TableField.class);
when(field03.getComment()).thenReturn("分类");
List<TableField> fields = Arrays.asList(field01, field03);
when(tableInfo.getFields()).thenReturn(fields);
when(databaseTableService.getTable(eq(1L), eq("t_yunai")))
.thenReturn(tableInfo);
// mock 方法CodegenTableDO
List<CodegenColumnDO> newColumns = randomPojoList(CodegenColumnDO.class);
when(codegenBuilder.buildColumns(eq(table.getId()), argThat(tableFields -> {
assertEquals(2, tableFields.size());
assertSame(tableInfo.getFields(), tableFields);
return true;
}))).thenReturn(newColumns);
// 调用
codegenService.syncCodegenFromDB(tableId);
// 断言
List<CodegenColumnDO> dbColumns = codegenColumnMapper.selectList();
assertEquals(newColumns.size(), dbColumns.size());
assertPojoEquals(newColumns.get(0), dbColumns.get(0));
assertPojoEquals(newColumns.get(1), dbColumns.get(1));
}
@Test
public void testDeleteCodegen_notExists() {
assertServiceException(() -> codegenService.deleteCodegen(randomLongId()),
CODEGEN_TABLE_NOT_EXISTS);
}
@Test
public void testDeleteCodegen_success() {
// mock 数据
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table);
CodegenColumnDO column = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column);
// 准备参数
Long tableId = table.getId();
// 调用
codegenService.deleteCodegen(tableId);
// 断言
assertNull(codegenTableMapper.selectById(tableId));
assertEquals(0, codegenColumnMapper.selectList().size());
}
@Test
public void testGetCodegenTableList() {
// mock 数据
CodegenTableDO table01 = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table01);
CodegenTableDO table02 = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(table02);
// 准备参数
Long dataSourceConfigId = table01.getDataSourceConfigId();
// 调用
List<CodegenTableDO> result = codegenService.getCodegenTableList(dataSourceConfigId);
// 断言
assertEquals(1, result.size());
assertPojoEquals(table01, result.get(0));
}
@Test
public void testGetCodegenTablePage() {
// mock 数据
CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> {
o.setTableName("t_yunai");
o.setTableComment("芋艿");
o.setClassName("SystemYunai");
o.setCreateTime(buildTime(2021, 3, 10));
}).setScene(CodegenSceneEnum.ADMIN.getScene());
codegenTableMapper.insert(tableDO);
// 测试 tableName 不匹配
codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableName(randomString())));
// 测试 tableComment 不匹配
codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setTableComment(randomString())));
// 测试 className 不匹配
codegenTableMapper.insert(cloneIgnoreId(tableDO, o -> o.setClassName(randomString())));
// 测试 createTime 不匹配
codegenTableMapper.insert(cloneIgnoreId(tableDO, logDO -> logDO.setCreateTime(buildTime(2021, 4, 10))));
// 准备参数
CodegenTablePageReqVO reqVO = new CodegenTablePageReqVO();
reqVO.setTableName("yunai");
reqVO.setTableComment("");
reqVO.setClassName("Yunai");
reqVO.setCreateTime(buildBetweenTime(2021, 3, 1, 2021, 3, 31));
// 调用
PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(reqVO);
// 断言只查到了一条符合条件的
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(tableDO, pageResult.getList().get(0));
}
@Test
public void testGetCodegenTable() {
// mock 数据
CodegenTableDO tableDO = randomPojo(CodegenTableDO.class, o -> o.setScene(CodegenSceneEnum.ADMIN.getScene()));
codegenTableMapper.insert(tableDO);
// 准备参数
Long id = tableDO.getId();
// 调用
CodegenTableDO result = codegenService.getCodegenTable(id);
// 断言
assertPojoEquals(tableDO, result);
}
@Test
public void testGetCodegenColumnListByTableId() {
// mock 数据
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class);
codegenColumnMapper.insert(column01);
CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class);
codegenColumnMapper.insert(column02);
// 准备参数
Long tableId = column01.getTableId();
// 调用
List<CodegenColumnDO> result = codegenService.getCodegenColumnListByTableId(tableId);
// 断言
assertEquals(1, result.size());
assertPojoEquals(column01, result.get(0));
}
@Test
public void testGenerationCodes_tableNotExists() {
assertServiceException(() -> codegenService.generationCodes(randomLongId()),
CODEGEN_TABLE_NOT_EXISTS);
}
@Test
public void testGenerationCodes_columnNotExists() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
codegenTableMapper.insert(table);
// 准备参数
Long tableId = table.getId();
// 调用并断言
assertServiceException(() -> codegenService.generationCodes(tableId),
CODEGEN_COLUMN_NOT_EXISTS);
}
@Test
public void testGenerationCodes_sub_tableNotExists() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
codegenTableMapper.insert(table);
// mock 数据CodegenColumnDO
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column01);
// 准备参数
Long tableId = table.getId();
// 调用并断言
assertServiceException(() -> codegenService.generationCodes(tableId),
CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
}
@Test
public void testGenerationCodes_sub_columnNotExists() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
codegenTableMapper.insert(table);
// mock 数据CodegenColumnDO
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column01);
// mock 数据sub CodegenTableDO
CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setMasterTableId(table.getId()));
codegenTableMapper.insert(subTable);
// 准备参数
Long tableId = table.getId();
// 调用并断言
assertServiceException(() -> codegenService.generationCodes(tableId),
CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
}
@Test
public void testGenerationCodes_one_success() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType()));
codegenTableMapper.insert(table);
// mock 数据CodegenColumnDO
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column01);
CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column02);
// mock 执行生成
Map<String, String> codes = MapUtil.of(randomString(), randomString());
when(codegenEngine.execute(eq(table), argThat(columns -> {
assertEquals(2, columns.size());
assertEquals(column01, columns.get(0));
assertEquals(column02, columns.get(1));
return true;
}), isNull(), isNull())).thenReturn(codes);
// 准备参数
Long tableId = table.getId();
// 调用
Map<String, String> result = codegenService.generationCodes(tableId);
// 断言
assertSame(codes, result);
}
@Test
public void testGenerationCodes_master_success() {
// mock 数据CodegenTableDO
CodegenTableDO table = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()));
codegenTableMapper.insert(table);
// mock 数据CodegenColumnDO
CodegenColumnDO column01 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column01);
CodegenColumnDO column02 = randomPojo(CodegenColumnDO.class, o -> o.setTableId(table.getId()));
codegenColumnMapper.insert(column02);
// mock 数据sub CodegenTableDO
CodegenTableDO subTable = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setMasterTableId(table.getId())
.setSubJoinColumnId(1024L));
codegenTableMapper.insert(subTable);
// mock 数据sub CodegenColumnDO
CodegenColumnDO subColumn01 = randomPojo(CodegenColumnDO.class, o -> o.setId(1024L).setTableId(subTable.getId()));
codegenColumnMapper.insert(subColumn01);
// mock 执行生成
Map<String, String> codes = MapUtil.of(randomString(), randomString());
when(codegenEngine.execute(eq(table), argThat(columns -> {
assertEquals(2, columns.size());
assertEquals(column01, columns.get(0));
assertEquals(column02, columns.get(1));
return true;
}), argThat(tables -> {
assertEquals(1, tables.size());
assertPojoEquals(subTable, tables.get(0));
return true;
}), argThat(columns -> {
assertEquals(1, columns.size());
assertPojoEquals(subColumn01, columns.size());
return true;
}))).thenReturn(codes);
// 准备参数
Long tableId = table.getId();
// 调用
Map<String, String> result = codegenService.generationCodes(tableId);
// 断言
assertSame(codes, result);
}
@Test
public void testGetDatabaseTableList() {
// 准备参数
Long dataSourceConfigId = randomLongId();
String name = randomString();
String comment = randomString();
// mock 方法
TableInfo tableInfo01 = mock(TableInfo.class);
when(tableInfo01.getName()).thenReturn("t_yunai");
when(tableInfo01.getComment()).thenReturn("芋艿");
TableInfo tableInfo02 = mock(TableInfo.class);
when(tableInfo02.getName()).thenReturn("t_yunai_02");
when(tableInfo02.getComment()).thenReturn("芋艿_02");
when(databaseTableService.getTableList(eq(dataSourceConfigId), eq(name), eq(comment)))
.thenReturn(ListUtil.toList(tableInfo01, tableInfo02));
// mock 数据
CodegenTableDO tableDO = randomPojo(CodegenTableDO.class,
o -> o.setScene(CodegenSceneEnum.ADMIN.getScene())
.setTableName("t_yunai_02")
.setDataSourceConfigId(dataSourceConfigId));
codegenTableMapper.insert(tableDO);
// 调用
List<DatabaseTableRespVO> result = codegenService.getDatabaseTableList(dataSourceConfigId, name, comment);
// 断言
assertEquals(1, result.size());
assertEquals("t_yunai", result.get(0).getName());
assertEquals("芋艿", result.get(0).getComment());
}
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import org.apache.ibatis.type.JdbcType;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class CodegenBuilderTest extends BaseMockitoUnitTest {
@InjectMocks
private CodegenBuilder codegenBuilder;
@Test
public void testBuildTable() {
// 准备参数
TableInfo tableInfo = mock(TableInfo.class);
// mock 方法
when(tableInfo.getName()).thenReturn("system_user");
when(tableInfo.getComment()).thenReturn("用户");
// 调用
CodegenTableDO table = codegenBuilder.buildTable(tableInfo);
// 断言
assertEquals("system_user", table.getTableName());
assertEquals("用户", table.getTableComment());
assertEquals("system", table.getModuleName());
assertEquals("user", table.getBusinessName());
assertEquals("User", table.getClassName());
assertEquals("用户", table.getClassComment());
}
@Test
public void testBuildColumns() {
// 准备参数
Long tableId = randomLongId();
TableField tableField = mock(TableField.class);
List<TableField> tableFields = Collections.singletonList(tableField);
// mock 方法
TableField.MetaInfo metaInfo = mock(TableField.MetaInfo.class);
when(tableField.getMetaInfo()).thenReturn(metaInfo);
when(metaInfo.getJdbcType()).thenReturn(JdbcType.BIGINT);
when(tableField.getComment()).thenReturn("编号");
when(tableField.isKeyFlag()).thenReturn(true);
when(tableField.isKeyIdentityFlag()).thenReturn(true);
IColumnType columnType = mock(IColumnType.class);
when(tableField.getColumnType()).thenReturn(columnType);
when(columnType.getType()).thenReturn("Long");
when(tableField.getName()).thenReturn("id2");
when(tableField.getPropertyName()).thenReturn("id");
// 调用
List<CodegenColumnDO> columns = codegenBuilder.buildColumns(tableId, tableFields);
// 断言
assertEquals(1, columns.size());
CodegenColumnDO column = columns.get(0);
assertEquals(tableId, column.getTableId());
assertEquals("id2", column.getColumnName());
assertEquals("BIGINT", column.getDataType());
assertEquals("编号", column.getColumnComment());
assertFalse(column.getNullable());
assertTrue(column.getPrimaryKey());
assertTrue(column.getAutoIncrement());
assertEquals(1, column.getOrdinalPosition());
assertEquals("Long", column.getJavaType());
assertEquals("id", column.getJavaField());
assertNull(column.getDictType());
assertNotNull(column.getExample());
assertFalse(column.getCreateOperation());
assertTrue(column.getUpdateOperation());
assertFalse(column.getListOperation());
assertEquals("=", column.getListOperationCondition());
assertTrue(column.getListOperationResult());
assertEquals("input", column.getHtmlType());
}
}

View File

@ -0,0 +1,127 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link CodegenEngine} 的单元测试抽象基类
*
* @author 芋道源码
*/
public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest {
@InjectMocks
protected CodegenEngine codegenEngine;
@Spy
protected CodegenProperties codegenProperties = new CodegenProperties()
.setBasePackage("cn.iocoder.yudao");
@BeforeEach
public void setUp() {
codegenEngine.initGlobalBindingMap();
}
protected static CodegenTableDO getTable(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
}
protected static List<CodegenColumnDO> getColumnList(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
list.forEach(column -> {
if (column.getNullable() == null) {
column.setNullable(false);
}
if (column.getCreateOperation() == null) {
column.setCreateOperation(false);
}
if (column.getUpdateOperation() == null) {
column.setUpdateOperation(false);
}
if (column.getListOperation() == null) {
column.setListOperation(false);
}
if (column.getListOperationResult() == null) {
column.setListOperationResult(false);
}
});
return list;
}
@SuppressWarnings("rawtypes")
protected static void assertResult(Map<String, String> result, String path) {
String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
assertEquals(asserts.size(), result.size());
// 校验每个文件
asserts.forEach(assertMap -> {
String contentPath = (String) assertMap.get("contentPath");
String filePath = (String) assertMap.get("filePath");
String content = ResourceUtil.readUtf8Str(path + "/" + contentPath);
assertEquals(content, result.get(filePath), filePath + ":不匹配");
});
}
// ==================== 调试专用 ====================
/**
* 调试使用将生成的代码写入到文件
*
* @param result 生成的代码
* @param path 写入文件的路径
*/
protected void writeFile(Map<String, String> result, String path) {
// 生成压缩包
String[] paths = result.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipUtil.zip(outputStream, paths, ins);
// 写入文件
FileUtil.writeBytes(outputStream.toByteArray(), path);
}
/**
* 调试使用将生成的结果写入到文件
*
* @param result 生成的代码
* @param basePath 写入文件的路径绝对路径
*/
protected void writeResult(Map<String, String> result, String basePath) {
// 写入文件内容
List<Map<String, String>> asserts = new ArrayList<>();
result.forEach((filePath, fileContent) -> {
String lastFilePath = StrUtil.subAfter(filePath, '/', true);
String contentPath = StrUtil.subAfter(lastFilePath, '.', true)
+ '/' + StrUtil.subBefore(lastFilePath, '.', true);
asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
.put("contentPath", contentPath).build());
FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
});
// 写入 assert.json 文件
FileUtil.writeUtf8String(JsonUtils.toJsonPrettyString(asserts), basePath +"/assert.json");
}
}

View File

@ -0,0 +1,98 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
// TODO @puhui999单测需要 fix
/**
* {@link CodegenEngine} Vue2 + Element UI 单元测试
*
* @author 芋道源码
*/
@Disabled
public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
@Test
public void testExecute_vue2_one() {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE2.getType())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue2_one");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue2_one");
}
@Test
public void testExecute_vue2_tree() {
// 准备参数
CodegenTableDO table = getTable("category")
.setFrontType(CodegenFrontTypeEnum.VUE2.getType())
.setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
List<CodegenColumnDO> columns = getColumnList("category");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue2_tree");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue2_tree");
// writeFile(result, "/Users/yunai/test/demo66.zip");
}
@Test
public void testExecute_vue2_master_normal() {
testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue2_master_normal");
}
@Test
public void testExecute_vue2_master_erp() {
testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue2_master_erp");
}
@Test
public void testExecute_vue2_master_inner() {
testExecute_vue2_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue2_master_inner");
}
private void testExecute_vue2_master(CodegenTemplateTypeEnum templateType,
String path) {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE2.getType())
.setTemplateType(templateType.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 准备参数子表
CodegenTableDO contactTable = getTable("contact")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE2.getType())
.setSubJoinColumnId(100L).setSubJoinMany(true);
List<CodegenColumnDO> contactColumns = getColumnList("contact");
// 准备参数班主任
CodegenTableDO teacherTable = getTable("teacher")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE2.getType())
.setSubJoinColumnId(200L).setSubJoinMany(false);
List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns,
Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
// 断言
assertResult(result, path);
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
// writeFile(result, "/Users/yunai/test/demo11.zip");
}
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* {@link CodegenEngine} Vue2 + Element Plus 单元测试
*
* @author 芋道源码
*/
public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
@Test
public void testExecute_vue3_one() {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_one");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
}
@Test
public void testExecute_vue3_tree() {
// 准备参数
CodegenTableDO table = getTable("category")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
List<CodegenColumnDO> columns = getColumnList("category");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_tree");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
// writeFile(result, "/Users/yunai/test/demo66.zip");
}
@Test
public void testExecute_vue3_master_normal() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
}
@Test
public void testExecute_vue3_master_erp() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
}
@Test
public void testExecute_vue3_master_inner() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
}
private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
String path) {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(templateType.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 准备参数子表
CodegenTableDO contactTable = getTable("contact")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(100L).setSubJoinMany(true);
List<CodegenColumnDO> contactColumns = getColumnList("contact");
// 准备参数班主任
CodegenTableDO teacherTable = getTable("teacher")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(200L).setSubJoinMany(false);
List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns,
Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
// 断言
assertResult(result, path);
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
// writeFile(result, "/Users/yunai/test/demo11.zip");
}
}

View File

@ -1,4 +0,0 @@
/**
* 占位无其它作用
*/
package cn.iocoder.yudao.module.infra.service.codegen;

View File

@ -0,0 +1,12 @@
<?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="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@ -197,11 +197,11 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
birthday: null,
name: undefined,
birthday: undefined,
birthday: [],
sex: null,
enabled: null,
sex: undefined,
enabled: undefined,
createTime: []
})
const queryFormRef = ref() // 搜索的表单

View File

@ -192,11 +192,11 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
birthday: null,
name: undefined,
birthday: undefined,
birthday: [],
sex: null,
enabled: null,
sex: undefined,
enabled: undefined,
createTime: []
})
const queryFormRef = ref() // 搜索的表单

View File

@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
birthday: null,
name: undefined,
birthday: undefined,
birthday: [],
sex: null,
enabled: null,
sex: undefined,
enabled: undefined,
createTime: []
})
const queryFormRef = ref() // 搜索的表单

View File

@ -177,11 +177,11 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: null,
birthday: null,
name: undefined,
birthday: undefined,
birthday: [],
sex: null,
enabled: null,
sex: undefined,
enabled: undefined,
createTime: []
})
const queryFormRef = ref() // 搜索的表单

View File

@ -106,7 +106,7 @@ const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中
const list = ref([]) // 列表的数据
const queryParams = reactive({
name: null
name: undefined
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中

View File

@ -8,3 +8,5 @@ DELETE FROM "infra_api_error_log";
DELETE FROM "infra_file_config";
DELETE FROM "infra_test_demo";
DELETE FROM "infra_data_source_config";
DELETE FROM "infra_codegen_table";
DELETE FROM "infra_codegen_column";

View File

@ -170,3 +170,59 @@ CREATE TABLE IF NOT EXISTS "infra_data_source_config" (
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '数据源配置表';
CREATE TABLE IF NOT EXISTS "infra_codegen_table" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"data_source_config_id" bigint not null,
"scene" tinyint not null DEFAULT 1,
"table_name" varchar(200) NOT NULL,
"table_comment" varchar(500) NOT NULL,
"remark" varchar(500) NOT NULL,
"module_name" varchar(30) NOT NULL,
"business_name" varchar(30) NOT NULL,
"class_name" varchar(100) NOT NULL,
"class_comment" varchar(50) NOT NULL,
"author" varchar(50) NOT NULL,
"template_type" tinyint not null DEFAULT 1,
"front_type" tinyint not null,
"parent_menu_id" bigint not null,
"master_table_id" bigint not null,
"sub_join_column_id" bigint not null,
"sub_join_many" bit not null,
"tree_parent_column_id" bigint not null,
"tree_name_column_id" bigint not null,
"creator" varchar(64) DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '代码生成表定义表';
CREATE TABLE IF NOT EXISTS "infra_codegen_column" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"table_id" bigint not null,
"column_name" varchar(200) NOT NULL,
"data_type" varchar(100) NOT NULL,
"column_comment" varchar(500) NOT NULL,
"nullable" tinyint not null,
"primary_key" tinyint not null,
"auto_increment" varchar(5) not null,
"ordinal_position" int not null,
"java_type" varchar(32) NOT NULL,
"java_field" varchar(64) NOT NULL,
"dict_type" varchar(200) NOT NULL,
"example" varchar(64) NOT NULL,
"create_operation" bit not null,
"update_operation" bit not null,
"list_operation" bit not null,
"list_operation_condition" varchar(32) not null,
"list_operation_result" bit not null,
"html_type" varchar(32) NOT NULL,
"creator" varchar(64) DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '代码生成表字段定义表';

View File

@ -14,8 +14,7 @@ import java.util.Set;
@Data
public class UserSaveReqVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "用户编号不能为空")
@Schema(description = "用户编号", example = "1024")
private Long id;
@Schema(description = "用户账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")