init
This commit is contained in:
28
salpa-system/pom.xml
Normal file
28
salpa-system/pom.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>salpa</artifactId>
|
||||
<groupId>com.salpa</groupId>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>salpa-system</artifactId>
|
||||
|
||||
<description>
|
||||
system系统模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.salpa</groupId>
|
||||
<artifactId>salpa-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
130
salpa-system/salpa-system.iml
Normal file
130
salpa-system/salpa-system.iml
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Spring" name="Spring">
|
||||
<configuration />
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_11">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="salpa-common" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.5.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.5.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.5.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.5.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.4.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.63" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.6.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.8" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.11.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-fileupload:commons-fileupload:1.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.21" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:3.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.deepoove:poi-tl:1.10.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.deepoove:poi-ooxml-schemas-extra:4.1.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-transcoder:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-anim:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-css:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-ext:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-parser:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-svg-dom:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-awt-util:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:xmlgraphics-commons:2.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.0.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-bridge:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-script:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-dom:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: xalan:xalan:2.7.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: xalan:serializer:2.7.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-gvt:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-shared-resources:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-svggen:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-util:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-constants:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-i18n:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-xml:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: xml-apis:xml-apis-ext:1.3.04" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.xmlgraphics:batik-codec:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.24" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.4.2.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.sourceforge.plantuml:plantuml:1.2022.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.31" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.5.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.5.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.5.11" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.20" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.8.RELEASE" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.77.Final" level="project" />
|
||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.18" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" />
|
||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.salpa.model.domain;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* 项目模型信息管理表 project_model_info
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class ProjectModelInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** ID */
|
||||
private Integer projectId;
|
||||
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
|
||||
/** 项目描述 */
|
||||
private String projectDescription;
|
||||
|
||||
/** 项目json文件存储 */
|
||||
private String jsonFile;
|
||||
|
||||
/** 删除标识 */
|
||||
private boolean deleted;
|
||||
|
||||
/** 创建时间 */
|
||||
private Timestamp createAt;
|
||||
|
||||
/*业务字段*/
|
||||
/*组员*/
|
||||
private Long[] userIds;
|
||||
private String[] userNames;
|
||||
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
public void setProjectName(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
public String getProjectDescription() {
|
||||
return projectDescription;
|
||||
}
|
||||
|
||||
public void setProjectDescription(String projectDescription) {
|
||||
this.projectDescription = projectDescription;
|
||||
}
|
||||
|
||||
public String getJsonFile() {
|
||||
return jsonFile;
|
||||
}
|
||||
|
||||
public void setJsonFile(String jsonFile) {
|
||||
this.jsonFile = jsonFile;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public Timestamp getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(Timestamp createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Long[] getUserIds() {
|
||||
return userIds;
|
||||
}
|
||||
|
||||
public void setUserIds(Long[] userIds) {
|
||||
this.userIds = userIds;
|
||||
}
|
||||
|
||||
public String[] getUserNames() {
|
||||
return userNames;
|
||||
}
|
||||
|
||||
public void setUserNames(String[] userNames) {
|
||||
this.userNames = userNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.salpa.model.mapper;
|
||||
|
||||
import com.salpa.model.domain.ProjectModelInfo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhuff
|
||||
*/
|
||||
@Mapper
|
||||
public interface ModelMapper {
|
||||
|
||||
String getProjectIds(Long userId);
|
||||
|
||||
List<ProjectModelInfo> getList(@Param("list") List<String> list,@Param("projectName") String projectName);
|
||||
|
||||
int checkProjectNameUnique(String projectName);
|
||||
|
||||
int addProject(ProjectModelInfo projectModelInfo);
|
||||
|
||||
void updateProjectIds(@Param("projectIds") String projectIds, @Param("userId") Long userId);
|
||||
|
||||
int deleteProject(Integer projectId);
|
||||
|
||||
int updateProject(ProjectModelInfo projectModelInfo);
|
||||
|
||||
ProjectModelInfo getById(Integer projectId);
|
||||
|
||||
List<Map<String, Object>> getUserList();
|
||||
|
||||
int updateJsonFile(ProjectModelInfo projectModelInfo);
|
||||
|
||||
void addProjectIds(@Param("projectIds") String projectIds, @Param("userId") Long userId);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.salpa.model.service;
|
||||
|
||||
import com.salpa.common.core.domain.AjaxResult;
|
||||
import com.salpa.model.domain.ProjectModelInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhuff
|
||||
*/
|
||||
public interface ModelService {
|
||||
|
||||
List<ProjectModelInfo> getList(Integer pageNum,Integer pageSize,String projectName);
|
||||
|
||||
String checkProjectNameUnique(String projectName);
|
||||
|
||||
int addProject(ProjectModelInfo projectModelInfo) throws IOException;
|
||||
|
||||
int deleteProject(Integer projectId);
|
||||
|
||||
int updateProject(ProjectModelInfo projectModelInfo);
|
||||
|
||||
ProjectModelInfo getById(Integer projectId);
|
||||
|
||||
List<Map<String, Object>> getUserList();
|
||||
|
||||
int updateJsonFile(ProjectModelInfo projectModelInfo);
|
||||
|
||||
AjaxResult connectDataSource(Map map);
|
||||
|
||||
AjaxResult executeSql(Map map);
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
package com.salpa.model.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.salpa.common.constant.UserConstants;
|
||||
import com.salpa.common.core.domain.AjaxResult;
|
||||
import com.salpa.common.core.domain.entity.SysUser;
|
||||
import com.salpa.common.utils.SecurityUtils;
|
||||
import com.salpa.model.domain.ProjectModelInfo;
|
||||
import com.salpa.model.mapper.ModelMapper;
|
||||
import com.salpa.model.service.ModelService;
|
||||
import com.salpa.system.domain.SysUserRole;
|
||||
import com.salpa.system.mapper.SysUserMapper;
|
||||
import com.salpa.system.mapper.SysUserRoleMapper;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class ModelServiceImpl implements ModelService {
|
||||
|
||||
|
||||
@Autowired
|
||||
private ModelMapper modelMappper;
|
||||
|
||||
@Autowired
|
||||
private SysUserRoleMapper sysUserRoleMapper;
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
/**
|
||||
* 获取当前用户项目模型列表
|
||||
* @author zhuff
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<ProjectModelInfo> getList(Integer pageNum,Integer pageSize,String projectName) {
|
||||
SysUser user = SecurityUtils.getLoginUser().getUser();
|
||||
List<String> projectList = new ArrayList<>();
|
||||
if (!user.isAdmin()){
|
||||
/*获取当前用户所对应项目id*/
|
||||
String projectIds = modelMappper.getProjectIds(user.getUserId());
|
||||
if (projectIds != null && projectIds != "") {
|
||||
projectList = Arrays.asList(projectIds.split(","));
|
||||
}
|
||||
}
|
||||
PageHelper.startPage(pageNum,pageSize);
|
||||
List<ProjectModelInfo> list = modelMappper.getList(projectList,projectName);
|
||||
/*添加项目人员*/
|
||||
for (ProjectModelInfo projectModelInfo : list) {
|
||||
List<SysUserRole> userRole = sysUserRoleMapper.getUserRole();
|
||||
List<Long> userList = new ArrayList<>();
|
||||
List<String> userNameList = new ArrayList<>();
|
||||
for (SysUserRole sysUserRole : userRole) {
|
||||
String projectIds = sysUserRole.getProjectIds();
|
||||
if (projectIds!=null){
|
||||
String[] split = projectIds.split(",");
|
||||
for (String projectId : split) {
|
||||
if (projectId.equals(projectModelInfo.getProjectId().toString())){
|
||||
userList.add(sysUserRole.getUserId());
|
||||
userNameList.add(sysUserMapper.selectUserById(sysUserRole.getUserId()).getUserName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
projectModelInfo.setUserIds(userList.toArray(new Long[userList.size()]));
|
||||
projectModelInfo.setUserNames(userNameList.toArray(new String[userNameList.size()]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验项目模型名称是否唯一
|
||||
* @author zhuff
|
||||
* @param projectName
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String checkProjectNameUnique(String projectName) {
|
||||
int count = modelMappper.checkProjectNameUnique(projectName);
|
||||
if (count > 0)
|
||||
{
|
||||
return UserConstants.NOT_UNIQUE;
|
||||
}
|
||||
return UserConstants.UNIQUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增项目模型
|
||||
* @author zhuff
|
||||
* @param projectModelInfo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int addProject(ProjectModelInfo projectModelInfo) throws IOException {
|
||||
InputStream inputStream = new ClassPathResource("empty.json").getInputStream();
|
||||
String json = IOUtils.toString(inputStream, "UTF-8");
|
||||
Map map = JSON.parseObject(json);
|
||||
map.put("name",projectModelInfo.getProjectName());
|
||||
map.put("describe",projectModelInfo.getProjectDescription());
|
||||
projectModelInfo.setJsonFile(JSONObject.toJSONString(map));
|
||||
/*新增项目模型*/
|
||||
int i = modelMappper.addProject(projectModelInfo);
|
||||
/*获取新增项目模型的id*/
|
||||
Integer projectId = projectModelInfo.getProjectId();
|
||||
/*为用户添加项目权限*/
|
||||
Long[] userIds = projectModelInfo.getUserIds();
|
||||
for (Long userId : userIds) {
|
||||
/*获取已有项目权限*/
|
||||
String projectIds = modelMappper.getProjectIds(userId);
|
||||
if (projectIds != null && !"".equals(projectIds)){
|
||||
projectIds += ","+ projectId;
|
||||
modelMappper.updateProjectIds(projectIds,userId);
|
||||
} else {
|
||||
if ("".equals(projectIds)) {
|
||||
projectIds = projectId.toString();
|
||||
modelMappper.updateProjectIds(projectIds,userId);
|
||||
} else {
|
||||
projectIds = projectId.toString();
|
||||
modelMappper.addProjectIds(projectIds,userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项目模型
|
||||
* @author zhuff
|
||||
* @param projectId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int deleteProject(Integer projectId) {
|
||||
return modelMappper.deleteProject(projectId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改项目模型
|
||||
* @author zhuff
|
||||
* @param projectModelInfo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int updateProject(ProjectModelInfo projectModelInfo) {
|
||||
/*读取json,修改名称及描述*/
|
||||
ProjectModelInfo byId = modelMappper.getById(projectModelInfo.getProjectId());
|
||||
Map map = JSON.parseObject(byId.getJsonFile());
|
||||
map.put("name",projectModelInfo.getProjectName());
|
||||
map.put("describe",projectModelInfo.getProjectDescription());
|
||||
projectModelInfo.setJsonFile(JSONObject.toJSONString(map));
|
||||
/*修改项目模型*/
|
||||
int i = modelMappper.updateProject(projectModelInfo);
|
||||
/*删除该项目原有人员*/
|
||||
List<SysUserRole> userRole = sysUserRoleMapper.getUserRole();
|
||||
for (SysUserRole sysUserRole : userRole) {
|
||||
List<String> projectList = new ArrayList<>(Arrays.asList(sysUserRole.getProjectIds().split(",")));
|
||||
if (projectList.size()>0){
|
||||
// 获取迭代器
|
||||
Iterator<String> it = projectList.iterator();
|
||||
while(it.hasNext()){
|
||||
String str = it.next();
|
||||
if(projectModelInfo.getProjectId().toString().equals(str)){
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
String projectIds = "";
|
||||
if (projectList.size()>0){
|
||||
for (String project : projectList) {
|
||||
if (projectIds == ""){
|
||||
projectIds = project;
|
||||
} else {
|
||||
projectIds += "," + project;
|
||||
}
|
||||
}
|
||||
}
|
||||
modelMappper.updateProjectIds(projectIds,sysUserRole.getUserId());
|
||||
}
|
||||
/*添加项目现有人员*/
|
||||
Long[] userIds = projectModelInfo.getUserIds();
|
||||
for (Long userId : userIds) {
|
||||
/*获取已有项目权限*/
|
||||
String projectIds = modelMappper.getProjectIds(userId);
|
||||
if (projectIds != null && !"".equals(projectIds)){
|
||||
projectIds += ","+ projectModelInfo.getProjectId();
|
||||
modelMappper.updateProjectIds(projectIds,userId);
|
||||
} else {
|
||||
if ("".equals(projectIds)) {
|
||||
projectIds = projectModelInfo.getProjectId().toString();
|
||||
modelMappper.updateProjectIds(projectIds,userId);
|
||||
} else {
|
||||
projectIds = projectModelInfo.getProjectId().toString();
|
||||
modelMappper.addProjectIds(projectIds,userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id获取项目模型
|
||||
* @author zhuff
|
||||
* @param projectId
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ProjectModelInfo getById(Integer projectId) {
|
||||
ProjectModelInfo projectModelInfo = modelMappper.getById(projectId);
|
||||
List<SysUserRole> userRole = sysUserRoleMapper.getUserRole();
|
||||
List<Long> userList = new ArrayList<>();
|
||||
for (SysUserRole sysUserRole : userRole) {
|
||||
String projectIds = sysUserRole.getProjectIds();
|
||||
if (projectIds!=null){
|
||||
String[] split = projectIds.split(",");
|
||||
for (String project : split) {
|
||||
if (project.equals(projectModelInfo.getProjectId().toString())){
|
||||
userList.add(sysUserRole.getUserId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
projectModelInfo.setUserIds(userList.toArray(new Long[userList.size()]));
|
||||
return projectModelInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getUserList() {
|
||||
return modelMappper.getUserList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新jsonFile
|
||||
* @param projectModelInfo
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int updateJsonFile(ProjectModelInfo projectModelInfo) {
|
||||
return modelMappper.updateJsonFile(projectModelInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试连接数据库
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult connectDataSource(Map map) {
|
||||
Properties info = new Properties();
|
||||
info.put("user" ,map.get("username"));
|
||||
info.put("password" ,map.get("password"));
|
||||
try {
|
||||
Class.forName(map.get("driverName").toString());
|
||||
System.out.println("驱动加载成功");
|
||||
}catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
return AjaxResult.error("驱动加载失败");
|
||||
}
|
||||
try {
|
||||
DriverManager.getConnection(map.get("url").toString(), info);
|
||||
return AjaxResult.success("数据库连接成功");
|
||||
}catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
return AjaxResult.error("数据库连接失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行ddl语句
|
||||
* @param map
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult executeSql(Map map) {
|
||||
Properties info = new Properties();
|
||||
info.put("user" ,map.get("username"));
|
||||
info.put("password" ,map.get("password"));
|
||||
try {
|
||||
Class.forName(map.get("driverName").toString());
|
||||
System.out.println("驱动加载成功");
|
||||
}catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
System.out.println("驱动加载失败");
|
||||
}
|
||||
try {
|
||||
Connection connection = DriverManager.getConnection(map.get("url").toString(), info);
|
||||
String[] tableTypes = {"TABLE"};
|
||||
ResultSet tablesResult = connection.getMetaData()
|
||||
.getTables(connection.getCatalog(), connection.getSchema(), null, tableTypes);
|
||||
while (tablesResult.next()) {
|
||||
return AjaxResult.error("该数据库已存在数据表,不能再次执行");
|
||||
}
|
||||
Statement statement = connection.createStatement();
|
||||
String[] sqls = map.get("sql").toString().split(";");
|
||||
for (String sql : sqls) {
|
||||
if (!sql.equals("\n\n") && !sql.equals("\n")) {
|
||||
statement.executeUpdate(sql);
|
||||
}
|
||||
}
|
||||
statement.close();
|
||||
tablesResult.close();
|
||||
connection.close();
|
||||
return AjaxResult.success("执行成功");
|
||||
}catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
e.printStackTrace();
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.salpa.online.service;
|
||||
|
||||
import com.salpa.common.core.domain.AjaxResult;
|
||||
import com.salpa.subject.domain.MonitorDataSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OnlineService {
|
||||
|
||||
List<MonitorDataSource> getDataSource();
|
||||
|
||||
AjaxResult connectDataSource(String databaseName);
|
||||
|
||||
AjaxResult testExecute(String databaseName, String script);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.salpa.online.service.impl;
|
||||
|
||||
import com.salpa.common.core.domain.AjaxResult;
|
||||
import com.salpa.online.service.OnlineService;
|
||||
import com.salpa.subject.domain.MonitorDataSource;
|
||||
import com.salpa.subject.mapper.DataSourcePropertyMapper;
|
||||
import com.salpa.subject.mapper.DatabaseMapper;
|
||||
import com.salpa.subject.service.ProjectService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class OnlineServiceImpl implements OnlineService {
|
||||
|
||||
@Autowired
|
||||
private DatabaseMapper databaseMapper;
|
||||
|
||||
@Autowired
|
||||
private ProjectService projectService;
|
||||
|
||||
@Autowired
|
||||
private DataSourcePropertyMapper dataSourcePropertyMapper;
|
||||
|
||||
/**
|
||||
* 获取数据源
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<MonitorDataSource> getDataSource() {
|
||||
List<MonitorDataSource> list = databaseMapper.selectDataSourceList();
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接数据库
|
||||
* @param databaseName
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult connectDataSource(String databaseName) {
|
||||
MonitorDataSource monitorDataSource = databaseMapper.selectByDatabaseName(databaseName);
|
||||
List<Map<String,Object>> properties = dataSourcePropertyMapper.selectPropertyBySourceId(monitorDataSource.getId());
|
||||
Connection connection = projectService.create(monitorDataSource, properties);
|
||||
List<String> tables = new ArrayList<>();
|
||||
if (connection == null) {
|
||||
return AjaxResult.error("连接失败");
|
||||
} else {
|
||||
try {
|
||||
String[] tableTypes = {"TABLE"};
|
||||
ResultSet tablesResult = connection.getMetaData()
|
||||
.getTables(databaseName, monitorDataSource.getSchemaName(), null, tableTypes);
|
||||
while (tablesResult.next()) {
|
||||
tables.add(tablesResult.getString("TABLE_NAME"));
|
||||
}
|
||||
tablesResult.close();//关闭tablesResult对象
|
||||
connection.close();//关闭Connection对象
|
||||
} catch (Exception throwAbles) {
|
||||
throwAbles.printStackTrace();
|
||||
return AjaxResult.error(throwAbles.getMessage());
|
||||
}
|
||||
}
|
||||
return AjaxResult.success(tables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql语句
|
||||
* @param databaseName
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult testExecute(String databaseName, String script) {
|
||||
Map<String, Map<String,Object>> columns = new LinkedHashMap();
|
||||
MonitorDataSource monitorDataSource = databaseMapper.selectByDatabaseName(databaseName);
|
||||
List<Map<String,Object>> properties = dataSourcePropertyMapper.selectPropertyBySourceId(monitorDataSource.getId());
|
||||
Map<String,Object> reslutMap = new LinkedHashMap<>();
|
||||
List<Map<String, Object>> rows = new ArrayList<>();
|
||||
try {
|
||||
Connection connection = projectService.create(monitorDataSource, properties);
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(script);
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("name",metaData.getColumnName(i+1));
|
||||
map.put("type",metaData.getColumnTypeName(i+1));
|
||||
columns.put(metaData.getColumnName(i+1),map);
|
||||
}
|
||||
while(resultSet.next()){
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
Object object = resultSet.getObject(metaData.getColumnLabel(i+1));
|
||||
if (metaData.getColumnTypeName(i+1).equals("DATETIME") || metaData.getColumnTypeName(i+1).equals("TIMESTAMP") || metaData.getColumnTypeName(i+1).equals("DATE")) {
|
||||
row.put(metaData.getColumnName(i+1),resultSet.getString(metaData.getColumnLabel(i+1)));
|
||||
} else {
|
||||
row.put(metaData.getColumnName(i+1),object);
|
||||
}
|
||||
}
|
||||
rows.add(row);
|
||||
}
|
||||
resultSet.close();//关闭ResultSet对象
|
||||
statement.close();//关闭Statement对象
|
||||
connection.close();//关闭Connection对象
|
||||
reslutMap.put("columns",columns);
|
||||
reslutMap.put("rows",rows);
|
||||
} catch (SQLException throwAbles) {
|
||||
throwAbles.printStackTrace();
|
||||
return AjaxResult.error(throwAbles.getMessage());
|
||||
}
|
||||
return AjaxResult.success(reslutMap);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据库表 monitor_data_source
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorDataSource {
|
||||
|
||||
/** id */
|
||||
private Integer id;
|
||||
|
||||
/** 项目id */
|
||||
private Integer projectId;
|
||||
|
||||
/** 数据库名称 */
|
||||
private String databaseName;
|
||||
|
||||
/** schema名称 */
|
||||
private String schemaName;
|
||||
|
||||
/** 数据库类型 */
|
||||
private String databaseType;
|
||||
|
||||
/** 数据库路径 */
|
||||
private String url;
|
||||
|
||||
/** 登录名 */
|
||||
private String username;
|
||||
|
||||
/** 密码 */
|
||||
private String password;
|
||||
|
||||
/** 修改时间 */
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
/** 连接参数 */
|
||||
private Map[] properties;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
public void setDatabaseName(String databaseName) {
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getDatabaseType() {
|
||||
return databaseType;
|
||||
}
|
||||
|
||||
public void setDatabaseType(String databaseType) {
|
||||
this.databaseType = databaseType;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Map[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map[] properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 数据库参数表 monitor_data_source_property
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorDataSourceProperty {
|
||||
|
||||
/** ID */
|
||||
private Integer id;
|
||||
|
||||
/** 数据库ID */
|
||||
private Integer dataSourceId;
|
||||
|
||||
/** key值 */
|
||||
private String dataSourceKey;
|
||||
|
||||
/** value值 */
|
||||
private String dataSourceValue;
|
||||
|
||||
/** 项目ID */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getDataSourceId() {
|
||||
return dataSourceId;
|
||||
}
|
||||
|
||||
public void setDataSourceId(Integer dataSourceId) {
|
||||
this.dataSourceId = dataSourceId;
|
||||
}
|
||||
|
||||
public String getDataSourceKey() {
|
||||
return dataSourceKey;
|
||||
}
|
||||
|
||||
public void setDataSourceKey(String dataSourceKey) {
|
||||
this.dataSourceKey = dataSourceKey;
|
||||
}
|
||||
|
||||
public String getDataSourceValue() {
|
||||
return dataSourceValue;
|
||||
}
|
||||
|
||||
public void setDataSourceValue(String dataSourceValue) {
|
||||
this.dataSourceValue = dataSourceValue;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据库文档表
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorDatabaseDocument {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer projectId;
|
||||
|
||||
private String databaseName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String productVersion;
|
||||
|
||||
private Long documentVersion;
|
||||
|
||||
private boolean archive;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
private List<MonitorTableDocument> tables;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
public void setDatabaseName(String databaseName) {
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName) {
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
public String getProductVersion() {
|
||||
return productVersion;
|
||||
}
|
||||
|
||||
public void setProductVersion(String productVersion) {
|
||||
this.productVersion = productVersion;
|
||||
}
|
||||
|
||||
public Long getDocumentVersion() {
|
||||
return documentVersion;
|
||||
}
|
||||
|
||||
public void setDocumentVersion(Long documentVersion) {
|
||||
this.documentVersion = documentVersion;
|
||||
}
|
||||
|
||||
public boolean isArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
public void setArchive(boolean archive) {
|
||||
this.archive = archive;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public List<MonitorTableDocument> getTables() {
|
||||
return tables;
|
||||
}
|
||||
|
||||
public void setTables(List<MonitorTableDocument> tables) {
|
||||
this.tables = tables;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 数据库类型表 monitor_database_type
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorDatabaseType {
|
||||
|
||||
/** id */
|
||||
private Integer id;
|
||||
|
||||
/** 数据库类型 */
|
||||
private String databaseType;
|
||||
|
||||
/** 图像 */
|
||||
private String icon;
|
||||
|
||||
/** 描述 */
|
||||
private String description;
|
||||
|
||||
/** jdbc文件网络地址 */
|
||||
private String jdbcDriverFileUrl;
|
||||
|
||||
/** jdbc文件路径 */
|
||||
private String jdbcDriverFilePath;
|
||||
|
||||
/** jdbc名称 */
|
||||
private String jdbcDriverClassName;
|
||||
|
||||
/** jdbcProtocol */
|
||||
private String jdbcProtocol;
|
||||
|
||||
/** urlPattern */
|
||||
private String urlPattern;
|
||||
|
||||
/** 删除标识 */
|
||||
private boolean deleted;
|
||||
|
||||
/** 删除token */
|
||||
private Integer deletedToken;
|
||||
|
||||
/** 修改时间 */
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
/*业务字段,项目数量*/
|
||||
private Integer projectCount;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getDatabaseType() {
|
||||
return databaseType;
|
||||
}
|
||||
|
||||
public void setDatabaseType(String databaseType) {
|
||||
this.databaseType = databaseType;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getJdbcDriverFileUrl() {
|
||||
return jdbcDriverFileUrl;
|
||||
}
|
||||
|
||||
public void setJdbcDriverFileUrl(String jdbcDriverFileUrl) {
|
||||
this.jdbcDriverFileUrl = jdbcDriverFileUrl;
|
||||
}
|
||||
|
||||
public String getJdbcDriverFilePath() {
|
||||
return jdbcDriverFilePath;
|
||||
}
|
||||
|
||||
public void setJdbcDriverFilePath(String jdbcDriverFilePath) {
|
||||
this.jdbcDriverFilePath = jdbcDriverFilePath;
|
||||
}
|
||||
|
||||
public String getJdbcDriverClassName() {
|
||||
return jdbcDriverClassName;
|
||||
}
|
||||
|
||||
public void setJdbcDriverClassName(String jdbcDriverClassName) {
|
||||
this.jdbcDriverClassName = jdbcDriverClassName;
|
||||
}
|
||||
|
||||
public String getJdbcProtocol() {
|
||||
return jdbcProtocol;
|
||||
}
|
||||
|
||||
public void setJdbcProtocol(String jdbcProtocol) {
|
||||
this.jdbcProtocol = jdbcProtocol;
|
||||
}
|
||||
|
||||
public String getUrlPattern() {
|
||||
return urlPattern;
|
||||
}
|
||||
|
||||
public void setUrlPattern(String urlPattern) {
|
||||
this.urlPattern = urlPattern;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public Integer getDeletedToken() {
|
||||
return deletedToken;
|
||||
}
|
||||
|
||||
public void setDeletedToken(Integer deletedToken) {
|
||||
this.deletedToken = deletedToken;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getProjectCount() {
|
||||
return projectCount;
|
||||
}
|
||||
|
||||
public void setProjectCount(Integer projectCount) {
|
||||
this.projectCount = projectCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
/**
|
||||
* 描述表 monitor_document_description
|
||||
* @author rhl
|
||||
*/
|
||||
|
||||
public class MonitorDocumentDescription {
|
||||
/** ID */
|
||||
private Integer id;
|
||||
/** 内容 */
|
||||
private String content;
|
||||
/** 项目ID */
|
||||
private Integer projectId;
|
||||
/** 表名 */
|
||||
private String tableName;
|
||||
/** 列表项 */
|
||||
private String columnName;
|
||||
/** 用户ID */
|
||||
private Long updateBy;
|
||||
/** 更新时间 */
|
||||
private LocalDateTime updateAt;
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
public Long getUpdateBy() {
|
||||
return updateBy;
|
||||
}
|
||||
|
||||
public void setUpdateBy(Long updateBy) {
|
||||
this.updateBy = updateBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 数据库表 monitor_document_discussion
|
||||
* @author hzl
|
||||
*/
|
||||
public class MonitorDocumentDiscussion {
|
||||
/** id */
|
||||
private Integer id;
|
||||
/** 评论内容content */
|
||||
private String content;
|
||||
/** 用户id user_id */
|
||||
private Long userId;
|
||||
/** 项目id project_id */
|
||||
private Integer projectId;
|
||||
/** 表名称 table_name */
|
||||
private String tableName;
|
||||
/** 列名称 column_name */
|
||||
private String columnName;
|
||||
/** 创建时间 create_at */
|
||||
/*时间格式化*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
/** 当前记录起始索引 */
|
||||
private Integer pageNum;
|
||||
|
||||
/** 每页显示记录数 */
|
||||
private Integer pageSize;
|
||||
/** 用户名称 */
|
||||
private String userName;
|
||||
/** 头像地址 */
|
||||
private String avatar;
|
||||
/** 登陆人 */
|
||||
private String loginUser;
|
||||
|
||||
public String getLoginUser() {
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
public void setLoginUser(String loginUser) {
|
||||
this.loginUser = loginUser;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.salpa.subject.domain.data.DocumentTemplatePropertyType;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* monitor_document_template_property 文档模板属性
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorDocumentTemplateProperty {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private DocumentTemplatePropertyType type;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public MonitorDocumentTemplateProperty() {}
|
||||
|
||||
public MonitorDocumentTemplateProperty(MonitorDocumentTemplateProperty value) {
|
||||
this.id = value.id;
|
||||
this.key = value.key;
|
||||
this.value = value.value;
|
||||
this.defaultValue = value.defaultValue;
|
||||
this.type = value.type;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorDocumentTemplateProperty(
|
||||
Integer id,
|
||||
String key,
|
||||
String value,
|
||||
String defaultValue,
|
||||
DocumentTemplatePropertyType type,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.defaultValue = defaultValue;
|
||||
this.type = type;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public DocumentTemplatePropertyType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(DocumentTemplatePropertyType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Builder;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 日志表 monitor_operation_log
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
@Builder
|
||||
public class MonitorOperationLog {
|
||||
|
||||
/*id*/
|
||||
private Long id;
|
||||
|
||||
/*用户id*/
|
||||
private Long operatorUserId;
|
||||
|
||||
/*用户名*/
|
||||
private String operatorUsername;
|
||||
|
||||
/*用户昵称*/
|
||||
private String operatorNickname;
|
||||
|
||||
/*所属模块*/
|
||||
private String operationModule;
|
||||
|
||||
/*方法名*/
|
||||
private String operationCode;
|
||||
|
||||
/*日志名称*/
|
||||
private String operationName;
|
||||
|
||||
/*结果*/
|
||||
private String operationResponse;
|
||||
|
||||
/*操作是否成功*/
|
||||
private boolean success;
|
||||
|
||||
/*涉及项目*/
|
||||
private Integer involvedProjectId;
|
||||
|
||||
/*创建时间*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getOperatorUserId() {
|
||||
return operatorUserId;
|
||||
}
|
||||
|
||||
public void setOperatorUserId(Long operatorUserId) {
|
||||
this.operatorUserId = operatorUserId;
|
||||
}
|
||||
|
||||
public String getOperatorUsername() {
|
||||
return operatorUsername;
|
||||
}
|
||||
|
||||
public void setOperatorUsername(String operatorUsername) {
|
||||
this.operatorUsername = operatorUsername;
|
||||
}
|
||||
|
||||
public String getOperatorNickname() {
|
||||
return operatorNickname;
|
||||
}
|
||||
|
||||
public void setOperatorNickname(String operatorNickname) {
|
||||
this.operatorNickname = operatorNickname;
|
||||
}
|
||||
|
||||
public String getOperationModule() {
|
||||
return operationModule;
|
||||
}
|
||||
|
||||
public void setOperationModule(String operationModule) {
|
||||
this.operationModule = operationModule;
|
||||
}
|
||||
|
||||
public String getOperationCode() {
|
||||
return operationCode;
|
||||
}
|
||||
|
||||
public void setOperationCode(String operationCode) {
|
||||
this.operationCode = operationCode;
|
||||
}
|
||||
|
||||
public String getOperationName() {
|
||||
return operationName;
|
||||
}
|
||||
|
||||
public void setOperationName(String operationName) {
|
||||
this.operationName = operationName;
|
||||
}
|
||||
|
||||
public String getOperationResponse() {
|
||||
return operationResponse;
|
||||
}
|
||||
|
||||
public void setOperationResponse(String operationResponse) {
|
||||
this.operationResponse = operationResponse;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public Integer getInvolvedProjectId() {
|
||||
return involvedProjectId;
|
||||
}
|
||||
|
||||
public void setInvolvedProjectId(Integer involvedProjectId) {
|
||||
this.involvedProjectId = involvedProjectId;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.salpa.subject.domain.vo.ProjectSyncRule;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 项目实体
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorProject implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 项目ID */
|
||||
private Integer id;
|
||||
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
|
||||
/** 项目名称 */
|
||||
private String projectDescription;
|
||||
|
||||
/** 主题id */
|
||||
private Integer subjectId;
|
||||
|
||||
/** 删除标识 */
|
||||
private boolean deleted;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
|
||||
/** 数据库 */
|
||||
private MonitorDataSource monitorDataSource;
|
||||
|
||||
/** 数据库高级设置 */
|
||||
private ProjectSyncRule projectSyncRule;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return projectName;
|
||||
}
|
||||
|
||||
public void setProjectName(String projectName) {
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
public String getProjectDescription() {
|
||||
return projectDescription;
|
||||
}
|
||||
|
||||
public void setProjectDescription(String projectDescription) {
|
||||
this.projectDescription = projectDescription;
|
||||
}
|
||||
|
||||
public Integer getSubjectId() {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public void setSubjectId(Integer subjectId) {
|
||||
this.subjectId = subjectId;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public MonitorDataSource getMonitorDataSource() {
|
||||
return monitorDataSource;
|
||||
}
|
||||
|
||||
public void setMonitorDataSource(MonitorDataSource monitorDataSource) {
|
||||
this.monitorDataSource = monitorDataSource;
|
||||
}
|
||||
|
||||
public ProjectSyncRule getProjectSyncRule() {
|
||||
return projectSyncRule;
|
||||
}
|
||||
|
||||
public void setProjectSyncRule(ProjectSyncRule projectSyncRule) {
|
||||
this.projectSyncRule = projectSyncRule;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 数据库配置表 monitor_project_sync_rule
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorProjectSyncRule implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** ID */
|
||||
private Integer id;
|
||||
|
||||
/** 项目ID */
|
||||
private Integer projectId;
|
||||
|
||||
/** 忽略表名称 */
|
||||
private String ignoreTableNameRegexArray;
|
||||
|
||||
/** 忽略字段名称 */
|
||||
private String ignoreColumnNameRegexArray;
|
||||
|
||||
/** 是否定时同步 */
|
||||
private boolean autoSync;
|
||||
|
||||
/** cron表达式 */
|
||||
private String autoSyncCron;
|
||||
|
||||
/** 修改时间 */
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public String getIgnoreTableNameRegexArray() {
|
||||
return ignoreTableNameRegexArray;
|
||||
}
|
||||
|
||||
public void setIgnoreTableNameRegexArray(String ignoreTableNameRegexArray) {
|
||||
this.ignoreTableNameRegexArray = ignoreTableNameRegexArray;
|
||||
}
|
||||
|
||||
public String getIgnoreColumnNameRegexArray() {
|
||||
return ignoreColumnNameRegexArray;
|
||||
}
|
||||
|
||||
public void setIgnoreColumnNameRegexArray(String ignoreColumnNameRegexArray) {
|
||||
this.ignoreColumnNameRegexArray = ignoreColumnNameRegexArray;
|
||||
}
|
||||
|
||||
public boolean isAutoSync() {
|
||||
return autoSync;
|
||||
}
|
||||
|
||||
public void setAutoSync(boolean autoSync) {
|
||||
this.autoSync = autoSync;
|
||||
}
|
||||
|
||||
public String getAutoSyncCron() {
|
||||
return autoSyncCron;
|
||||
}
|
||||
|
||||
public void setAutoSyncCron(String autoSyncCron) {
|
||||
this.autoSyncCron = autoSyncCron;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MonitorProjectSyncRule{" +
|
||||
"id=" + id +
|
||||
", projectId=" + projectId +
|
||||
", ignoreTableNameRegexArray='" + ignoreTableNameRegexArray + '\'' +
|
||||
", ignoreColumnNameRegexArray='" + ignoreColumnNameRegexArray + '\'' +
|
||||
", autoSync=" + autoSync +
|
||||
", autoSyncCron='" + autoSyncCron + '\'' +
|
||||
", updateAt=" + updateAt +
|
||||
", createAt=" + createAt +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 数据库配置表 monitor_project_sync_task
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorProjectSyncTask {
|
||||
|
||||
/** ID */
|
||||
private Integer id;
|
||||
|
||||
/** 项目ID */
|
||||
private Integer projectId;
|
||||
|
||||
/** 用户id */
|
||||
private Long userId;
|
||||
|
||||
/** 状态 */
|
||||
private String status;
|
||||
|
||||
/** 同步结果 */
|
||||
private String result;
|
||||
|
||||
/** 同步时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private Date runAt;
|
||||
|
||||
/** 修改时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getProjectId() {
|
||||
return projectId;
|
||||
}
|
||||
|
||||
public void setProjectId(Integer projectId) {
|
||||
this.projectId = projectId;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public Date getRunAt() {
|
||||
return runAt;
|
||||
}
|
||||
|
||||
public void setRunAt(Date runAt) {
|
||||
this.runAt = runAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateAt() {
|
||||
return updateAt;
|
||||
}
|
||||
|
||||
public void setUpdateAt(LocalDateTime updateAt) {
|
||||
this.updateAt = updateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 主题管理表 monitor_subject
|
||||
*
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorSubject implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** ID */
|
||||
private Integer id;
|
||||
|
||||
/** 主题名称 */
|
||||
private String subjectName;
|
||||
|
||||
/** 主题描述 */
|
||||
private String subjectDescription;
|
||||
|
||||
/** 删除标识 */
|
||||
private boolean deleted;
|
||||
|
||||
/** 创建时间 */
|
||||
private LocalDateTime createAt;
|
||||
|
||||
/** 形目数量 */
|
||||
private Integer projectCount;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getSubjectName() {
|
||||
return subjectName;
|
||||
}
|
||||
|
||||
public void setSubjectName(String subjectName) {
|
||||
this.subjectName = subjectName;
|
||||
}
|
||||
|
||||
public String getSubjectDescription() {
|
||||
return subjectDescription;
|
||||
}
|
||||
|
||||
public void setSubjectDescription(String subjectDescription) {
|
||||
this.subjectDescription = subjectDescription;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getProjectCount() {
|
||||
return projectCount;
|
||||
}
|
||||
|
||||
public void setProjectCount(Integer projectCount) {
|
||||
this.projectCount = projectCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* monitor_table_column_document
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorTableColumnDocument implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer dataType;
|
||||
|
||||
private String comment;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private Integer size;
|
||||
|
||||
private Integer decimalDigits;
|
||||
|
||||
private Boolean primaryKey;
|
||||
|
||||
private String nullable;
|
||||
|
||||
private String autoIncrement;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public MonitorTableColumnDocument() {}
|
||||
|
||||
public MonitorTableColumnDocument(MonitorTableColumnDocument value) {
|
||||
this.id = value.id;
|
||||
this.tableDocumentId = value.tableDocumentId;
|
||||
this.databaseDocumentId = value.databaseDocumentId;
|
||||
this.name = value.name;
|
||||
this.type = value.type;
|
||||
this.dataType = value.dataType;
|
||||
this.comment = value.comment;
|
||||
this.defaultValue = value.defaultValue;
|
||||
this.size = value.size;
|
||||
this.decimalDigits = value.decimalDigits;
|
||||
this.primaryKey = value.primaryKey;
|
||||
this.nullable = value.nullable;
|
||||
this.autoIncrement = value.autoIncrement;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorTableColumnDocument(
|
||||
Integer id,
|
||||
Integer tableDocumentId,
|
||||
Integer databaseDocumentId,
|
||||
String name,
|
||||
String type,
|
||||
Integer dataType,
|
||||
String comment,
|
||||
String defaultValue,
|
||||
Integer size,
|
||||
Integer decimalDigits,
|
||||
Boolean primaryKey,
|
||||
String nullable,
|
||||
String autoIncrement,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.dataType = dataType;
|
||||
this.comment = comment;
|
||||
this.defaultValue = defaultValue;
|
||||
this.size = size;
|
||||
this.decimalDigits = decimalDigits;
|
||||
this.primaryKey = primaryKey;
|
||||
this.nullable = nullable;
|
||||
this.autoIncrement = autoIncrement;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getTableDocumentId() {
|
||||
return tableDocumentId;
|
||||
}
|
||||
|
||||
public void setTableDocumentId(Integer tableDocumentId) {
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
}
|
||||
|
||||
public Integer getDatabaseDocumentId() {
|
||||
return databaseDocumentId;
|
||||
}
|
||||
|
||||
public void setDatabaseDocumentId(Integer databaseDocumentId) {
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Integer getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public void setDataType(Integer dataType) {
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Integer getDecimalDigits() {
|
||||
return decimalDigits;
|
||||
}
|
||||
|
||||
public void setDecimalDigits(Integer decimalDigits) {
|
||||
this.decimalDigits = decimalDigits;
|
||||
}
|
||||
|
||||
public Boolean getPrimaryKey() {
|
||||
return primaryKey;
|
||||
}
|
||||
|
||||
public void setPrimaryKey(Boolean primaryKey) {
|
||||
this.primaryKey = primaryKey;
|
||||
}
|
||||
|
||||
public String getNullable() {
|
||||
return nullable;
|
||||
}
|
||||
|
||||
public void setNullable(String nullable) {
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
public String getAutoIncrement() {
|
||||
return autoIncrement;
|
||||
}
|
||||
|
||||
public void setAutoIncrement(String autoIncrement) {
|
||||
this.autoIncrement = autoIncrement;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MonitorTableDocument {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String comment;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public MonitorTableDocument() {};
|
||||
|
||||
public MonitorTableDocument(MonitorTableDocument value) {
|
||||
this.id = value.id;
|
||||
this.databaseDocumentId = value.databaseDocumentId;
|
||||
this.name = value.name;
|
||||
this.type = value.type;
|
||||
this.comment = value.comment;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorTableDocument(
|
||||
Integer id,
|
||||
Integer databaseDocumentId,
|
||||
String name,
|
||||
String type,
|
||||
String comment,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.comment = comment;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
/*描述*/
|
||||
private String description;
|
||||
|
||||
/*评论条数*/
|
||||
private Integer discussionCount;
|
||||
|
||||
private List<MonitorTableColumnDocument> columns;
|
||||
|
||||
private List<MonitorTableIndexDocument> indexes;
|
||||
|
||||
private List<MonitorTableForeignKeyDocument> foreignKeys;
|
||||
|
||||
private List<MonitorTableTriggerDocument> triggers;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getDatabaseDocumentId() {
|
||||
return databaseDocumentId;
|
||||
}
|
||||
|
||||
public void setDatabaseDocumentId(Integer databaseDocumentId) {
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Integer getDiscussionCount() {
|
||||
return discussionCount;
|
||||
}
|
||||
|
||||
public void setDiscussionCount(Integer discussionCount) {
|
||||
this.discussionCount = discussionCount;
|
||||
}
|
||||
|
||||
public List<MonitorTableColumnDocument> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(List<MonitorTableColumnDocument> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public List<MonitorTableIndexDocument> getIndexes() {
|
||||
return indexes;
|
||||
}
|
||||
|
||||
public void setIndexes(List<MonitorTableIndexDocument> indexes) {
|
||||
this.indexes = indexes;
|
||||
}
|
||||
|
||||
public List<MonitorTableForeignKeyDocument> getForeignKeys() {
|
||||
return foreignKeys;
|
||||
}
|
||||
|
||||
public void setForeignKeys(List<MonitorTableForeignKeyDocument> foreignKeys) {
|
||||
this.foreignKeys = foreignKeys;
|
||||
}
|
||||
|
||||
public List<MonitorTableTriggerDocument> getTriggers() {
|
||||
return triggers;
|
||||
}
|
||||
|
||||
public void setTriggers(List<MonitorTableTriggerDocument> triggers) {
|
||||
this.triggers = triggers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("TableDocument (");
|
||||
|
||||
sb.append(id);
|
||||
sb.append(", ").append(databaseDocumentId);
|
||||
sb.append(", ").append(name);
|
||||
sb.append(", ").append(type);
|
||||
sb.append(", ").append(comment);
|
||||
sb.append(", ").append(createAt);
|
||||
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* monitor_table_foreign_key_document
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorTableForeignKeyDocument implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private Integer keySeq;
|
||||
|
||||
private String fkName;
|
||||
|
||||
private String fkTableName;
|
||||
|
||||
private String fkColumnName;
|
||||
|
||||
private String pkName;
|
||||
|
||||
private String pkTableName;
|
||||
|
||||
private String pkColumnName;
|
||||
|
||||
private String updateRule;
|
||||
|
||||
private String deleteRule;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public MonitorTableForeignKeyDocument() {}
|
||||
|
||||
public MonitorTableForeignKeyDocument(MonitorTableForeignKeyDocument value) {
|
||||
this.id = value.id;
|
||||
this.tableDocumentId = value.tableDocumentId;
|
||||
this.databaseDocumentId = value.databaseDocumentId;
|
||||
this.keySeq = value.keySeq;
|
||||
this.fkName = value.fkName;
|
||||
this.fkTableName = value.fkTableName;
|
||||
this.fkColumnName = value.fkColumnName;
|
||||
this.pkName = value.pkName;
|
||||
this.pkTableName = value.pkTableName;
|
||||
this.pkColumnName = value.pkColumnName;
|
||||
this.updateRule = value.updateRule;
|
||||
this.deleteRule = value.deleteRule;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorTableForeignKeyDocument(
|
||||
Integer id,
|
||||
Integer tableDocumentId,
|
||||
Integer databaseDocumentId,
|
||||
Integer keySeq,
|
||||
String fkName,
|
||||
String fkTableName,
|
||||
String fkColumnName,
|
||||
String pkName,
|
||||
String pkTableName,
|
||||
String pkColumnName,
|
||||
String updateRule,
|
||||
String deleteRule,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
this.keySeq = keySeq;
|
||||
this.fkName = fkName;
|
||||
this.fkTableName = fkTableName;
|
||||
this.fkColumnName = fkColumnName;
|
||||
this.pkName = pkName;
|
||||
this.pkTableName = pkTableName;
|
||||
this.pkColumnName = pkColumnName;
|
||||
this.updateRule = updateRule;
|
||||
this.deleteRule = deleteRule;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getTableDocumentId() {
|
||||
return tableDocumentId;
|
||||
}
|
||||
|
||||
public void setTableDocumentId(Integer tableDocumentId) {
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
}
|
||||
|
||||
public Integer getDatabaseDocumentId() {
|
||||
return databaseDocumentId;
|
||||
}
|
||||
|
||||
public void setDatabaseDocumentId(Integer databaseDocumentId) {
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
}
|
||||
|
||||
public Integer getKeySeq() {
|
||||
return keySeq;
|
||||
}
|
||||
|
||||
public void setKeySeq(Integer keySeq) {
|
||||
this.keySeq = keySeq;
|
||||
}
|
||||
|
||||
public String getFkName() {
|
||||
return fkName;
|
||||
}
|
||||
|
||||
public void setFkName(String fkName) {
|
||||
this.fkName = fkName;
|
||||
}
|
||||
|
||||
public String getFkTableName() {
|
||||
return fkTableName;
|
||||
}
|
||||
|
||||
public void setFkTableName(String fkTableName) {
|
||||
this.fkTableName = fkTableName;
|
||||
}
|
||||
|
||||
public String getFkColumnName() {
|
||||
return fkColumnName;
|
||||
}
|
||||
|
||||
public void setFkColumnName(String fkColumnName) {
|
||||
this.fkColumnName = fkColumnName;
|
||||
}
|
||||
|
||||
public String getPkName() {
|
||||
return pkName;
|
||||
}
|
||||
|
||||
public void setPkName(String pkName) {
|
||||
this.pkName = pkName;
|
||||
}
|
||||
|
||||
public String getPkTableName() {
|
||||
return pkTableName;
|
||||
}
|
||||
|
||||
public void setPkTableName(String pkTableName) {
|
||||
this.pkTableName = pkTableName;
|
||||
}
|
||||
|
||||
public String getPkColumnName() {
|
||||
return pkColumnName;
|
||||
}
|
||||
|
||||
public void setPkColumnName(String pkColumnName) {
|
||||
this.pkColumnName = pkColumnName;
|
||||
}
|
||||
|
||||
public String getUpdateRule() {
|
||||
return updateRule;
|
||||
}
|
||||
|
||||
public void setUpdateRule(String updateRule) {
|
||||
this.updateRule = updateRule;
|
||||
}
|
||||
|
||||
public String getDeleteRule() {
|
||||
return deleteRule;
|
||||
}
|
||||
|
||||
public void setDeleteRule(String deleteRule) {
|
||||
this.deleteRule = deleteRule;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* @author zhuff
|
||||
* monitor_table_index_document
|
||||
*/
|
||||
public class MonitorTableIndexDocument implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private Boolean unique;
|
||||
|
||||
private String columnNameArray;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
/*业务字段*/
|
||||
private Object columnNameArrays;
|
||||
|
||||
public MonitorTableIndexDocument() {}
|
||||
|
||||
public MonitorTableIndexDocument(MonitorTableIndexDocument value) {
|
||||
this.id = value.id;
|
||||
this.tableDocumentId = value.tableDocumentId;
|
||||
this.databaseDocumentId = value.databaseDocumentId;
|
||||
this.name = value.name;
|
||||
this.unique = value.unique;
|
||||
this.columnNameArray = value.columnNameArray;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorTableIndexDocument(
|
||||
Integer id,
|
||||
Integer tableDocumentId,
|
||||
Integer databaseDocumentId,
|
||||
String name,
|
||||
Boolean unique,
|
||||
String columnNameArray,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
this.name = name;
|
||||
this.unique = unique;
|
||||
this.columnNameArray = columnNameArray;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getTableDocumentId() {
|
||||
return tableDocumentId;
|
||||
}
|
||||
|
||||
public void setTableDocumentId(Integer tableDocumentId) {
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
}
|
||||
|
||||
public Integer getDatabaseDocumentId() {
|
||||
return databaseDocumentId;
|
||||
}
|
||||
|
||||
public void setDatabaseDocumentId(Integer databaseDocumentId) {
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Boolean getUnique() {
|
||||
return unique;
|
||||
}
|
||||
|
||||
public void setUnique(Boolean unique) {
|
||||
this.unique = unique;
|
||||
}
|
||||
|
||||
public String getColumnNameArray() {
|
||||
return columnNameArray;
|
||||
}
|
||||
|
||||
public void setColumnNameArray(String columnNameArray) {
|
||||
this.columnNameArray = columnNameArray;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Object getColumnNameArrays() {
|
||||
return columnNameArrays;
|
||||
}
|
||||
|
||||
public void setColumnNameArrays(Object columnNameArrays) {
|
||||
this.columnNameArrays = columnNameArrays;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* monitor_table_trigger_document
|
||||
* @author zhuff
|
||||
*/
|
||||
public class MonitorTableTriggerDocument implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String timing;
|
||||
|
||||
private String manipulation;
|
||||
|
||||
private String statement;
|
||||
|
||||
private String triggerCreateAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
public MonitorTableTriggerDocument() {}
|
||||
|
||||
public MonitorTableTriggerDocument(MonitorTableTriggerDocument value) {
|
||||
this.id = value.id;
|
||||
this.name = value.name;
|
||||
this.tableDocumentId = value.tableDocumentId;
|
||||
this.databaseDocumentId = value.databaseDocumentId;
|
||||
this.timing = value.timing;
|
||||
this.manipulation = value.manipulation;
|
||||
this.statement = value.statement;
|
||||
this.triggerCreateAt = value.triggerCreateAt;
|
||||
this.createAt = value.createAt;
|
||||
}
|
||||
|
||||
public MonitorTableTriggerDocument(
|
||||
Integer id,
|
||||
String name,
|
||||
Integer tableDocumentId,
|
||||
Integer databaseDocumentId,
|
||||
String timing,
|
||||
String manipulation,
|
||||
String statement,
|
||||
String triggerCreateAt,
|
||||
LocalDateTime createAt
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
this.timing = timing;
|
||||
this.manipulation = manipulation;
|
||||
this.statement = statement;
|
||||
this.triggerCreateAt = triggerCreateAt;
|
||||
this.createAt = createAt;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getTableDocumentId() {
|
||||
return tableDocumentId;
|
||||
}
|
||||
|
||||
public void setTableDocumentId(Integer tableDocumentId) {
|
||||
this.tableDocumentId = tableDocumentId;
|
||||
}
|
||||
|
||||
public Integer getDatabaseDocumentId() {
|
||||
return databaseDocumentId;
|
||||
}
|
||||
|
||||
public void setDatabaseDocumentId(Integer databaseDocumentId) {
|
||||
this.databaseDocumentId = databaseDocumentId;
|
||||
}
|
||||
|
||||
public String getTiming() {
|
||||
return timing;
|
||||
}
|
||||
|
||||
public void setTiming(String timing) {
|
||||
this.timing = timing;
|
||||
}
|
||||
|
||||
public String getManipulation() {
|
||||
return manipulation;
|
||||
}
|
||||
|
||||
public void setManipulation(String manipulation) {
|
||||
this.manipulation = manipulation;
|
||||
}
|
||||
|
||||
public String getStatement() {
|
||||
return statement;
|
||||
}
|
||||
|
||||
public void setStatement(String statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
public String getTriggerCreateAt() {
|
||||
return triggerCreateAt;
|
||||
}
|
||||
|
||||
public void setTriggerCreateAt(String triggerCreateAt) {
|
||||
this.triggerCreateAt = triggerCreateAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateAt() {
|
||||
return createAt;
|
||||
}
|
||||
|
||||
public void setCreateAt(LocalDateTime createAt) {
|
||||
this.createAt = createAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.salpa.subject.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 数据库类型表 monitor_waening
|
||||
*
|
||||
* @author zff
|
||||
*/
|
||||
@Data
|
||||
public class MonitorWarning {
|
||||
|
||||
/** ID */
|
||||
private Integer id;
|
||||
|
||||
/** 告警名称 */
|
||||
private String warningName;
|
||||
|
||||
/** 所属主题模型 */
|
||||
private String warningSubject;
|
||||
|
||||
/** 所属数据库 */
|
||||
private String warningDataSource;
|
||||
|
||||
/** 告警时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date warningTime;
|
||||
|
||||
/** 告警内容 */
|
||||
private String warningContent;
|
||||
|
||||
/** 告警状态 */
|
||||
private Integer warningStatus;
|
||||
|
||||
/** 告警处理人 */
|
||||
private String handlingUser;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.salpa.subject.domain.converter;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.salpa.common.core.domain.JsonData;
|
||||
import com.salpa.subject.domain.data.DatabaseDocumentResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class JsonConverter {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public List<String> fromJson(String data) {
|
||||
if (data == null) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
return Arrays.asList(data.split(","));
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject toJson(List<String> array) {
|
||||
String json = objToJson(array);
|
||||
return JSONObject.parseObject(json);
|
||||
}
|
||||
|
||||
public JSONObject toJson(DatabaseDocumentResponse response) {
|
||||
String json = objToJson(response);
|
||||
return JSONObject.parseObject(json);
|
||||
}
|
||||
|
||||
public JSONObject toJson(JsonData<Object> data) {
|
||||
String json = objToJson(data);
|
||||
return JSONObject.parseObject(json);
|
||||
}
|
||||
|
||||
public DatabaseDocumentResponse of(JSONObject json) {
|
||||
try {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
return objectMapper.readValue(json.toString().getBytes(StandardCharsets.UTF_8), DatabaseDocumentResponse.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonData toJsonData(JSONObject json) {
|
||||
try {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
return objectMapper.readValue(json.toString().getBytes(StandardCharsets.UTF_8), JsonData.class);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject objToJsonData(Object obj) {
|
||||
String json = objToJson(obj);
|
||||
return JSONObject.parseObject(json);
|
||||
}
|
||||
|
||||
private String objToJson(Object obj) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ColumnMeta {
|
||||
|
||||
private String name;
|
||||
|
||||
private String comment;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer dataType;
|
||||
|
||||
/**
|
||||
* if default value is empty string, will be converted to ''.
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
private Integer size;
|
||||
|
||||
private Integer decimalDigits;
|
||||
|
||||
private String nullable;
|
||||
|
||||
private String autoIncrement;
|
||||
|
||||
private Boolean isPrimaryKey;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DatabaseDocumentResponse {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String databaseName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String productVersion;
|
||||
|
||||
private Integer documentVersion;
|
||||
|
||||
@Builder.Default
|
||||
private List<TableDocumentResponse> tables = new ArrayList<>();
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.salpa.subject.domain.MonitorTableColumnDocument;
|
||||
import com.salpa.subject.domain.diff.DiffAble;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DatabaseDocumentSimpleResponse {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String projectName;
|
||||
|
||||
private String databaseName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String productVersion;
|
||||
|
||||
private Long documentVersion;
|
||||
|
||||
private List<TableData> tables = new ArrayList<>();
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT +8")
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
@Data
|
||||
public static class TableData implements DiffAble<TableData> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String comment;
|
||||
|
||||
private List<MonitorTableColumnDocument> columns = new ArrayList<>();
|
||||
|
||||
private Integer discussionCount;
|
||||
|
||||
private String description;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private TableData original;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DatabaseMeta {
|
||||
|
||||
/**
|
||||
* product_name
|
||||
*/
|
||||
private String productName;
|
||||
|
||||
/**
|
||||
* product_version
|
||||
*/
|
||||
private String productVersion;
|
||||
|
||||
/**
|
||||
* driver_name
|
||||
*/
|
||||
private String driverName;
|
||||
|
||||
/**
|
||||
* driver_version
|
||||
*/
|
||||
private String driverVersion;
|
||||
|
||||
/**
|
||||
* database_name
|
||||
*/
|
||||
private String databaseName;
|
||||
|
||||
/**
|
||||
* schema_name
|
||||
*/
|
||||
private String schemaName;
|
||||
|
||||
@Builder.Default
|
||||
private List<TableMeta> tables = Collections.emptyList();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import com.salpa.subject.domain.provider.MetaProviders;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
import com.salpa.subject.domain.render.Render;
|
||||
import com.salpa.subject.domain.render.RenderConfig;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class Databasir {
|
||||
|
||||
private final DatabasirConfig config;
|
||||
|
||||
public Optional<DatabaseMeta> get(Connection connection, String databaseName, String schemaName) {
|
||||
// pre compile regex
|
||||
List<Pattern> ignoreTableColumnPatterns = config.getIgnoreTableColumnNameRegex().stream()
|
||||
.map(Pattern::compile)
|
||||
.collect(Collectors.toList());
|
||||
List<Pattern> ignoreTableNamePatterns = config.getIgnoreTableNameRegex().stream()
|
||||
.map(Pattern::compile)
|
||||
.collect(Collectors.toList());
|
||||
Condition condition = Condition.builder()
|
||||
.databaseName(databaseName)
|
||||
.schemaName(schemaName)
|
||||
.ignoreTableNamePatterns(ignoreTableNamePatterns)
|
||||
.ignoreTableColumnNamePatterns(ignoreTableColumnPatterns)
|
||||
.build();
|
||||
return MetaProviders
|
||||
.of(connection)
|
||||
.select(connection, condition);
|
||||
}
|
||||
|
||||
public void renderAsMarkdown(DatabaseMeta meta, OutputStream out) throws IOException {
|
||||
renderAsMarkdown(new RenderConfig(), meta, out);
|
||||
}
|
||||
|
||||
public void renderAsMarkdown(RenderConfig config, DatabaseMeta meta, OutputStream stream) throws IOException {
|
||||
Render.markdownRender(config).rendering(meta, stream);
|
||||
}
|
||||
|
||||
public static Databasir of() {
|
||||
return of(new DatabasirConfig());
|
||||
}
|
||||
|
||||
public static Databasir of(DatabasirConfig config) {
|
||||
return new Databasir(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DatabasirConfig {
|
||||
|
||||
private Collection<String> ignoreTableNameRegex = new HashSet<>();
|
||||
|
||||
private Collection<String> ignoreTableColumnNameRegex = new HashSet<>();
|
||||
|
||||
public DatabasirConfig ignoreTable(String tableNameRegex) {
|
||||
ignoreTableNameRegex.add(tableNameRegex);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DatabasirConfig ignoreColumn(String columnNameRegex) {
|
||||
ignoreTableColumnNameRegex.add(columnNameRegex);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DocumentTemplatePropertiesResponse {
|
||||
|
||||
@Builder.Default
|
||||
private List<DocumentTemplatePropertyResponse> tableFieldNameProperties = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<DocumentTemplatePropertyResponse> columnFieldNameProperties = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<DocumentTemplatePropertyResponse> indexFieldNameProperties = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<DocumentTemplatePropertyResponse> triggerFieldNameProperties = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<DocumentTemplatePropertyResponse> foreignKeyFieldNameProperties = Collections.emptyList();
|
||||
|
||||
@Data
|
||||
public static class DocumentTemplatePropertyResponse {
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private DocumentTemplatePropertyType type;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
public enum DocumentTemplatePropertyType {
|
||||
|
||||
TABLE_FIELD_NAME, INDEX_FIELD_NAME, COLUMN_FIELD_NAME, TRIGGER_FIELD_NAME, FOREIGN_KEY_FIELD_NAME;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.RootDiff;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DocumentUpdated {
|
||||
|
||||
private RootDiff diff;
|
||||
|
||||
private Long newVersion;
|
||||
|
||||
private Long oldVersion;
|
||||
|
||||
private Integer projectId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
public Optional<Long> getOldVersion() {
|
||||
return Optional.ofNullable(oldVersion);
|
||||
}
|
||||
|
||||
public Optional<RootDiff> getDiff() {
|
||||
return Optional.ofNullable(diff);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ForeignKeyMeta {
|
||||
|
||||
private Integer keySeq;
|
||||
|
||||
/**
|
||||
* may null
|
||||
*/
|
||||
private String pkName;
|
||||
|
||||
private String pkTableName;
|
||||
|
||||
private String pkColumnName;
|
||||
|
||||
/**
|
||||
* may null
|
||||
*/
|
||||
private String fkName;
|
||||
|
||||
private String fkTableName;
|
||||
|
||||
private String fkColumnName;
|
||||
|
||||
/**
|
||||
* NO_ACTION \ CASCADE \ SET_NULL \ SET_DEFAULT
|
||||
*/
|
||||
private String updateRule;
|
||||
|
||||
/**
|
||||
* NO_ACTION \ CASCADE \ SET_NULL \ SET_DEFAULT
|
||||
*/
|
||||
private String deleteRule;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IndexMeta {
|
||||
|
||||
private String name;
|
||||
|
||||
@Builder.Default
|
||||
private List<String> columnNames = Collections.emptyList();
|
||||
|
||||
private Boolean isUniqueKey;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
public enum ProjectSyncTaskStatus {
|
||||
|
||||
NEW,
|
||||
RUNNING,
|
||||
FINISHED,
|
||||
FAILED,
|
||||
CANCELED
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.diff.DiffAble;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class TableDocumentResponse {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String comment;
|
||||
|
||||
private Integer discussionCount;
|
||||
|
||||
private String description;
|
||||
|
||||
@Builder.Default
|
||||
private List<ColumnDocumentResponse> columns = new ArrayList<>();
|
||||
|
||||
@Builder.Default
|
||||
private List<IndexDocumentResponse> indexes = new ArrayList<>();
|
||||
|
||||
@Builder.Default
|
||||
private List<ForeignKeyDocumentResponse> foreignKeys = new ArrayList<>();
|
||||
|
||||
@Builder.Default
|
||||
private List<TriggerDocumentResponse> triggers = new ArrayList<>();
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private TableDocumentResponse original;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class ColumnDocumentResponse implements DiffAble<ColumnDocumentResponse> {
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer size;
|
||||
|
||||
private Integer decimalDigits;
|
||||
|
||||
private String comment;
|
||||
|
||||
private String description;
|
||||
|
||||
private Boolean isPrimaryKey;
|
||||
|
||||
private String nullable;
|
||||
|
||||
private String autoIncrement;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private Integer discussionCount;
|
||||
|
||||
private ColumnDocumentResponse original;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class IndexDocumentResponse implements DiffAble<IndexDocumentResponse> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Boolean isUnique;
|
||||
|
||||
@Builder.Default
|
||||
private List<String> columnNames = new ArrayList<>();
|
||||
|
||||
private String columnNameArray;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private IndexDocumentResponse original;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class ForeignKeyDocumentResponse implements DiffAble<ForeignKeyDocumentResponse> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String fkName;
|
||||
|
||||
private String fkTableName;
|
||||
|
||||
private String fkColumnName;
|
||||
|
||||
private Integer keySeq;
|
||||
|
||||
private String pkName;
|
||||
|
||||
private String pkTableName;
|
||||
|
||||
private String pkColumnName;
|
||||
|
||||
private String updateRule;
|
||||
|
||||
private String deleteRule;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private ForeignKeyDocumentResponse original;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class TriggerDocumentResponse implements DiffAble<TriggerDocumentResponse> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String timing;
|
||||
|
||||
private String manipulation;
|
||||
|
||||
private String statement;
|
||||
|
||||
private String triggerCreateAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private TriggerDocumentResponse original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TableMeta {
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String comment;
|
||||
|
||||
@Builder.Default
|
||||
private List<ColumnMeta> columns = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<TriggerMeta> triggers = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<IndexMeta> indexes = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<ForeignKeyMeta> foreignKeys = Collections.emptyList();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.salpa.subject.domain.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* now: only support mysql, postgresql.
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TriggerMeta {
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* example: BEFORE, AFTER
|
||||
*/
|
||||
private String timing;
|
||||
|
||||
/**
|
||||
* example: INSERT, UPDATE
|
||||
*/
|
||||
private String manipulation;
|
||||
|
||||
private String statement;
|
||||
|
||||
private String createAt;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BaseTypeFieldEqualFunction implements BiFunction<Object, Object, Boolean> {
|
||||
|
||||
private final List<String> ignoreFields;
|
||||
|
||||
@Override
|
||||
public Boolean apply(Object that, Object other) {
|
||||
if (Objects.equals(that, other)) {
|
||||
return true;
|
||||
}
|
||||
if (that == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
BeanInfo thatBean = Introspector.getBeanInfo(that.getClass());
|
||||
BeanInfo otherBean = Introspector.getBeanInfo(other.getClass());
|
||||
Map<String, PropertyDescriptor> otherBeanPropertyMap = Arrays.stream(otherBean.getPropertyDescriptors())
|
||||
.collect(Collectors.toMap(PropertyDescriptor::getName, p -> p));
|
||||
for (PropertyDescriptor thatProperty : thatBean.getPropertyDescriptors()) {
|
||||
if (thatProperty.getReadMethod() == null || thatProperty.getWriteMethod() == null) {
|
||||
continue;
|
||||
}
|
||||
if (ignoreFields.contains(thatProperty.getName())) {
|
||||
continue;
|
||||
}
|
||||
if (!otherBeanPropertyMap.containsKey(thatProperty.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (Collection.class.isAssignableFrom(thatProperty.getPropertyType())) {
|
||||
Collection thatValue = (Collection) thatProperty.getReadMethod().invoke(that);
|
||||
Collection otherValue = (Collection) otherBeanPropertyMap.get(thatProperty.getName())
|
||||
.getReadMethod().invoke(other);
|
||||
return handleCollection(thatValue, otherValue);
|
||||
}
|
||||
if (!thatProperty.getPropertyType().isPrimitive()) {
|
||||
Object thatValue = thatProperty.getReadMethod().invoke(that);
|
||||
Object otherValue = otherBeanPropertyMap.get(thatProperty.getName()).getReadMethod().invoke(other);
|
||||
if (!apply(thatValue, otherValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Object thatValue = thatProperty.getReadMethod().invoke(that);
|
||||
Object otherValue = otherBeanPropertyMap.get(thatProperty.getName()).getReadMethod().invoke(other);
|
||||
if (!Objects.equals(thatValue, otherValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
|
||||
log.error("Error comparing objects", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleCollection(Collection<Object> that, Collection<Object> other) {
|
||||
if (that.size() != other.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Object thatObj : that) {
|
||||
boolean anyMatch = other.stream().anyMatch(otherObj -> this.apply(thatObj, otherObj));
|
||||
if (!anyMatch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class ColumnDocDiff implements DiffAble<ColumnDocDiff> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer dataType;
|
||||
|
||||
private String comment;
|
||||
|
||||
private String defaultValue;
|
||||
|
||||
private Integer size;
|
||||
|
||||
private Integer decimalDigits;
|
||||
|
||||
private Boolean isPrimaryKey;
|
||||
|
||||
private String nullable;
|
||||
|
||||
private String autoIncrement;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private ColumnDocDiff original;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class DatabaseDocDiff {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer projectId;
|
||||
|
||||
private String databaseName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String productName;
|
||||
|
||||
private String productVersion;
|
||||
|
||||
private Long version;
|
||||
|
||||
private List<TableDocDiff> tables = Collections.emptyList();
|
||||
|
||||
private LocalDateTime updateAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
|
||||
public interface DiffAble<T> {
|
||||
|
||||
void setDiffType(DiffType diffType);
|
||||
|
||||
void setOriginal(T t);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseDocumentSimpleResponse;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DiffTypePredictor {
|
||||
|
||||
public static DiffType predict(List<DatabaseDocumentSimpleResponse.TableData> result) {
|
||||
long changedItemSize = result.stream()
|
||||
.filter(item -> !item.getDiffType().isNone())
|
||||
.count();
|
||||
long addedItemSize = result.stream()
|
||||
.filter(item -> !item.getDiffType().isNone())
|
||||
.filter(item -> item.getDiffType().isAdded())
|
||||
.count();
|
||||
long removedItemSize = result.stream()
|
||||
.filter(item -> !item.getDiffType().isNone())
|
||||
.filter(item -> item.getDiffType().isRemoved())
|
||||
.count();
|
||||
if (changedItemSize > 0 && addedItemSize == changedItemSize) {
|
||||
return DiffType.ADDED;
|
||||
} else if (changedItemSize > 0 && removedItemSize == changedItemSize) {
|
||||
return DiffType.REMOVED;
|
||||
} else {
|
||||
return result.stream()
|
||||
.anyMatch(t -> t.getDiffType() != DiffType.NONE) ? DiffType.MODIFIED : DiffType.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseMeta;
|
||||
import com.salpa.subject.domain.diff.data.RootDiff;
|
||||
import com.salpa.subject.domain.diff.processor.DatabaseDiffProcessor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class Diffs {
|
||||
|
||||
private static final DatabaseDiffProcessor databaseDiffProcessor = new DatabaseDiffProcessor();
|
||||
|
||||
public static RootDiff diff(DatabaseMeta original, DatabaseMeta current) {
|
||||
return databaseDiffProcessor.process(original, current);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DocumentDiffChecker {
|
||||
|
||||
private static final List<String> IGNORE_FIELDS = List.of(
|
||||
"id",
|
||||
"class",
|
||||
"tableDocumentId",
|
||||
"databaseDocumentId",
|
||||
"createAt",
|
||||
"updateAt",
|
||||
"diffType",
|
||||
"original"
|
||||
);
|
||||
|
||||
public List<TableDocDiff> diff(List<TableDocDiff> original, List<TableDocDiff> current) {
|
||||
Map<String, TableDocDiff> originalTablesMap = toMap(original, TableDocDiff::getName);
|
||||
Map<String, TableDocDiff> currentTablesMap = toMap(current, TableDocDiff::getName);
|
||||
// added items
|
||||
var added = added(originalTablesMap, currentTablesMap)
|
||||
.stream()
|
||||
.map(curr -> {
|
||||
List<ColumnDocDiff> columnDiffs =
|
||||
doDiff(Collections.emptyList(), curr.getColumns(), ColumnDocDiff::getName);
|
||||
columnDiffs.sort(Comparator.comparingInt(c -> c.getId()));
|
||||
List<IndexDocDiff> indexDiffs =
|
||||
doDiff(Collections.emptyList(), curr.getIndexes(), IndexDocDiff::getName);
|
||||
List<TriggerDocDiff> triggerDiffs =
|
||||
doDiff(Collections.emptyList(), curr.getTriggers(), TriggerDocDiff::getName);
|
||||
List<ForeignKeyDocDiff> fkDiffs =
|
||||
doDiff(Collections.emptyList(),
|
||||
curr.getForeignKeys(),
|
||||
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
|
||||
return TableDocDiff.builder()
|
||||
.id(curr.getId())
|
||||
.diffType(DiffType.ADDED)
|
||||
.name(curr.getName())
|
||||
.comment(curr.getComment())
|
||||
.type(curr.getType())
|
||||
.createAt(curr.getCreateAt())
|
||||
.columns(columnDiffs)
|
||||
.indexes(indexDiffs)
|
||||
.triggers(triggerDiffs)
|
||||
.foreignKeys(fkDiffs)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
// removed items
|
||||
var removed = removed(originalTablesMap, currentTablesMap)
|
||||
.stream()
|
||||
.map(old -> {
|
||||
List<ColumnDocDiff> columnDiffs =
|
||||
doDiff(old.getColumns(), Collections.emptyList(), ColumnDocDiff::getName);
|
||||
columnDiffs.sort(Comparator.comparingInt(c -> c.getId()));
|
||||
List<IndexDocDiff> indexDiffs =
|
||||
doDiff(old.getIndexes(), Collections.emptyList(), IndexDocDiff::getName);
|
||||
List<TriggerDocDiff> triggerDiffs =
|
||||
doDiff(old.getTriggers(), Collections.emptyList(), TriggerDocDiff::getName);
|
||||
List<ForeignKeyDocDiff> fkDiffs =
|
||||
doDiff(old.getForeignKeys(),
|
||||
Collections.emptyList(),
|
||||
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
|
||||
return TableDocDiff.builder()
|
||||
.id(old.getId())
|
||||
.diffType(DiffType.REMOVED)
|
||||
.name(old.getName())
|
||||
.comment(old.getComment())
|
||||
.type(old.getType())
|
||||
.createAt(old.getCreateAt())
|
||||
.columns(columnDiffs)
|
||||
.indexes(indexDiffs)
|
||||
.triggers(triggerDiffs)
|
||||
.foreignKeys(fkDiffs)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
// unchanged or modified items
|
||||
List<TableDocDiff> sameOrModified = currentTablesMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> originalTablesMap.containsKey(entry.getKey()))
|
||||
.map(entry -> {
|
||||
String tableName = entry.getKey();
|
||||
TableDocDiff currentTable = entry.getValue();
|
||||
TableDocDiff originalTable = originalTablesMap.get(tableName);
|
||||
|
||||
List<ColumnDocDiff> columnDiffs =
|
||||
doDiff(originalTable.getColumns(), currentTable.getColumns(), ColumnDocDiff::getName);
|
||||
columnDiffs.sort(Comparator.comparingInt(c -> c.getId()));
|
||||
List<IndexDocDiff> indexDiffs =
|
||||
doDiff(originalTable.getIndexes(), currentTable.getIndexes(), IndexDocDiff::getName);
|
||||
List<TriggerDocDiff> triggerDiffs =
|
||||
doDiff(originalTable.getTriggers(), currentTable.getTriggers(), TriggerDocDiff::getName);
|
||||
List<ForeignKeyDocDiff> fkDiffs =
|
||||
doDiff(originalTable.getForeignKeys(),
|
||||
currentTable.getForeignKeys(),
|
||||
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
|
||||
|
||||
BaseTypeFieldEqualFunction eq = new BaseTypeFieldEqualFunction(IGNORE_FIELDS);
|
||||
DiffType diffType = eq.apply(currentTable, originalTable) ? DiffType.NONE : DiffType.MODIFIED;
|
||||
// workaround for diffType = NONE
|
||||
if (diffType == DiffType.NONE) {
|
||||
originalTable = null;
|
||||
}
|
||||
return TableDocDiff.builder()
|
||||
.id(currentTable.getId())
|
||||
.diffType(diffType)
|
||||
.original(originalTable)
|
||||
.name(currentTable.getName())
|
||||
.comment(currentTable.getComment())
|
||||
.type(currentTable.getType())
|
||||
.createAt(currentTable.getCreateAt())
|
||||
.columns(columnDiffs)
|
||||
.indexes(indexDiffs)
|
||||
.triggers(triggerDiffs)
|
||||
.foreignKeys(fkDiffs)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<TableDocDiff> all = new ArrayList<>(16);
|
||||
all.addAll(sameOrModified);
|
||||
all.addAll(added);
|
||||
all.addAll(removed);
|
||||
return all;
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> doDiff(List<T> original, List<T> current, Function<T, String> idMapping) {
|
||||
Map<String, T> originalMap = toMap(original, idMapping);
|
||||
Map<String, T> currentMap = toMap(current, idMapping);
|
||||
List<T> added = added(originalMap, currentMap);
|
||||
List<T> removed = removed(originalMap, currentMap);
|
||||
List<T> modified = modified(originalMap, currentMap);
|
||||
List<T> same = same(originalMap, currentMap);
|
||||
List<T> results = new ArrayList<>();
|
||||
results.addAll(same);
|
||||
results.addAll(added);
|
||||
results.addAll(modified);
|
||||
results.addAll(removed);
|
||||
return results;
|
||||
}
|
||||
|
||||
private <T> Map<String, T> toMap(List<T> content, Function<T, String> idMapping) {
|
||||
return content
|
||||
.stream()
|
||||
.collect(Collectors.toMap(idMapping, Function.identity(), (a, b) -> {
|
||||
log.warn("Duplicate key, origin = {}, current = {}", a, b);
|
||||
return a;
|
||||
}));
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> added(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
return currentMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !originalMapById.containsKey(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.map(value -> {
|
||||
value.setDiffType(DiffType.ADDED);
|
||||
return value;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> removed(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
return originalMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !currentMapById.containsKey(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.map(value -> {
|
||||
value.setDiffType(DiffType.REMOVED);
|
||||
return value;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> modified(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
BaseTypeFieldEqualFunction eq = new BaseTypeFieldEqualFunction(IGNORE_FIELDS);
|
||||
return modified(originalMapById, currentMapById, eq);
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> modified(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById,
|
||||
BiFunction<Object, Object, Boolean> sameFunction) {
|
||||
return currentMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> originalMapById.containsKey(entry.getKey()))
|
||||
.filter(entry -> !sameFunction.apply(entry.getValue(), originalMapById.get(entry.getKey())))
|
||||
.map(entry -> {
|
||||
T value = entry.getValue();
|
||||
value.setDiffType(DiffType.MODIFIED);
|
||||
value.setOriginal(originalMapById.get(entry.getKey()));
|
||||
return value;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> same(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
BaseTypeFieldEqualFunction eq = new BaseTypeFieldEqualFunction(IGNORE_FIELDS);
|
||||
return same(originalMapById, currentMapById, eq);
|
||||
}
|
||||
|
||||
private <T extends DiffAble<T>> List<T> same(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById,
|
||||
BiFunction<Object, Object, Boolean> sameFunction) {
|
||||
return currentMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> originalMapById.containsKey(entry.getKey()))
|
||||
.filter(entry -> sameFunction.apply(entry.getValue(), originalMapById.get(entry.getKey())))
|
||||
.map(entry -> {
|
||||
T value = entry.getValue();
|
||||
value.setDiffType(DiffType.NONE);
|
||||
return value;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class ForeignKeyDocDiff implements DiffAble<ForeignKeyDocDiff> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private Integer keySeq;
|
||||
|
||||
private String fkName;
|
||||
|
||||
private String fkTableName;
|
||||
|
||||
private String fkColumnName;
|
||||
|
||||
private String pkName;
|
||||
|
||||
private String pkTableName;
|
||||
|
||||
private String pkColumnName;
|
||||
|
||||
private String updateRule;
|
||||
|
||||
private String deleteRule;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private ForeignKeyDocDiff original;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class IndexDocDiff implements DiffAble<IndexDocDiff> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private Boolean isUnique;
|
||||
|
||||
private String columnNameArray;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private IndexDocDiff original;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class TableDocDiff implements DiffAble<TableDocDiff> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String comment;
|
||||
|
||||
@Builder.Default
|
||||
private List<ColumnDocDiff> columns = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<IndexDocDiff> indexes = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<TriggerDocDiff> triggers = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
private List<ForeignKeyDocDiff> foreignKeys = Collections.emptyList();
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private TableDocDiff original;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.salpa.subject.domain.diff;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class TriggerDocDiff implements DiffAble<TriggerDocDiff> {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer tableDocumentId;
|
||||
|
||||
private Integer databaseDocumentId;
|
||||
|
||||
private String timing;
|
||||
|
||||
private String manipulation;
|
||||
|
||||
private String statement;
|
||||
|
||||
private String triggerCreateAt;
|
||||
|
||||
private LocalDateTime createAt;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private TriggerDocDiff original;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.salpa.subject.domain.diff.data;
|
||||
|
||||
public interface Diff {
|
||||
|
||||
DiffType getDiffType();
|
||||
|
||||
Object getOriginal();
|
||||
|
||||
Object getCurrent();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.salpa.subject.domain.diff.data;
|
||||
|
||||
public enum DiffType {
|
||||
NONE, ADDED, REMOVED, MODIFIED;
|
||||
|
||||
public static boolean isModified(DiffType type) {
|
||||
return type != null && type != NONE;
|
||||
}
|
||||
|
||||
public boolean isAdded() {
|
||||
return this == ADDED;
|
||||
}
|
||||
|
||||
public boolean isRemoved() {
|
||||
return this == REMOVED;
|
||||
}
|
||||
|
||||
public boolean isNone() {
|
||||
return this == NONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.salpa.subject.domain.diff.data;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class FieldDiff implements Diff {
|
||||
|
||||
private String fieldName;
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private Object original;
|
||||
|
||||
private Object current;
|
||||
|
||||
@Builder.Default
|
||||
private List<FieldDiff> fields = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.salpa.subject.domain.diff.data;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RootDiff {
|
||||
|
||||
private DiffType diffType;
|
||||
|
||||
private List<FieldDiff> fields = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ColumnDiffProcessor implements DiffProcessor<ColumnMeta> {
|
||||
|
||||
@Override
|
||||
public FieldDiff process(String fieldName, List<ColumnMeta> original, List<ColumnMeta> current) {
|
||||
return diffTableField(original, current, fieldName, ColumnMeta::getName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseMeta;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
import com.salpa.subject.domain.diff.data.RootDiff;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public class DatabaseDiffProcessor {
|
||||
|
||||
private final TableDiffProcessor tableDiffProcessor = new TableDiffProcessor();
|
||||
|
||||
private static final DatabaseMeta EMPTY = DatabaseMeta.builder().build();
|
||||
|
||||
public RootDiff process(DatabaseMeta original, DatabaseMeta current) {
|
||||
DiffType diffType = null;
|
||||
if (original == null && current != null) {
|
||||
diffType = DiffType.ADDED;
|
||||
}
|
||||
if (original != null && current == null) {
|
||||
diffType = DiffType.REMOVED;
|
||||
}
|
||||
List<FieldDiff> fields = diffDatabaseFields(
|
||||
Objects.requireNonNullElse(original, EMPTY),
|
||||
Objects.requireNonNullElse(current, EMPTY)
|
||||
);
|
||||
boolean isModified = fields.stream().anyMatch(f -> DiffType.isModified(f.getDiffType()));
|
||||
if (diffType == null) {
|
||||
diffType = isModified ? DiffType.MODIFIED : DiffType.NONE;
|
||||
}
|
||||
RootDiff diff = new RootDiff();
|
||||
diff.setFields(fields);
|
||||
diff.setDiffType(diffType);
|
||||
return diff;
|
||||
}
|
||||
|
||||
private List<FieldDiff> diffDatabaseFields(DatabaseMeta original, DatabaseMeta current) {
|
||||
Class<DatabaseMeta> clazz = DatabaseMeta.class;
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
List<FieldDiff> diffs = new ArrayList<>(32);
|
||||
// ignore tables diff
|
||||
Arrays.stream(fields)
|
||||
.filter(field -> !Objects.equals(field.getName(), "tables"))
|
||||
.forEach(field -> {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object originalValue = original == null ? null : field.get(original);
|
||||
Object currentValue = current == null ? null : field.get(current);
|
||||
if (!Objects.equals(originalValue, currentValue)) {
|
||||
DiffType diffType;
|
||||
if (originalValue == null) {
|
||||
diffType = DiffType.ADDED;
|
||||
} else if (currentValue == null) {
|
||||
diffType = DiffType.REMOVED;
|
||||
} else {
|
||||
diffType = DiffType.MODIFIED;
|
||||
}
|
||||
diffs.add(FieldDiff.builder()
|
||||
.diffType(diffType)
|
||||
.fieldName(field.getName())
|
||||
.original(originalValue)
|
||||
.current(currentValue)
|
||||
.build());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
log.error("diff field failed", e);
|
||||
}
|
||||
});
|
||||
|
||||
FieldDiff tablesField = tableDiffProcessor.process("tables", original.getTables(), current.getTables());
|
||||
diffs.add(tablesField);
|
||||
return diffs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface DiffProcessor<T> {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(DiffProcessor.class);
|
||||
|
||||
FieldDiff process(String fieldName, List<T> original, List<T> current);
|
||||
|
||||
default FieldDiff diffTableField(List<T> original,
|
||||
List<T> current,
|
||||
String fieldName,
|
||||
Function<T, String> identity) {
|
||||
Map<String, T> originalMap = toMap(original, identity);
|
||||
Map<String, T> currentMap = toMap(current, identity);
|
||||
List<FieldDiff> columnFieldDiffs = new ArrayList<>(32);
|
||||
// removed
|
||||
List<FieldDiff> removedFields = originalRemovedField(originalMap, currentMap);
|
||||
columnFieldDiffs.addAll(removedFields);
|
||||
// added
|
||||
List<FieldDiff> addedFields = currentAddedField(originalMap, currentMap);
|
||||
columnFieldDiffs.addAll(addedFields);
|
||||
// modified
|
||||
List<FieldDiff> modifiedFields = modifiedField(originalMap, currentMap);
|
||||
columnFieldDiffs.addAll(modifiedFields);
|
||||
return FieldDiff.builder()
|
||||
.fieldName(fieldName)
|
||||
.diffType(columnFieldDiffs.isEmpty() ? DiffType.NONE : DiffType.MODIFIED)
|
||||
.fields(columnFieldDiffs)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
default Map<String, T> toMap(List<T> content, Function<T, String> idMapping) {
|
||||
return content
|
||||
.stream()
|
||||
.collect(Collectors.toMap(idMapping, Function.identity(), (a, b) -> {
|
||||
log.warn("Duplicate key, origin = {}, current = {}", a, b);
|
||||
return a;
|
||||
}));
|
||||
}
|
||||
|
||||
default List<FieldDiff> originalRemovedField(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
return originalMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !currentMapById.containsKey(entry.getKey()))
|
||||
.map(entry -> FieldDiff.builder()
|
||||
.fieldName(entry.getKey())
|
||||
.original(entry.getValue())
|
||||
.diffType(DiffType.REMOVED)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default List<FieldDiff> currentAddedField(Map<String, T> originalMapById,
|
||||
Map<String, T> currentMapById) {
|
||||
return currentMapById.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !originalMapById.containsKey(entry.getKey()))
|
||||
.map(entry -> FieldDiff.builder()
|
||||
.fieldName(entry.getKey())
|
||||
.current(entry.getValue())
|
||||
.diffType(DiffType.ADDED)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default List<FieldDiff> modifiedField(Map<String, T> original,
|
||||
Map<String, T> current) {
|
||||
List<FieldDiff> diff = new ArrayList<>();
|
||||
original.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> current.containsKey(entry.getKey()))
|
||||
.forEach(entry -> {
|
||||
T originalValue = entry.getValue();
|
||||
T currentValue = current.get(entry.getKey());
|
||||
if (!Objects.equals(originalValue, currentValue)) {
|
||||
FieldDiff fieldDiff = FieldDiff.builder()
|
||||
.fieldName(entry.getKey())
|
||||
.original(originalValue)
|
||||
.current(currentValue)
|
||||
.diffType(DiffType.MODIFIED)
|
||||
.build();
|
||||
diff.add(fieldDiff);
|
||||
}
|
||||
});
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.ForeignKeyMeta;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ForeignKeyDiffProcessor implements DiffProcessor<ForeignKeyMeta> {
|
||||
|
||||
@Override
|
||||
public FieldDiff process(String fieldName, List<ForeignKeyMeta> original, List<ForeignKeyMeta> current) {
|
||||
return diffTableField(
|
||||
original,
|
||||
current,
|
||||
"foreignKeys",
|
||||
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.IndexMeta;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class IndexDiffProcessor implements DiffProcessor<IndexMeta> {
|
||||
|
||||
@Override
|
||||
public FieldDiff process(String fieldName, List<IndexMeta> original, List<IndexMeta> current) {
|
||||
return diffTableField(original, current, fieldName, IndexMeta::getName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
import com.salpa.subject.domain.data.TableMeta;
|
||||
import com.salpa.subject.domain.diff.data.DiffType;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class TableDiffProcessor implements DiffProcessor<TableMeta> {
|
||||
|
||||
private final IndexDiffProcessor indexDiffProcessor = new IndexDiffProcessor();
|
||||
|
||||
private final ColumnDiffProcessor columnDiffProcessor = new ColumnDiffProcessor();
|
||||
|
||||
private final TriggerDiffProcessor triggerDiffProcessor = new TriggerDiffProcessor();
|
||||
|
||||
private final ForeignKeyDiffProcessor foreignKeyDiffProcessor = new ForeignKeyDiffProcessor();
|
||||
|
||||
private static final TableMeta EMPTY = new TableMeta();
|
||||
|
||||
@Override
|
||||
public FieldDiff process(String fieldName, List<TableMeta> original, List<TableMeta> current) {
|
||||
// diff tables field
|
||||
Map<String, TableMeta> originalMap = toMap(original, TableMeta::getName);
|
||||
Map<String, TableMeta> currentMap = toMap(current, TableMeta::getName);
|
||||
List<FieldDiff> tables = new ArrayList<>();
|
||||
List<TableMeta> added = added(originalMap, currentMap);
|
||||
List<TableMeta> removed = removed(originalMap, currentMap);
|
||||
// added
|
||||
List<FieldDiff> addedFields = added.stream()
|
||||
.map(table -> diffTableField(EMPTY, table))
|
||||
.collect(Collectors.toList());
|
||||
tables.addAll(addedFields);
|
||||
// removed
|
||||
List<FieldDiff> removedFields = removed.stream()
|
||||
.map(table -> diffTableField(table, EMPTY))
|
||||
.collect(Collectors.toList());
|
||||
tables.addAll(removedFields);
|
||||
// modified
|
||||
List<FieldDiff> modified = originalMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> currentMap.containsKey(entry.getKey()))
|
||||
.filter(entry -> !Objects.equals(entry.getValue(), currentMap.get(entry.getKey())))
|
||||
.map(entry -> {
|
||||
TableMeta originalValue = entry.getValue();
|
||||
TableMeta currentValue = currentMap.get(entry.getKey());
|
||||
return diffTableField(originalValue, currentValue);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
tables.addAll(modified);
|
||||
DiffType tablesDiffType;
|
||||
if (!modified.isEmpty()) {
|
||||
tablesDiffType = DiffType.MODIFIED;
|
||||
} else if (!addedFields.isEmpty()) {
|
||||
tablesDiffType = DiffType.ADDED;
|
||||
} else if (!removedFields.isEmpty()) {
|
||||
tablesDiffType = DiffType.REMOVED;
|
||||
} else {
|
||||
tablesDiffType = DiffType.NONE;
|
||||
}
|
||||
FieldDiff tablesField = FieldDiff.builder()
|
||||
.diffType(tablesDiffType)
|
||||
.fieldName(fieldName)
|
||||
.fields(tables)
|
||||
.build();
|
||||
return tablesField;
|
||||
}
|
||||
|
||||
private List<TableMeta> added(Map<String, TableMeta> originalMap,
|
||||
Map<String, TableMeta> currentMap) {
|
||||
return currentMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !originalMap.containsKey(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<TableMeta> removed(Map<String, TableMeta> originalMap,
|
||||
Map<String, TableMeta> currentMap) {
|
||||
return originalMap.entrySet()
|
||||
.stream()
|
||||
.filter(entry -> !currentMap.containsKey(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private FieldDiff diffTableField(TableMeta original, TableMeta current) {
|
||||
FieldDiff columns =
|
||||
columnDiffProcessor.process("columns", original.getColumns(), current.getColumns());
|
||||
FieldDiff indexes =
|
||||
indexDiffProcessor.process("indexes", original.getIndexes(), current.getIndexes());
|
||||
FieldDiff triggers =
|
||||
triggerDiffProcessor.process("triggers", original.getTriggers(), current.getTriggers());
|
||||
FieldDiff foreignKeys =
|
||||
foreignKeyDiffProcessor.process("foreignKeys", original.getForeignKeys(), current.getForeignKeys());
|
||||
List<FieldDiff> otherFields = fields(original, current);
|
||||
|
||||
List<FieldDiff> fields = new ArrayList<>();
|
||||
fields.add(columns);
|
||||
fields.add(indexes);
|
||||
fields.add(foreignKeys);
|
||||
fields.add(triggers);
|
||||
fields.addAll(otherFields);
|
||||
DiffType diffType;
|
||||
if (original == EMPTY) {
|
||||
diffType = DiffType.ADDED;
|
||||
} else if (current == EMPTY) {
|
||||
diffType = DiffType.REMOVED;
|
||||
} else {
|
||||
diffType = DiffType.MODIFIED;
|
||||
}
|
||||
return FieldDiff.builder()
|
||||
.diffType(diffType)
|
||||
.fieldName(original == EMPTY ? current.getName() : original.getName())
|
||||
.original(current == EMPTY ? original : null)
|
||||
.current(original == EMPTY ? current : null)
|
||||
.fields(fields)
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<FieldDiff> fields(TableMeta original, TableMeta current) {
|
||||
List<FieldDiff> fields = new ArrayList<>();
|
||||
// ignore tables diff
|
||||
Class<TableMeta> clazz = TableMeta.class;
|
||||
List<String> ignoredFields = List.of("columns", "indexes", "triggers", "foreignKeys");
|
||||
Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(field -> !ignoredFields.contains(field.getName()))
|
||||
.forEach(field -> {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object originalValue = original == null ? null : field.get(original);
|
||||
Object currentValue = current == null ? null : field.get(current);
|
||||
if (!Objects.equals(originalValue, currentValue)) {
|
||||
DiffType diffType;
|
||||
if (originalValue == null) {
|
||||
diffType = DiffType.ADDED;
|
||||
} else if (currentValue == null) {
|
||||
diffType = DiffType.REMOVED;
|
||||
} else {
|
||||
diffType = DiffType.MODIFIED;
|
||||
}
|
||||
fields.add(FieldDiff.builder()
|
||||
.diffType(diffType)
|
||||
.fieldName(field.getName())
|
||||
.original(originalValue)
|
||||
.current(currentValue)
|
||||
.build());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
log.error("diff field failed", e);
|
||||
}
|
||||
});
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.salpa.subject.domain.diff.processor;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.TriggerMeta;
|
||||
import com.salpa.subject.domain.diff.data.FieldDiff;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TriggerDiffProcessor implements DiffProcessor<TriggerMeta> {
|
||||
|
||||
@Override
|
||||
public FieldDiff process(String fieldName, List<TriggerMeta> original, List<TriggerMeta> current) {
|
||||
return diffTableField(original, current, fieldName, TriggerMeta::getName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.salpa.subject.domain.error;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum DomainErrors implements MetaopsErrors {
|
||||
|
||||
REFRESH_TOKEN_EXPIRED("X_0001", "refresh token expired"),
|
||||
INVALID_REFRESH_TOKEN_OPERATION("X_0002", "invalid refresh token operation"),
|
||||
NETWORK_ERROR("X_0003", "网络似乎不稳定,请稍后再试"),
|
||||
INVALID_ACCESS_TOKEN("X_0004", "无效的 access token"),
|
||||
|
||||
NOT_SUPPORT_DATABASE_TYPE("A_10000", "不支持的数据库类型, 请检查项目配置"),
|
||||
PROJECT_NOT_FOUND("A_10001", "项目不存在"),
|
||||
DATABASE_META_NOT_FOUND("A_10002", "获取数据库信息失败"),
|
||||
CONNECT_DATABASE_FAILED("A_10003", "连接数据库失败,请检查连接配置"),
|
||||
GROUP_OWNER_MUST_NOT_BE_EMPTY("A_10004", "请至少指定一个分组组长"),
|
||||
PASSWORD_MUST_NOT_BE_BLANK("A_10005", "密码不能为空"),
|
||||
USERNAME_OR_EMAIL_DUPLICATE("A_10006", "用户名或邮箱已存在"),
|
||||
USER_ROLE_DUPLICATE("A_10007", "用户角色已存在"),
|
||||
PROJECT_NAME_DUPLICATE("A_10008", "项目名称已被占用"),
|
||||
CANNOT_UPDATE_SELF_ROLE("A_10009", "无法对自己执行角色变更的操作"),
|
||||
UPDATE_PASSWORD_CONFIRM_FAILED("A_10010", "两次密码输入不一致"),
|
||||
ORIGIN_PASSWORD_NOT_CORRECT("A_10011", "原密码不正确"),
|
||||
INVALID_CRON_EXPRESSION("A_10012", "不合法的 cron 表达式"),
|
||||
REGISTRATION_ID_DUPLICATE("A_10013", "应用注册 ID 不能重复"),
|
||||
REGISTRATION_ID_NOT_FOUND("A_10014", "应用 ID 不存在"),
|
||||
MISS_REQUIRED_PARAMETERS("A_10015", "缺少必填参数"),
|
||||
DATABASE_TYPE_NAME_DUPLICATE("A_10016", "数据库类型名已存在"),
|
||||
MUST_NOT_MODIFY_SYSTEM_DEFAULT_DATABASE_TYPE("A_10017", "禁止修改系统默认数据库类型"),
|
||||
DOWNLOAD_DRIVER_ERROR("A_10018", "驱动下载失败"),
|
||||
INVALID_DATABASE_TYPE_URL_PATTERN("A_10019", "不合法的 url pattern"),
|
||||
DOCUMENT_VERSION_IS_INVALID("A_10020", "文档版本不合法"),
|
||||
CANNOT_UPDATE_SELF_ENABLED_STATUS("A_10021", "无法对自己执行启用禁用操作"),
|
||||
MOCK_DATA_SCRIPT_MUST_NOT_BE_BLANK("A_10022", "脚本内容不能为空"),
|
||||
TABLE_META_NOT_FOUND("A_10023", "不存在的数据库表"),
|
||||
DEPENDENT_COLUMN_NAME_MUST_NOT_BE_BLANK("A_10024", "必须指定依赖的字段"),
|
||||
DEPENDENT_REF_MUST_NOT_BE_BLANK("A_10025", "请选择关联表和字段"),
|
||||
MUST_NOT_REF_SELF("A_10026", "不能引用自身"),
|
||||
CIRCLE_REFERENCE("A_10027", "检查到循环引用"),
|
||||
DUPLICATE_COLUMN("A_10028", "重复的列"),
|
||||
INVALID_MOCK_DATA_SCRIPT("A_10029", "不合法的表达式"),
|
||||
CANNOT_DELETE_SELF("A_10030", "无法对自己执行删除账号操作"),
|
||||
DRIVER_CLASS_NOT_FOUND("A_10031", "获取驱动类名失败"),
|
||||
DATABASE_DOCUMENT_DUPLICATE_KEY("A_10032", "文档版本重复"),
|
||||
UPLOAD_DRIVER_FILE_ERROR("A_10033", "上传失败,请检查后重新上传"),
|
||||
DRIVER_URL_AND_PATH_MUST_NOT_BE_ALL_BLANK("A_10034", "请填写下载驱动的地址或手动上传驱动文件"),
|
||||
LOAD_DRIVER_FAILED("A_10045", "驱动加载失败,请检查后重试")
|
||||
;
|
||||
|
||||
private final String errCode;
|
||||
|
||||
private final String errMessage;
|
||||
|
||||
public MetaopsException exception() {
|
||||
return new MetaopsException(this);
|
||||
}
|
||||
|
||||
public MetaopsException exception(Throwable origin) {
|
||||
return new MetaopsException(this, origin);
|
||||
}
|
||||
|
||||
public MetaopsException exception(String message, Throwable origin) {
|
||||
return new MetaopsException(this, message, origin);
|
||||
}
|
||||
|
||||
public MetaopsException exception(String s) {
|
||||
return exception(s, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.salpa.subject.domain.error;
|
||||
|
||||
public interface MetaopsErrors {
|
||||
|
||||
String getErrCode();
|
||||
|
||||
String getErrMessage();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.salpa.subject.domain.error;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class MetaopsException extends RuntimeException {
|
||||
|
||||
@Getter
|
||||
private MetaopsErrors errorCodeMessage;
|
||||
|
||||
@Getter
|
||||
private String errCode;
|
||||
|
||||
@Getter
|
||||
private String errMessage;
|
||||
|
||||
/**
|
||||
* @param errorCodeMessage 错误信息
|
||||
*/
|
||||
public MetaopsException(MetaopsErrors errorCodeMessage) {
|
||||
super(errorCodeMessage.getErrMessage());
|
||||
this.errorCodeMessage = errorCodeMessage;
|
||||
this.errCode = errorCodeMessage.getErrCode();
|
||||
this.errMessage = errorCodeMessage.getErrMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param errorCodeMessage 错误信息
|
||||
* @param overrideMessage 覆盖 message
|
||||
*/
|
||||
public MetaopsException(MetaopsErrors errorCodeMessage, String overrideMessage) {
|
||||
super(overrideMessage);
|
||||
this.errorCodeMessage = errorCodeMessage;
|
||||
this.errCode = errorCodeMessage.getErrCode();
|
||||
this.errMessage = overrideMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param errorCodeMessage 错误信息
|
||||
* @param cause root cause
|
||||
*/
|
||||
public MetaopsException(MetaopsErrors errorCodeMessage, Throwable cause) {
|
||||
super(errorCodeMessage.getErrMessage(), cause);
|
||||
this.errorCodeMessage = errorCodeMessage;
|
||||
this.errCode = errorCodeMessage.getErrCode();
|
||||
this.errMessage = errorCodeMessage.getErrMessage();
|
||||
}
|
||||
|
||||
public MetaopsException(MetaopsErrors errorCodeMessage, String overrideMessage, Throwable cause) {
|
||||
super(overrideMessage, cause);
|
||||
this.errorCodeMessage = errorCodeMessage;
|
||||
this.errCode = errorCodeMessage.getErrCode();
|
||||
this.errMessage = overrideMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.salpa.subject.domain.generator;
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseDocumentResponse;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
@Component
|
||||
public interface DocumentFileGenerator {
|
||||
|
||||
boolean support(DocumentFileType type);
|
||||
|
||||
void generate(DocumentFileGenerateContext context, OutputStream outputStream);
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
class DocumentFileGenerateContext {
|
||||
|
||||
@NonNull
|
||||
private DocumentFileType documentFileType;
|
||||
|
||||
@NonNull
|
||||
private DatabaseDocumentResponse databaseDocument;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.salpa.subject.domain.generator;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum DocumentFileType {
|
||||
|
||||
MARKDOWN("md", "Markdown"),
|
||||
|
||||
PLANT_UML_ER_SVG("svg", "UML SVG"),
|
||||
|
||||
PLANT_UML_ER_PNG("png", "UML PNG"),
|
||||
|
||||
WORD("docx", "Word"),
|
||||
;
|
||||
|
||||
private String fileExtension;
|
||||
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package com.salpa.subject.domain.generator;
|
||||
|
||||
import com.salpa.common.exception.SystemException;
|
||||
import com.salpa.common.utils.StringUtils;
|
||||
import com.salpa.subject.domain.data.DatabaseDocumentResponse;
|
||||
import com.salpa.subject.domain.data.DocumentTemplatePropertiesResponse;
|
||||
import com.salpa.subject.domain.data.TableDocumentResponse;
|
||||
import com.salpa.subject.domain.render.markdown.MarkdownBuilder;
|
||||
import com.salpa.subject.service.DocumentTemplateService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class MarkdownDocumentFileGenerator implements DocumentFileGenerator {
|
||||
|
||||
@Autowired(required=false)
|
||||
private DocumentTemplateService documentTemplateService;
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.MARKDOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DocumentFileGenerateContext context, OutputStream outputStream) {
|
||||
DocumentTemplatePropertiesResponse templateProperties = documentTemplateService.getAllProperties();
|
||||
String fileName = context.getDatabaseDocument().getDatabaseName() + "-" + UUID.randomUUID().toString();
|
||||
String data = markdownData(context, templateProperties);
|
||||
Path tempFile = null;
|
||||
try {
|
||||
tempFile = Files.createTempFile(fileName, ".md");
|
||||
Path path = Files.writeString(tempFile, data, StandardCharsets.UTF_8);
|
||||
byte[] bytes = Files.readAllBytes(path);
|
||||
outputStream.write(bytes);
|
||||
} catch (IOException e) {
|
||||
if (tempFile != null) {
|
||||
try {
|
||||
Files.deleteIfExists(tempFile);
|
||||
} catch (IOException ex) {
|
||||
log.warn("delete temp file error", ex);
|
||||
}
|
||||
}
|
||||
throw new SystemException("System error");
|
||||
}
|
||||
}
|
||||
|
||||
private String markdownData(DocumentFileGenerateContext context,
|
||||
DocumentTemplatePropertiesResponse properties) {
|
||||
DatabaseDocumentResponse doc = context.getDatabaseDocument();
|
||||
MarkdownBuilder builder = MarkdownBuilder.builder();
|
||||
builder.primaryTitle(doc.getDatabaseName());
|
||||
// overview
|
||||
overviewBuild(builder, doc);
|
||||
// field map by table name
|
||||
Map<String, String> columnTitleMap = properties.getColumnFieldNameProperties()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(d -> d.getKey(),
|
||||
d -> Objects.requireNonNullElse(d.getValue(), d.getDefaultValue())));
|
||||
Map<String, String> indexTitleMap = properties.getIndexFieldNameProperties()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(d -> d.getKey(),
|
||||
d -> Objects.requireNonNullElse(d.getValue(), d.getDefaultValue())));
|
||||
Map<String, String> triggerTitleMap = properties.getTriggerFieldNameProperties()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(d -> d.getKey(),
|
||||
d -> Objects.requireNonNullElse(d.getValue(), d.getDefaultValue())));
|
||||
Map<String, String> foreignKeyTitleMap = properties.getForeignKeyFieldNameProperties()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(d -> d.getKey(),
|
||||
d -> Objects.requireNonNullElse(d.getValue(), d.getDefaultValue())));
|
||||
// table document build
|
||||
doc.getTables().forEach(table -> {
|
||||
if (StringUtils.isNotBlank(table.getComment())) {
|
||||
builder.secondTitle(table.getName() + " /\\*" + table.getComment() + "\\*/");
|
||||
} else {
|
||||
builder.secondTitle(table.getName());
|
||||
}
|
||||
columnBuild(builder, table, columnTitleMap);
|
||||
indexBuild(builder, table, indexTitleMap);
|
||||
foreignKeyBuild(builder, table, foreignKeyTitleMap);
|
||||
triggerBuild(builder, table, triggerTitleMap);
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void overviewBuild(MarkdownBuilder builder, DatabaseDocumentResponse doc) {
|
||||
builder.secondTitle("overview");
|
||||
List<List<String>> overviewContent = new ArrayList<>();
|
||||
for (int i = 0; i < doc.getTables().size(); i++) {
|
||||
TableDocumentResponse table = doc.getTables().get(i);
|
||||
List<String> row = List.of((i + 1) + "",
|
||||
Objects.requireNonNullElse(table.getName(), ""),
|
||||
Objects.requireNonNullElse(table.getType(), ""),
|
||||
Objects.requireNonNullElse(table.getComment(), ""));
|
||||
overviewContent.add(row);
|
||||
}
|
||||
builder.table(List.of("", "表名", "类型", "备注"), overviewContent);
|
||||
}
|
||||
|
||||
private void columnBuild(MarkdownBuilder builder,
|
||||
TableDocumentResponse table,
|
||||
Map<String, String> titleMap) {
|
||||
Function<TableDocumentResponse.ColumnDocumentResponse, String>
|
||||
columnDefaultValueMapping = column -> {
|
||||
if (Objects.equals(column.getNullable(), "YES")) {
|
||||
return Objects.requireNonNullElse(column.getDefaultValue(), "null");
|
||||
} else {
|
||||
return Objects.requireNonNullElse(column.getDefaultValue(), "");
|
||||
}
|
||||
};
|
||||
builder.thirdTitle("Columns");
|
||||
List<List<String>> columnContent = new ArrayList<>();
|
||||
for (int i = 0; i < table.getColumns().size(); i++) {
|
||||
var column = table.getColumns().get(i);
|
||||
String type;
|
||||
if (column.getDecimalDigits() == null
|
||||
|| Objects.requireNonNullElse(column.getDecimalDigits(), 0) == 0) {
|
||||
type = column.getType() + "(" + column.getSize() + ")";
|
||||
} else {
|
||||
type = column.getType() + "(" + column.getSize() + "," + column.getDecimalDigits() + ")";
|
||||
}
|
||||
columnContent.add(List.of((i + 1) + "",
|
||||
column.getName(),
|
||||
type,
|
||||
column.getIsPrimaryKey() ? "YES" : "NO",
|
||||
column.getNullable(),
|
||||
column.getAutoIncrement(),
|
||||
columnDefaultValueMapping.apply(column),
|
||||
Objects.requireNonNullElse(column.getComment(), "")));
|
||||
}
|
||||
builder.table(
|
||||
List.of(
|
||||
"",
|
||||
titleMap.getOrDefault("name", "name"),
|
||||
titleMap.getOrDefault("type", "type"),
|
||||
titleMap.getOrDefault("isPrimaryKey", "isPrimaryKey"),
|
||||
titleMap.getOrDefault("nullable", "nullable"),
|
||||
titleMap.getOrDefault("autoIncrement", "autoIncrement"),
|
||||
titleMap.getOrDefault("defaultValue", "defaultValue"),
|
||||
titleMap.getOrDefault("comment", "comment")
|
||||
),
|
||||
columnContent
|
||||
);
|
||||
}
|
||||
|
||||
private void indexBuild(MarkdownBuilder builder,
|
||||
TableDocumentResponse table,
|
||||
Map<String, String> titleMap) {
|
||||
builder.thirdTitle("Indexes");
|
||||
List<List<String>> indexContent = new ArrayList<>();
|
||||
for (int i = 0; i < table.getIndexes().size(); i++) {
|
||||
var index = table.getIndexes().get(i);
|
||||
String columnNames = String.join(", ", index.getColumnNames());
|
||||
String isUnique = index.getIsUnique() ? "YES" : "NO";
|
||||
indexContent.add(List.of((i + 1) + "", index.getName(), isUnique, columnNames));
|
||||
}
|
||||
builder.table(
|
||||
List.of(
|
||||
"",
|
||||
titleMap.getOrDefault("name", "name"),
|
||||
titleMap.getOrDefault("isUnique", "isUnique"),
|
||||
titleMap.getOrDefault("columnNames", "columnNames")
|
||||
),
|
||||
indexContent
|
||||
);
|
||||
}
|
||||
|
||||
private void foreignKeyBuild(MarkdownBuilder builder,
|
||||
TableDocumentResponse table,
|
||||
Map<String, String> titleMap) {
|
||||
if (!table.getForeignKeys().isEmpty()) {
|
||||
List<List<String>> foreignKeys = new ArrayList<>();
|
||||
builder.thirdTitle("Foreign Keys");
|
||||
for (int i = 0; i < table.getForeignKeys().size(); i++) {
|
||||
TableDocumentResponse.ForeignKeyDocumentResponse fk = table.getForeignKeys().get(i);
|
||||
List<String> item = List.of(
|
||||
(i + 1) + "",
|
||||
Objects.requireNonNullElse(fk.getFkName(), ""), fk.getFkColumnName(),
|
||||
Objects.requireNonNullElse(fk.getPkName(), ""), fk.getPkTableName(),
|
||||
fk.getPkColumnName(),
|
||||
fk.getUpdateRule(), fk.getDeleteRule()
|
||||
);
|
||||
foreignKeys.add(item);
|
||||
}
|
||||
builder.table(
|
||||
List.of(
|
||||
"",
|
||||
titleMap.getOrDefault("fkName", "fkName"),
|
||||
titleMap.getOrDefault("fkColumnName", "fkColumnName"),
|
||||
titleMap.getOrDefault("pkName", "pkName"),
|
||||
titleMap.getOrDefault("pkTableName", "pkTableName"),
|
||||
titleMap.getOrDefault("pkColumnName", "pkColumnName"),
|
||||
titleMap.getOrDefault("updateRule", "updateRule"),
|
||||
titleMap.getOrDefault("deleteRule", "deleteRule")
|
||||
),
|
||||
foreignKeys
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerBuild(MarkdownBuilder builder,
|
||||
TableDocumentResponse table,
|
||||
Map<String, String> titleMap) {
|
||||
if (!table.getTriggers().isEmpty()) {
|
||||
List<List<String>> triggerContent = new ArrayList<>();
|
||||
for (int i = 0; i < table.getTriggers().size(); i++) {
|
||||
var trigger = table.getTriggers().get(i);
|
||||
triggerContent.add(
|
||||
List.of(
|
||||
(i + 1) + "",
|
||||
Objects.requireNonNullElse(trigger.getName(), ""),
|
||||
Objects.requireNonNullElse(trigger.getTiming(), ""),
|
||||
Objects.requireNonNullElse(trigger.getManipulation(), ""),
|
||||
Objects.requireNonNullElse(trigger.getStatement(), "")
|
||||
));
|
||||
}
|
||||
builder.thirdTitle("Triggers");
|
||||
builder.table(
|
||||
List.of(
|
||||
"",
|
||||
titleMap.getOrDefault("name", "name"),
|
||||
titleMap.getOrDefault("timing", "timing"),
|
||||
titleMap.getOrDefault("manipulation", "manipulation"),
|
||||
titleMap.getOrDefault("statement", "statement")
|
||||
),
|
||||
triggerContent
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.salpa.subject.domain.generator;
|
||||
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.HackLoopTableRenderPolicy;
|
||||
import com.salpa.common.exception.SystemException;
|
||||
import com.salpa.subject.domain.data.TableDocumentResponse;
|
||||
import com.salpa.subject.domain.vo.ColumnVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WordFileGenerator implements DocumentFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.WORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DocumentFileGenerateContext context, OutputStream outputStream) {
|
||||
try {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("databaseName",context.getDatabaseDocument().getDatabaseName());
|
||||
List<Map<String,Object>> tList=new ArrayList<>();
|
||||
List<Map<String, Object>> tables = new ArrayList<>();
|
||||
List<TableDocumentResponse> tables1 = context.getDatabaseDocument().getTables();
|
||||
for (TableDocumentResponse tableDocumentResponse : tables1) {
|
||||
Map<String, Object> table = new HashMap<>();
|
||||
table.put("tableName",tableDocumentResponse.getName());
|
||||
table.put("tableType",tableDocumentResponse.getType());
|
||||
table.put("tableComment",tableDocumentResponse.getComment());
|
||||
tables.add(table);
|
||||
List<TableDocumentResponse.ColumnDocumentResponse> columns1 = tableDocumentResponse.getColumns();
|
||||
List<ColumnVo> columns = new ArrayList<>();
|
||||
Map<String,Object> tMap = new HashMap<>();
|
||||
for (TableDocumentResponse.ColumnDocumentResponse column : columns1) {
|
||||
ColumnVo columnVo = new ColumnVo();
|
||||
columnVo.setName(column.getName());
|
||||
columnVo.setType(column.getType() + "(" + column.getSize() + ")");
|
||||
if (column.getIsPrimaryKey()) {
|
||||
columnVo.setPrimaryKey("YES");
|
||||
} else {
|
||||
columnVo.setPrimaryKey("NO");
|
||||
}
|
||||
columnVo.setNullable(column.getNullable());
|
||||
columnVo.setAutoIncrement(column.getAutoIncrement());
|
||||
columnVo.setDefaultValue(column.getDefaultValue());
|
||||
columnVo.setComment(column.getComment());
|
||||
columns.add(columnVo);
|
||||
}
|
||||
tMap.put("tableName",tableDocumentResponse.getName());
|
||||
tMap.put("columns",columns);
|
||||
tList.add(tMap);
|
||||
}
|
||||
data.put("tables",tables);
|
||||
data.put("tableColumns",tList);
|
||||
InputStream inputStream = new ClassPathResource("word.docx").getInputStream();
|
||||
HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
|
||||
Configure config = Configure.newBuilder().bind("tables", policy).bind("columns",policy).build();
|
||||
XWPFTemplate template = XWPFTemplate.compile(inputStream,config).render(data);
|
||||
template.write(outputStream);
|
||||
} catch (IOException e) {
|
||||
throw new SystemException("System error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.salpa.subject.domain.generator.plantuml;
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseDocumentResponse;
|
||||
import com.salpa.subject.domain.data.TableDocumentResponse;
|
||||
import com.salpa.subject.domain.generator.DocumentFileGenerator;
|
||||
import com.salpa.common.exception.SystemException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.SourceStringReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public abstract class BasePlantUmlFileGenerator implements DocumentFileGenerator {
|
||||
|
||||
public static final String LINE = "\r\n";
|
||||
|
||||
@Override
|
||||
public void generate(DocumentFileGenerateContext context, OutputStream outputStream) {
|
||||
String dsl = new ErDsl(context).toDsl();
|
||||
try {
|
||||
new SourceStringReader(dsl).outputImage(outputStream, fileFormatOption());
|
||||
} catch (IOException e) {
|
||||
log.error("export plantuml error", e);
|
||||
throw new SystemException("System error");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract FileFormatOption fileFormatOption();
|
||||
|
||||
public class ErDsl {
|
||||
|
||||
private final DocumentFileGenerateContext context;
|
||||
|
||||
private Set<String> foreignKeyRelations = new HashSet<>(16);
|
||||
|
||||
private Set<String> tables = new HashSet<>(16);
|
||||
|
||||
public ErDsl(DocumentFileGenerateContext context) {
|
||||
this.context = context;
|
||||
Set<String> tables = context.getDatabaseDocument()
|
||||
.getTables()
|
||||
.stream()
|
||||
.map(TableDocumentResponse::getName)
|
||||
.collect(Collectors.toSet());
|
||||
this.tables = tables;
|
||||
}
|
||||
|
||||
public String toDsl() {
|
||||
DatabaseDocumentResponse databaseDocument = context.getDatabaseDocument();
|
||||
StringBuilder dslBuilder = new StringBuilder(1024);
|
||||
// use smetana engine
|
||||
dslBuilder.append("@startuml").append(LINE)
|
||||
.append("!pragma layout smetana").append(LINE);
|
||||
|
||||
// configuration
|
||||
dslBuilder.append("' hide the spot").append(LINE);
|
||||
dslBuilder.append("hide circle").append(LINE);
|
||||
|
||||
//分辨率像素
|
||||
dslBuilder.append("skinparam dpi 48").append(LINE);
|
||||
dslBuilder.append("scale 8192 width").append(LINE);
|
||||
dslBuilder.append("scale 8192 height").append(LINE);
|
||||
|
||||
// entities
|
||||
String entities = databaseDocument.getTables()
|
||||
.stream()
|
||||
.map(table -> toErDsl(table))
|
||||
.collect(Collectors.joining(LINE));
|
||||
dslBuilder.append(entities);
|
||||
|
||||
// relation
|
||||
dslBuilder.append(LINE);
|
||||
String relations = foreignKeyRelations.stream()
|
||||
.collect(Collectors.joining(LINE));
|
||||
dslBuilder.append(relations);
|
||||
dslBuilder.append(LINE);
|
||||
|
||||
dslBuilder.append("@enduml");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("------------------------------");
|
||||
log.debug(dslBuilder.toString());
|
||||
log.debug("------------------------------");
|
||||
}
|
||||
return dslBuilder.toString();
|
||||
}
|
||||
|
||||
private String toErDsl(TableDocumentResponse table) {
|
||||
StringBuilder dslBuilder = new StringBuilder(1024);
|
||||
dslBuilder.append("entity ").append(table.getName())
|
||||
.append(" {");
|
||||
table.getColumns()
|
||||
.stream()
|
||||
.filter(TableDocumentResponse.ColumnDocumentResponse::getIsPrimaryKey)
|
||||
.forEach(primaryCol -> {
|
||||
dslBuilder.append(LINE);
|
||||
dslBuilder.append("*")
|
||||
.append(primaryCol.getName())
|
||||
.append(" : ")
|
||||
.append(primaryCol.getType())
|
||||
.append("(")
|
||||
.append(primaryCol.getSize())
|
||||
.append(")")
|
||||
.append(" <PK> ");
|
||||
dslBuilder.append(LINE);
|
||||
});
|
||||
table.getColumns()
|
||||
.stream()
|
||||
.filter(col -> !col.getIsPrimaryKey())
|
||||
.forEach(col -> {
|
||||
dslBuilder.append(LINE);
|
||||
if ("NO".equalsIgnoreCase(col.getNullable())) {
|
||||
dslBuilder.append("*");
|
||||
}
|
||||
dslBuilder.append(col.getName())
|
||||
.append(" : ")
|
||||
.append(col.getType())
|
||||
.append("(")
|
||||
.append(col.getSize())
|
||||
.append(")");
|
||||
if (col.getComment() != null && !"".equals(col.getComment().trim())) {
|
||||
dslBuilder.append(" /* ").append(col.getComment()).append(" */");
|
||||
}
|
||||
dslBuilder.append(LINE);
|
||||
});
|
||||
dslBuilder.append("}");
|
||||
dslBuilder.append(LINE);
|
||||
|
||||
table.getForeignKeys()
|
||||
.stream()
|
||||
.filter(fk -> tables.contains(fk.getFkTableName()) && tables.contains(fk.getPkTableName()))
|
||||
.forEach(fk -> {
|
||||
String fkTableName = fk.getFkTableName();
|
||||
String fkColumnName = fk.getFkColumnName();
|
||||
String pkTableName = fk.getPkTableName();
|
||||
String pkColumnName = fk.getPkColumnName();
|
||||
StringBuilder relationBuilder = new StringBuilder();
|
||||
relationBuilder.append(fkTableName).append("::").append(fkColumnName)
|
||||
.append(" --> ")
|
||||
.append(pkTableName).append("::").append(pkColumnName)
|
||||
.append(" : ")
|
||||
.append(Objects.requireNonNullElse(fk.getFkName(), ""));
|
||||
foreignKeyRelations.add(relationBuilder.toString());
|
||||
});
|
||||
return dslBuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.salpa.subject.domain.generator.plantuml;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class PlantUmlErSvgFileGenerator extends BasePlantUmlFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(com.salpa.subject.domain.generator.DocumentFileType type) {
|
||||
return type == com.salpa.subject.domain.generator.DocumentFileType.PLANT_UML_ER_SVG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFormatOption fileFormatOption() {
|
||||
return new FileFormatOption(FileFormat.SVG);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.salpa.subject.domain.generator.plantuml;
|
||||
|
||||
import com.salpa.subject.domain.generator.DocumentFileType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class PlantUmlPngFileGenerator extends BasePlantUmlFileGenerator {
|
||||
|
||||
@Override
|
||||
public boolean support(DocumentFileType type) {
|
||||
return type == DocumentFileType.PLANT_UML_ER_PNG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileFormatOption fileFormatOption() {
|
||||
return new FileFormatOption(FileFormat.PNG);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
import com.salpa.subject.domain.data.TriggerMeta;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractSqlTriggerMetaProvider implements TriggerMetaProvider {
|
||||
|
||||
@Override
|
||||
public List<TriggerMeta> selectTriggers(Connection connection, TableCondition condition) {
|
||||
String sql = sql(condition);
|
||||
PreparedStatement preparedStatement = null;
|
||||
try {
|
||||
preparedStatement = connection.prepareStatement(sql);
|
||||
ResultSet results = preparedStatement.executeQuery();
|
||||
List<TriggerMeta> triggers = new ArrayList<>();
|
||||
while (results.next()) {
|
||||
String name = getTriggerName(results);
|
||||
String statement = getStatement(results);
|
||||
String timing = getTiming(results);
|
||||
String manipulation = getManipulation(results);
|
||||
String created = getCreateAt(results);
|
||||
TriggerMeta meta = TriggerMeta.builder()
|
||||
.name(name)
|
||||
.manipulation(manipulation)
|
||||
.timing(timing)
|
||||
.statement(statement)
|
||||
.createAt(created)
|
||||
.build();
|
||||
triggers.add(meta);
|
||||
}
|
||||
return triggers;
|
||||
} catch (SQLException e) {
|
||||
log.warn("get trigger meta failed", e);
|
||||
return Collections.emptyList();
|
||||
} finally {
|
||||
if (preparedStatement != null) {
|
||||
try {
|
||||
preparedStatement.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String sql(TableCondition condition);
|
||||
|
||||
protected String getTriggerName(ResultSet results) throws SQLException {
|
||||
return Objects.requireNonNullElse(results.getString("TRIGGER_NAME"), "");
|
||||
}
|
||||
|
||||
protected String getStatement(ResultSet results) throws SQLException {
|
||||
return results.getString("ACTION_STATEMENT");
|
||||
}
|
||||
|
||||
protected String getTiming(ResultSet results) throws SQLException {
|
||||
return results.getString("ACTION_TIMING");
|
||||
}
|
||||
|
||||
protected String getManipulation(ResultSet results) throws SQLException {
|
||||
return results.getString("EVENT_MANIPULATION");
|
||||
}
|
||||
|
||||
protected String getCreateAt(ResultSet results) throws SQLException {
|
||||
String created = results.getString("CREATED");
|
||||
if (created == null) {
|
||||
return "unknown";
|
||||
}
|
||||
return created;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public interface ColumnMetaProvider {
|
||||
|
||||
List<ColumnMeta> selectColumns(Connection connection, TableCondition condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseMeta;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface DatabaseMetaProvider {
|
||||
|
||||
Optional<DatabaseMeta> select(Connection connection, Condition condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.ForeignKeyMeta;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public interface ForeignKeyMetaProvider {
|
||||
|
||||
List<ForeignKeyMeta> selectForeignKeys(Connection connection, TableCondition condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.IndexMeta;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IndexMetaProvider {
|
||||
|
||||
List<IndexMeta> selectIndexes(Connection connection, TableCondition condition);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
import com.salpa.subject.domain.provider.jdbc.*;
|
||||
import com.salpa.subject.domain.provider.maria.MariaTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.mysql.MysqlTableTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.oracle.OracleTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.postgresql.PostgresqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.sqlserver.SqlServerColumnMetaProvider;
|
||||
import com.salpa.subject.domain.provider.sqlserver.SqlServerTableMetaProvider;
|
||||
import com.salpa.subject.domain.provider.sqlserver.SqlServerTriggerMetaProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@Slf4j
|
||||
public class MetaProviders {
|
||||
|
||||
public static DatabaseMetaProvider jdbc() {
|
||||
var columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new JdbcTriggerMetaProvider();
|
||||
var tableMetaProvider = new JdbcTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
triggerMetaProvider,
|
||||
foreignKeyMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
|
||||
public static DatabaseMetaProvider of(Connection connection) {
|
||||
String url;
|
||||
try {
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
url = metaData.getURL();
|
||||
} catch (SQLException e) {
|
||||
log.warn("failed to get connect url, {}, fallback to jdbc provider", e.getMessage());
|
||||
return jdbc();
|
||||
}
|
||||
if (url.contains(":sqlserver:")) {
|
||||
return sqlServer();
|
||||
}
|
||||
if (url.contains(":mysql:")) {
|
||||
return mysql();
|
||||
}
|
||||
if (url.contains(":postgresql:") || url.contains(":pgsql:")) {
|
||||
return postgresql();
|
||||
}
|
||||
if (url.contains(":mariadb:")) {
|
||||
return mariaDB();
|
||||
}
|
||||
if (url.contains(":oracle:")) {
|
||||
return oracle();
|
||||
}
|
||||
return jdbc();
|
||||
}
|
||||
|
||||
private static DatabaseMetaProvider mysql() {
|
||||
var columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new MysqlTableTriggerMetaProvider();
|
||||
var tableMetaProvider = new JdbcTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
triggerMetaProvider,
|
||||
foreignKeyMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
|
||||
private static DatabaseMetaProvider sqlServer() {
|
||||
var columnMetaProvider = new SqlServerColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new SqlServerTriggerMetaProvider();
|
||||
var tableMetaProvider = new SqlServerTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
foreignKeyMetaProvider,
|
||||
triggerMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
|
||||
private static DatabaseMetaProvider postgresql() {
|
||||
var columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new PostgresqlTriggerMetaProvider();
|
||||
var tableMetaProvider = new JdbcTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
triggerMetaProvider,
|
||||
foreignKeyMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
|
||||
private static DatabaseMetaProvider mariaDB() {
|
||||
var columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new MariaTriggerMetaProvider();
|
||||
var tableMetaProvider = new JdbcTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
triggerMetaProvider,
|
||||
foreignKeyMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
|
||||
private static DatabaseMetaProvider oracle() {
|
||||
var columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
var foreignKeyMetaProvider = new JdbcForeignKeyMetaProvider();
|
||||
var indexMetaProvider = new JdbcIndexMetaProvider();
|
||||
var triggerMetaProvider = new OracleTriggerMetaProvider();
|
||||
var tableMetaProvider = new JdbcTableMetaProvider(
|
||||
columnMetaProvider,
|
||||
indexMetaProvider,
|
||||
triggerMetaProvider,
|
||||
foreignKeyMetaProvider
|
||||
);
|
||||
return new JdbcDatabaseMetaProvider(tableMetaProvider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.TableMeta;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public interface TableMetaProvider {
|
||||
|
||||
List<TableMeta> selectTables(Connection connection, Condition condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.salpa.subject.domain.provider;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.TriggerMeta;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
|
||||
public interface TriggerMetaProvider {
|
||||
|
||||
List<TriggerMeta> selectTriggers(Connection connection, TableCondition condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.salpa.subject.domain.provider.condition;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@SuperBuilder
|
||||
@Getter
|
||||
public class Condition {
|
||||
|
||||
@NonNull
|
||||
private String databaseName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
@Builder.Default
|
||||
@Builder.ObtainVia(method = "ignoreTableNameRegexes")
|
||||
private Collection<Pattern> ignoreTableNamePatterns = Collections.emptyList();
|
||||
|
||||
@Builder.Default
|
||||
@Builder.ObtainVia(method = "ignoreTableColumnNameRegexes")
|
||||
private Collection<Pattern> ignoreTableColumnNamePatterns = Collections.emptyList();
|
||||
|
||||
public boolean tableIsIgnored(String tableName) {
|
||||
return ignoreTableNamePatterns.stream().anyMatch(regex -> regex.matcher(tableName).matches());
|
||||
}
|
||||
|
||||
public boolean columnIsIgnored(String column) {
|
||||
return ignoreTableColumnNamePatterns.stream().anyMatch(regex -> regex.matcher(column).matches());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.salpa.subject.domain.provider.condition;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@SuperBuilder
|
||||
@Getter
|
||||
public class TableCondition extends Condition {
|
||||
|
||||
@NonNull
|
||||
private String tableName;
|
||||
|
||||
public static TableCondition of(Condition condition, String tableName) {
|
||||
return TableCondition.builder()
|
||||
.databaseName(condition.getDatabaseName())
|
||||
.tableName(tableName)
|
||||
.schemaName(condition.getSchemaName())
|
||||
.ignoreTableNamePatterns(condition.getIgnoreTableNamePatterns())
|
||||
.ignoreTableColumnNamePatterns(condition.getIgnoreTableColumnNamePatterns())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.provider.ColumnMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class JdbcColumnMetaProvider implements ColumnMetaProvider {
|
||||
|
||||
@Override
|
||||
public List<ColumnMeta> selectColumns(Connection connection, TableCondition tableCondition) {
|
||||
try {
|
||||
return doSelect(connection, tableCondition);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<ColumnMeta> doSelect(Connection connection, TableCondition tableCondition) throws SQLException {
|
||||
List<ColumnMeta> columnDocs = new ArrayList<>();
|
||||
String databaseName = tableCondition.getDatabaseName();
|
||||
String tableName = tableCondition.getTableName();
|
||||
List<String> primaryKeyColumns = selectPrimaryKeyColumns(connection.getMetaData(), tableCondition);
|
||||
ResultSet columnsResult;
|
||||
try {
|
||||
columnsResult = connection.getMetaData()
|
||||
.getColumns(databaseName, tableCondition.getSchemaName(), tableName, null);
|
||||
} catch (SQLException e) {
|
||||
log.warn("warn: ignore columns in " + databaseName + "." + tableName + ", error: " + e.getMessage());
|
||||
return columnDocs;
|
||||
}
|
||||
try {
|
||||
while (columnsResult.next()) {
|
||||
String columnName = columnsResult.getString("COLUMN_NAME");
|
||||
if (tableCondition.columnIsIgnored(columnName)) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("ignore column: " + columnName);
|
||||
}
|
||||
} else {
|
||||
String defaultValue = columnsResult.getString("COLUMN_DEF");
|
||||
String isNullable = columnsResult.getString("IS_NULLABLE");
|
||||
if (isNullable.trim().equals("")) {
|
||||
isNullable = "UNKNOWN";
|
||||
}
|
||||
|
||||
if (defaultValue != null && defaultValue.trim().equals("")) {
|
||||
defaultValue = "'" + defaultValue + "'";
|
||||
}
|
||||
Integer decimalDigits;
|
||||
if (columnsResult.getObject("DECIMAL_DIGITS") == null) {
|
||||
decimalDigits = null;
|
||||
} else {
|
||||
decimalDigits = columnsResult.getInt("DECIMAL_DIGITS");
|
||||
}
|
||||
Integer columnSize = columnsResult.getInt("COLUMN_SIZE");
|
||||
String columnType = columnsResult.getString("TYPE_NAME");
|
||||
String columnComment = columnsResult.getString("REMARKS");
|
||||
int dataType = columnsResult.getInt("DATA_TYPE");
|
||||
String autoIncrement = retrieveAutoIncrement(columnsResult);
|
||||
ColumnMeta columnMeta = ColumnMeta.builder()
|
||||
.name(columnName)
|
||||
.dataType(dataType)
|
||||
.type(columnType)
|
||||
.size(columnSize)
|
||||
.decimalDigits(decimalDigits)
|
||||
.nullable(isNullable)
|
||||
.autoIncrement(autoIncrement)
|
||||
.comment(columnComment)
|
||||
.defaultValue(defaultValue)
|
||||
.isPrimaryKey(primaryKeyColumns.contains(columnName))
|
||||
.build();
|
||||
columnDocs.add(columnMeta);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
columnsResult.close();
|
||||
}
|
||||
return columnDocs;
|
||||
}
|
||||
|
||||
private String retrieveAutoIncrement(ResultSet columnsResult) {
|
||||
try {
|
||||
return retrieveAutoIncrement(columnsResult, "IS_AUTOINCREMENT");
|
||||
} catch (SQLException e) {
|
||||
log.warn("get is_autoincrement failed, fallback to is_auto_increment, error: " + e.getMessage());
|
||||
try {
|
||||
// hive jdbc driver doesn't support is_autoincrement, fallback to is_auto_increment
|
||||
return retrieveAutoIncrement(columnsResult, "is_auto_increment");
|
||||
} catch (SQLException ex) {
|
||||
log.warn("get is_auto_increment failed, error: " + ex.getMessage());
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String retrieveAutoIncrement(ResultSet columnsResult, String columnName) throws SQLException {
|
||||
String isAutoIncrement = columnsResult.getString(columnName);
|
||||
if (isAutoIncrement.trim().equals("")) {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
return isAutoIncrement;
|
||||
}
|
||||
|
||||
private List<String> selectPrimaryKeyColumns(DatabaseMetaData meta,
|
||||
TableCondition tableCondition) throws SQLException {
|
||||
ResultSet result = meta.getPrimaryKeys(tableCondition.getDatabaseName(),
|
||||
tableCondition.getSchemaName(), tableCondition.getTableName());
|
||||
try {
|
||||
List<String> columns = new ArrayList<>();
|
||||
while (result.next()) {
|
||||
String columnName = result.getString("COLUMN_NAME");
|
||||
columns.add(columnName);
|
||||
}
|
||||
return columns;
|
||||
} finally {
|
||||
result.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseMeta;
|
||||
import com.salpa.subject.domain.data.TableMeta;
|
||||
import com.salpa.subject.domain.provider.DatabaseMetaProvider;
|
||||
import com.salpa.subject.domain.provider.TableMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class JdbcDatabaseMetaProvider implements DatabaseMetaProvider {
|
||||
|
||||
private final TableMetaProvider tableMetaProvider;
|
||||
|
||||
@Override
|
||||
public Optional<DatabaseMeta> select(Connection connection, Condition condition) {
|
||||
try {
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet catalogs = metaData.getCatalogs();
|
||||
while (catalogs.next()) {
|
||||
String catalogName = catalogs.getString("TABLE_CAT");
|
||||
if (Objects.equals(condition.getDatabaseName(), catalogName)) {
|
||||
List<TableMeta> tableDocs = tableMetaProvider.selectTables(connection, condition);
|
||||
DatabaseMeta meta = DatabaseMeta.builder()
|
||||
.productName(metaData.getDatabaseProductName())
|
||||
.productVersion(metaData.getDatabaseProductVersion())
|
||||
.databaseName(catalogName)
|
||||
.schemaName(condition.getSchemaName())
|
||||
.tables(tableDocs)
|
||||
.build();
|
||||
return Optional.of(meta);
|
||||
}
|
||||
}
|
||||
|
||||
ResultSet schemas = metaData.getSchemas();
|
||||
while (schemas.next()) {
|
||||
String schemaName = schemas.getString("TABLE_SCHEM");
|
||||
if (Objects.equals(condition.getSchemaName(), schemaName)) {
|
||||
List<TableMeta> tableDocs = tableMetaProvider.selectTables(connection, condition);
|
||||
DatabaseMeta meta = DatabaseMeta.builder()
|
||||
.productName(metaData.getDatabaseProductName())
|
||||
.productVersion(metaData.getDatabaseProductVersion())
|
||||
.databaseName(condition.getDatabaseName())
|
||||
.schemaName(condition.getSchemaName())
|
||||
.tables(tableDocs)
|
||||
.build();
|
||||
return Optional.of(meta);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
import com.salpa.subject.domain.data.ForeignKeyMeta;
|
||||
import com.salpa.subject.domain.provider.ForeignKeyMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class JdbcForeignKeyMetaProvider implements ForeignKeyMetaProvider {
|
||||
|
||||
@Override
|
||||
public List<ForeignKeyMeta> selectForeignKeys(Connection connection, TableCondition condition) {
|
||||
String databaseName = condition.getDatabaseName();
|
||||
String schemaName = condition.getSchemaName();
|
||||
String tableName = condition.getTableName();
|
||||
List<ForeignKeyMeta> foreignKeys = new ArrayList<>();
|
||||
ResultSet keyResult = null;
|
||||
try {
|
||||
keyResult = connection.getMetaData().getImportedKeys(databaseName, schemaName, tableName);
|
||||
while (keyResult.next()) {
|
||||
String fkTableName = keyResult.getString("FKTABLE_NAME");
|
||||
String fkColumnName = keyResult.getString("FKCOLUMN_NAME");
|
||||
String fkName = keyResult.getString("FK_NAME");
|
||||
|
||||
String pkTableName = keyResult.getString("PKTABLE_NAME");
|
||||
String pkColumnName = keyResult.getString("PKCOLUMN_NAME");
|
||||
String pkName = keyResult.getString("PK_NAME");
|
||||
int updateRule = keyResult.getInt("UPDATE_RULE");
|
||||
int keySeq = keyResult.getInt("KEY_SEQ");
|
||||
int deleteRule = keyResult.getInt("DELETE_RULE");
|
||||
ForeignKeyMeta meta = ForeignKeyMeta.builder()
|
||||
.keySeq(keySeq)
|
||||
.fkTableName(fkTableName)
|
||||
.fkColumnName(fkColumnName)
|
||||
.fkName(fkName)
|
||||
.pkTableName(pkTableName)
|
||||
.pkColumnName(pkColumnName)
|
||||
.pkName(pkName)
|
||||
.updateRule(updateRuleConvert(updateRule))
|
||||
.deleteRule(deleteRuleConvert(deleteRule))
|
||||
.build();
|
||||
foreignKeys.add(meta);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.warn("warn: ignore foreign keys in " + databaseName + "." + tableName + ", " + e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (keyResult != null) {
|
||||
keyResult.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.warn("warn: close key result error " + databaseName + "." + tableName + ", " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return foreignKeys;
|
||||
}
|
||||
|
||||
private String updateRuleConvert(int updateRule) {
|
||||
return doMapping(updateRule, "update");
|
||||
}
|
||||
|
||||
private String deleteRuleConvert(int deleteRule) {
|
||||
return doMapping(deleteRule, "delete");
|
||||
}
|
||||
|
||||
private String doMapping(int rule, String type) {
|
||||
if (rule == DatabaseMetaData.importedKeyCascade) {
|
||||
return "CASCADE";
|
||||
}
|
||||
if (rule == DatabaseMetaData.importedKeyRestrict) {
|
||||
return "CASCADE";
|
||||
}
|
||||
if (rule == DatabaseMetaData.importedKeyNoAction) {
|
||||
return "RESTRICT";
|
||||
}
|
||||
if (rule == DatabaseMetaData.importedKeySetNull) {
|
||||
return "SET_NULL";
|
||||
}
|
||||
if (rule == DatabaseMetaData.importedKeySetDefault) {
|
||||
return "SET_DEFAULT";
|
||||
}
|
||||
log.warn("can not map foreign key " + type + " rule = " + rule);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
import com.salpa.subject.domain.data.IndexMeta;
|
||||
import com.salpa.subject.domain.provider.IndexMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
@Slf4j
|
||||
public class JdbcIndexMetaProvider implements IndexMetaProvider {
|
||||
@Override
|
||||
public List<IndexMeta> selectIndexes(Connection connection, TableCondition condition) {
|
||||
try {
|
||||
return doCreateIndexDocs(connection, condition);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IndexMeta> doCreateIndexDocs(Connection connection, TableCondition condition)
|
||||
throws SQLException {
|
||||
String databaseName = condition.getDatabaseName();
|
||||
String tableName = condition.getTableName();
|
||||
List<IndexMeta> indexMetas = new ArrayList<>();
|
||||
ResultSet indexResults;
|
||||
try {
|
||||
indexResults = connection.getMetaData()
|
||||
.getIndexInfo(databaseName, condition.getSchemaName(), tableName, false, false);
|
||||
} catch (SQLException e) {
|
||||
log.warn("warn: ignore " + databaseName + "." + tableName + ", error=" + e.getMessage());
|
||||
return indexMetas;
|
||||
}
|
||||
|
||||
Map<String, IndexMeta> metaGroupByName = new HashMap<>();
|
||||
try {
|
||||
while (indexResults.next()) {
|
||||
Boolean nonUnique = indexResults.getBoolean("NON_UNIQUE");
|
||||
String indexName = indexResults.getString("INDEX_NAME");
|
||||
String columnName = indexResults.getString("COLUMN_NAME");
|
||||
if (indexName == null) {
|
||||
continue;
|
||||
}
|
||||
if (metaGroupByName.containsKey(indexName)) {
|
||||
metaGroupByName.get(indexName).getColumnNames().add(columnName);
|
||||
} else {
|
||||
List<String> columns = new ArrayList<>();
|
||||
columns.add(columnName);
|
||||
IndexMeta indexMeta = IndexMeta.builder()
|
||||
.name(indexName)
|
||||
.columnNames(columns)
|
||||
.isUniqueKey(Objects.equals(nonUnique, false))
|
||||
.build();
|
||||
metaGroupByName.put(indexName, indexMeta);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
indexResults.close();
|
||||
}
|
||||
return new ArrayList<>(metaGroupByName.values());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.data.TableMeta;
|
||||
import com.salpa.subject.domain.provider.*;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JdbcTableMetaProvider implements TableMetaProvider {
|
||||
|
||||
private final ColumnMetaProvider columnMetaProvider;
|
||||
|
||||
private final IndexMetaProvider indexMetaProvider;
|
||||
|
||||
private final TriggerMetaProvider triggerMetaProvider;
|
||||
|
||||
private final ForeignKeyMetaProvider foreignKeyMetaProvider;
|
||||
|
||||
@Override
|
||||
public List<TableMeta> selectTables(Connection connection, Condition condition) {
|
||||
try {
|
||||
return doSelect(connection, condition);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<TableMeta> doSelect(Connection connection, Condition condition) throws SQLException {
|
||||
List<TableMeta> tableMetas = new ArrayList<>();
|
||||
String databaseName = condition.getDatabaseName();
|
||||
String[] tableTypes = {"TABLE", "VIEW"};
|
||||
ResultSet tablesResult = connection.getMetaData()
|
||||
.getTables(databaseName, condition.getSchemaName(), null, tableTypes);
|
||||
try {
|
||||
while (tablesResult.next()) {
|
||||
String tableName = tablesResult.getString("TABLE_NAME");
|
||||
if (condition.tableIsIgnored(tableName)) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("ignored table: " + databaseName + "." + tableName);
|
||||
}
|
||||
} else {
|
||||
String tableType = tablesResult.getString("TABLE_TYPE");
|
||||
String tableComment = tablesResult.getString("REMARKS");
|
||||
TableCondition tableCondition = TableCondition.of(condition, tableName);
|
||||
List<ColumnMeta> columns = columnMetaProvider.selectColumns(connection, tableCondition);
|
||||
if (columns.isEmpty()) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("ignored table: " + databaseName + "." + tableName
|
||||
+ ", caused by get empty columns");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
TableMeta tableMeta = TableMeta.builder()
|
||||
.name(tableName)
|
||||
.type(tableType)
|
||||
.comment(tableComment)
|
||||
.columns(columns)
|
||||
.foreignKeys(foreignKeyMetaProvider.selectForeignKeys(connection, tableCondition))
|
||||
.indexes(indexMetaProvider.selectIndexes(connection, tableCondition))
|
||||
.triggers(triggerMetaProvider.selectTriggers(connection, tableCondition))
|
||||
.build();
|
||||
tableMetas.add(tableMeta);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
tablesResult.close();
|
||||
}
|
||||
return tableMetas;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.salpa.subject.domain.provider.jdbc;
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.TriggerMeta;
|
||||
import com.salpa.subject.domain.provider.TriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JdbcTriggerMetaProvider implements TriggerMetaProvider {
|
||||
|
||||
@Override
|
||||
public List<TriggerMeta> selectTriggers(Connection connection, TableCondition condition) {
|
||||
// note: jdbc not support get triggers
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.salpa.subject.domain.provider.maria;
|
||||
|
||||
import com.salpa.subject.domain.provider.AbstractSqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class MariaTriggerMetaProvider extends AbstractSqlTriggerMetaProvider {
|
||||
@Override
|
||||
protected String sql(TableCondition condition) {
|
||||
String sql = "SELECT \n"
|
||||
+ " TRIGGER_NAME,\n"
|
||||
+ " TRIGGER_SCHEMA,\n"
|
||||
+ " TRIGGER_CATALOG,\n"
|
||||
+ " EVENT_OBJECT_CATALOG,\n"
|
||||
+ " EVENT_OBJECT_SCHEMA,\n"
|
||||
+ " EVENT_OBJECT_TABLE,\n"
|
||||
+ " ACTION_STATEMENT,\n"
|
||||
+ " ACTION_TIMING,\n"
|
||||
+ " EVENT_MANIPULATION,\n"
|
||||
+ " CREATED\n"
|
||||
+ "FROM information_schema.triggers "
|
||||
+ "WHERE TRIGGER_SCHEMA = '%s' AND EVENT_OBJECT_TABLE = '%s'";
|
||||
return String.format(sql, condition.getDatabaseName(), condition.getTableName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.salpa.subject.domain.provider.mysql;
|
||||
|
||||
import com.salpa.subject.domain.provider.AbstractSqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class MysqlTableTriggerMetaProvider extends AbstractSqlTriggerMetaProvider {
|
||||
@Override
|
||||
protected String sql(TableCondition condition) {
|
||||
String sql = "SELECT TRIGGER_CATALOG,\n"
|
||||
+ " TRIGGER_SCHEMA,\n"
|
||||
+ " TRIGGER_NAME,\n"
|
||||
+ " EVENT_MANIPULATION,\n"
|
||||
+ " EVENT_OBJECT_CATALOG,\n"
|
||||
+ " EVENT_OBJECT_SCHEMA,\n"
|
||||
+ " EVENT_OBJECT_TABLE,\n"
|
||||
+ " ACTION_ORDER,\n"
|
||||
+ " ACTION_CONDITION,\n"
|
||||
+ " ACTION_STATEMENT,\n"
|
||||
+ " ACTION_ORIENTATION,\n"
|
||||
+ " ACTION_TIMING,\n"
|
||||
+ " ACTION_REFERENCE_OLD_TABLE,\n"
|
||||
+ " ACTION_REFERENCE_NEW_TABLE,\n"
|
||||
+ " ACTION_REFERENCE_OLD_ROW,\n"
|
||||
+ " ACTION_REFERENCE_NEW_ROW,\n"
|
||||
+ " CREATED,\n"
|
||||
+ " SQL_MODE,\n"
|
||||
+ " DEFINER\n "
|
||||
+ "FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA = '%s' AND EVENT_OBJECT_TABLE = '%s'";
|
||||
return String.format(sql, condition.getDatabaseName(), condition.getTableName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.salpa.subject.domain.provider.oracle;
|
||||
|
||||
import com.salpa.subject.domain.provider.AbstractSqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
public class OracleTriggerMetaProvider extends AbstractSqlTriggerMetaProvider {
|
||||
@Override
|
||||
protected String sql(TableCondition condition) {
|
||||
String sql = "SELECT trig.table_owner AS schema_name,\n"
|
||||
+ " trig.table_name,\n"
|
||||
+ " trig.owner AS trigger_schema_name,\n"
|
||||
+ " trig.trigger_name as TRIGGER_NAME,\n"
|
||||
+ " trig.trigger_type AS ACTION_TIMING,\n"
|
||||
+ " trig.triggering_event as EVENT_MANIPULATION,\n"
|
||||
+ " trig.status,\n"
|
||||
+ " trig.trigger_body AS ACTION_STATEMENT \n"
|
||||
+ "FROM sys.all_triggers trig\n"
|
||||
+ " INNER JOIN sys.all_tables tab ON trig.table_owner = tab.owner\n"
|
||||
+ " AND trig.table_name = tab.table_name\n"
|
||||
+ "WHERE trig.base_object_type = 'TABLE' AND trig.owner = '%s' AND trig.TABLE_NAME = '%s'";
|
||||
return String.format(sql, condition.getSchemaName(), condition.getTableName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTriggerName(ResultSet results) throws SQLException {
|
||||
String status = results.getString("status");
|
||||
String name = Objects.requireNonNullElse(results.getString("trigger_name"), "")
|
||||
+ " ("
|
||||
+ status
|
||||
+ ")";
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateAt(ResultSet results) throws SQLException {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.salpa.subject.domain.provider.postgresql;
|
||||
|
||||
import com.salpa.subject.domain.provider.AbstractSqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class PostgresqlTriggerMetaProvider extends AbstractSqlTriggerMetaProvider {
|
||||
@Override
|
||||
protected String sql(TableCondition condition) {
|
||||
String sql = "SELECT trigger_name AS TRIGGER_NAME,\n"
|
||||
+ " action_timing AS ACTION_TIMING,\n"
|
||||
+ " event_manipulation AS EVENT_MANIPULATION,\n"
|
||||
+ " action_statement AS ACTION_STATEMENT,\n"
|
||||
+ " created AS CREATED,\n"
|
||||
+ " trigger_catalog AS trigger_catalog,\n"
|
||||
+ " TRIGGER_SCHEMA AS trigger_schema,\n"
|
||||
+ " event_object_catalog AS target_catalog,\n"
|
||||
+ " event_object_schema AS target_schema,\n"
|
||||
+ " event_object_table AS target_table_name\n"
|
||||
+ "FROM information_schema.triggers "
|
||||
+ "WHERE trigger_catalog = '%s' AND trigger_schema = '%s' AND event_object_table = '%s';";
|
||||
return String.format(sql, condition.getDatabaseName(), condition.getSchemaName(), condition.getTableName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.salpa.subject.domain.provider.sqlserver;
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.provider.ColumnMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import com.salpa.subject.domain.provider.jdbc.JdbcColumnMetaProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class SqlServerColumnMetaProvider implements ColumnMetaProvider {
|
||||
|
||||
private final ColumnMetaProvider columnMetaProvider = new JdbcColumnMetaProvider();
|
||||
|
||||
@Override
|
||||
public List<ColumnMeta> selectColumns(Connection connection, TableCondition condition) {
|
||||
Map<String, String> columnRemarksMap = getColumnRemarks(connection, condition);
|
||||
return columnMetaProvider.selectColumns(connection, condition)
|
||||
.stream()
|
||||
.map(column -> {
|
||||
String remark = columnRemarksMap.getOrDefault(column.getName(), "");
|
||||
column.setComment(remark);
|
||||
return column;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<String, String> getColumnRemarks(Connection connection,
|
||||
TableCondition condition) {
|
||||
String sql = "SELECT col.name AS COLUMN_NAME,\n"
|
||||
+ " ep.value AS REMARKS\n"
|
||||
+ "FROM sys.tables AS tab\n"
|
||||
+ " INNER JOIN sys.columns AS col\n"
|
||||
+ " ON tab.object_id = col.object_id\n"
|
||||
+ " LEFT JOIN sys.extended_properties AS ep "
|
||||
+ "ON ep.major_id = col.object_id AND ep.minor_id = col.column_id\n"
|
||||
+ "WHERE tab.name LIKE ?\n"
|
||||
+ " AND SCHEMA_NAME(tab.schema_id) LIKE ?\n"
|
||||
+ "ORDER BY tab.name, column_id;";
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
PreparedStatement preparedStatement = null;
|
||||
try {
|
||||
preparedStatement = connection.prepareStatement(sql);
|
||||
preparedStatement.setString(1, condition.getTableName());
|
||||
preparedStatement.setString(2, condition.getSchemaName());
|
||||
ResultSet result = preparedStatement.executeQuery();
|
||||
while (result.next()) {
|
||||
String name = result.getString("COLUMN_NAME");
|
||||
String remarks = result.getString("REMARKS");
|
||||
if (name == null || remarks == null) {
|
||||
continue;
|
||||
} else {
|
||||
map.put(name, remarks);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("", e);
|
||||
} finally {
|
||||
if (preparedStatement != null) {
|
||||
try {
|
||||
preparedStatement.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.salpa.subject.domain.provider.sqlserver;
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.data.TableMeta;
|
||||
import com.salpa.subject.domain.provider.*;
|
||||
import com.salpa.subject.domain.provider.condition.Condition;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class SqlServerTableMetaProvider implements TableMetaProvider {
|
||||
|
||||
private final ColumnMetaProvider columnMetaProvider;
|
||||
|
||||
private final IndexMetaProvider indexMetaProvider;
|
||||
|
||||
private final ForeignKeyMetaProvider foreignKeyMetaProvider;
|
||||
|
||||
private final TriggerMetaProvider triggerMetaProvider;
|
||||
|
||||
@Override
|
||||
public List<TableMeta> selectTables(Connection connection, Condition condition) {
|
||||
return doSelect(connection, condition);
|
||||
}
|
||||
|
||||
private List<TableMeta> doSelect(Connection connection, Condition condition) {
|
||||
List<TableMeta> tableMetas = new ArrayList<>();
|
||||
String databaseName = condition.getDatabaseName();
|
||||
Map<String, String> tableNameAndComment = tableNameAndCommentMap(connection, condition);
|
||||
ResultSet tablesResult = null;
|
||||
try {
|
||||
tablesResult = connection.getMetaData()
|
||||
.getTables(databaseName, condition.getSchemaName(), null, new String[]{"TABLE"});
|
||||
while (tablesResult.next()) {
|
||||
String tableName = tablesResult.getString("TABLE_NAME");
|
||||
if (condition.tableIsIgnored(tableName)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("ignored table: " + databaseName + "." + tableName);
|
||||
}
|
||||
} else {
|
||||
String tableType = tablesResult.getString("TABLE_TYPE");
|
||||
String tableComment = tableNameAndComment.getOrDefault(tableName, "");
|
||||
TableCondition tableCondition = TableCondition.of(condition, tableName);
|
||||
List<ColumnMeta> columns = columnMetaProvider.selectColumns(connection, tableCondition);
|
||||
if (columns.isEmpty()) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("ignored table: " + databaseName + "." + tableName
|
||||
+ ", caused by get empty columns");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
TableMeta tableMeta = TableMeta.builder()
|
||||
.name(tableName)
|
||||
.type(tableType)
|
||||
.comment(tableComment)
|
||||
.columns(columns)
|
||||
.foreignKeys(foreignKeyMetaProvider.selectForeignKeys(connection, tableCondition))
|
||||
.indexes(indexMetaProvider.selectIndexes(connection, tableCondition))
|
||||
.triggers(triggerMetaProvider.selectTriggers(connection, tableCondition))
|
||||
.build();
|
||||
tableMetas.add(tableMeta);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error("select tables error", e);
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
if (tablesResult != null) {
|
||||
try {
|
||||
tablesResult.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return tableMetas;
|
||||
}
|
||||
|
||||
public Map<String, String> tableNameAndCommentMap(Connection connection, Condition condition) {
|
||||
String sql = "SELECT sys.objects.name AS TABLE_NAME,\n"
|
||||
+ " sys.objects.type_desc AS TABLE_TYPE,\n"
|
||||
+ " CAST(extended_properties.value AS NVARCHAR(500)) AS REMARKS\n"
|
||||
+ "FROM sys.objects\n"
|
||||
+ " LEFT JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id\n"
|
||||
+ " LEFT JOIN sys.extended_properties "
|
||||
+ "ON sys.objects.object_id = sys.extended_properties.major_id\n"
|
||||
+ "WHERE (type = 'U' OR type = 'V')\n"
|
||||
+ " AND sys.extended_properties.minor_id = 0\n"
|
||||
+ " AND sys.schemas.name LIKE ?;\n";
|
||||
PreparedStatement preparedStatement = null;
|
||||
try {
|
||||
preparedStatement = connection.prepareStatement(sql);
|
||||
preparedStatement.setString(1, condition.getSchemaName());
|
||||
ResultSet results = preparedStatement.executeQuery();
|
||||
return tableNameAndCommentMap(results, connection, condition);
|
||||
} catch (SQLException e) {
|
||||
log.warn("get table meta failed {}", e.getMessage());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("get table meta failed", e);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
} finally {
|
||||
if (preparedStatement != null) {
|
||||
try {
|
||||
preparedStatement.close();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> tableNameAndCommentMap(ResultSet tablesResult,
|
||||
Connection connection,
|
||||
Condition condition) throws SQLException {
|
||||
|
||||
Map<String, String> tableNameAndCommentMap = new HashMap<>();
|
||||
try {
|
||||
while (tablesResult.next()) {
|
||||
String tableName = tablesResult.getString("TABLE_NAME");
|
||||
if (condition.tableIsIgnored(tableName)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("ignored table: " + condition.getSchemaName() + "." + tableName);
|
||||
}
|
||||
} else {
|
||||
String tableComment = tablesResult.getString("REMARKS");
|
||||
if (!Objects.isNull(tableComment)) {
|
||||
tableNameAndCommentMap.put(tableName, tableComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
tablesResult.close();
|
||||
}
|
||||
return tableNameAndCommentMap;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.salpa.subject.domain.provider.sqlserver;
|
||||
|
||||
import com.salpa.subject.domain.provider.AbstractSqlTriggerMetaProvider;
|
||||
import com.salpa.subject.domain.provider.condition.TableCondition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class SqlServerTriggerMetaProvider extends AbstractSqlTriggerMetaProvider {
|
||||
@Override
|
||||
protected String sql(TableCondition condition) {
|
||||
String sql = "SELECT SCHEMA_NAME(tab.schema_id) + '.' + tab.name AS table_name,\n"
|
||||
+ " trig.name AS TRIGGER_NAME,\n"
|
||||
+ " trig.create_date AS CREATED,\n"
|
||||
+ " CASE\n"
|
||||
+ " WHEN is_instead_of_trigger = 1 THEN 'Instead of'\n"
|
||||
+ " ELSE 'After' END AS ACTION_TIMING,\n"
|
||||
+ " (CASE\n"
|
||||
+ " WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsUpdateTrigger') = 1\n"
|
||||
+ " THEN 'Update '\n"
|
||||
+ " ELSE '' END\n"
|
||||
+ " + CASE\n"
|
||||
+ " WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsDeleteTrigger') = 1\n"
|
||||
+ " THEN 'Delete '\n"
|
||||
+ " ELSE '' END\n"
|
||||
+ " + CASE\n"
|
||||
+ " WHEN OBJECTPROPERTY(trig.object_id, 'ExecIsInsertTrigger') = 1\n"
|
||||
+ " THEN 'Insert '\n"
|
||||
+ " ELSE '' END\n"
|
||||
+ " ) AS EVENT_MANIPULATION,\n"
|
||||
+ " CASE\n"
|
||||
+ " WHEN trig.[type] = 'TA' THEN 'Assembly (CLR) trigger'\n"
|
||||
+ " WHEN trig.[type] = 'TR' THEN 'SQL trigger'\n"
|
||||
+ " ELSE '' END AS [TYPE],\n"
|
||||
+ " CASE\n"
|
||||
+ " WHEN is_disabled = 1 THEN 'Disabled'\n"
|
||||
+ " ELSE 'Active' END AS [status],\n"
|
||||
+ " OBJECT_DEFINITION(trig.object_id) AS ACTION_STATEMENT\n"
|
||||
+ "FROM sys.triggers trig\n"
|
||||
+ " INNER JOIN sys.objects tab\n"
|
||||
+ " ON trig.parent_id = tab.object_id\n"
|
||||
+ "WHERE SCHEMA_NAME(tab.schema_id) = '%s' AND tab.name = '%s'";
|
||||
return String.format(sql, condition.getSchemaName(), condition.getTableName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.salpa.subject.domain.render;
|
||||
|
||||
|
||||
|
||||
import com.salpa.subject.domain.data.DatabaseMeta;
|
||||
import com.salpa.subject.domain.render.markdown.MarkdownTemplateRender;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface Render {
|
||||
|
||||
void rendering(DatabaseMeta meta, OutputStream outputStream) throws IOException;
|
||||
|
||||
static Render markdownRender(RenderConfig configuration) {
|
||||
return new MarkdownTemplateRender(configuration);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.salpa.subject.domain.render;
|
||||
|
||||
import com.salpa.subject.domain.data.ColumnMeta;
|
||||
import com.salpa.subject.domain.data.IndexMeta;
|
||||
import com.salpa.subject.domain.data.TriggerMeta;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Data
|
||||
public class RenderConfig {
|
||||
|
||||
private Boolean renderTables = true;
|
||||
|
||||
private Boolean renderColumns = true;
|
||||
|
||||
private Boolean renderIndexes = true;
|
||||
|
||||
private Boolean renderTriggers = true;
|
||||
|
||||
private LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping =
|
||||
columnTitleAndValueMapping();
|
||||
|
||||
private LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping =
|
||||
indexTitleAndValueMapping();
|
||||
|
||||
private LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping =
|
||||
triggerTitleAndValueMapping();
|
||||
|
||||
protected LinkedHashMap<String, Function<ColumnMeta, String>> columnTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<ColumnMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", ColumnMeta::getName);
|
||||
mapping.put("Type", column -> {
|
||||
String type;
|
||||
if (column.getDecimalDigits() == null || column.getDecimalDigits().equals(0)) {
|
||||
type = column.getType()
|
||||
+ "(" + column.getSize().toString() + ")";
|
||||
} else {
|
||||
type = column.getType()
|
||||
+ "(" + column.getSize().toString() + ", " + column.getDecimalDigits().toString() + ")";
|
||||
}
|
||||
return type;
|
||||
});
|
||||
return mapping;
|
||||
}
|
||||
|
||||
protected LinkedHashMap<String, Function<IndexMeta, String>> indexTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<IndexMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", IndexMeta::getName);
|
||||
mapping.put("IsUnique", index -> index.getIsUniqueKey() ? "YES" : "");
|
||||
mapping.put("Columns", index -> String.join(", ", index.getColumnNames()));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
protected LinkedHashMap<String, Function<TriggerMeta, String>> triggerTitleAndValueMapping() {
|
||||
LinkedHashMap<String, Function<TriggerMeta, String>> mapping = new LinkedHashMap<>();
|
||||
mapping.put("Name", TriggerMeta::getName);
|
||||
mapping.put("Timing", trigger -> trigger.getTiming() + " " + trigger.getManipulation());
|
||||
mapping.put("Statement", trigger -> trigger.getStatement().replace("\n", " ")
|
||||
.replace("\r", " "));
|
||||
mapping.put("Create At", TriggerMeta::getCreateAt);
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.salpa.subject.domain.render.markdown;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class MarkdownBuilder {
|
||||
|
||||
private static final String LINE = "\n";
|
||||
|
||||
private static final String DOUBLE_LINE = LINE + LINE;
|
||||
|
||||
private StringBuilder builder = new StringBuilder(1024);
|
||||
|
||||
private MarkdownBuilder() {
|
||||
}
|
||||
|
||||
public static MarkdownBuilder builder() {
|
||||
return new MarkdownBuilder();
|
||||
}
|
||||
|
||||
public MarkdownBuilder primaryTitle(String title) {
|
||||
builder.append("# ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder secondTitle(String title) {
|
||||
builder.append("## ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder thirdTitle(String title) {
|
||||
builder.append("### ").append(title).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder text(String text) {
|
||||
builder.append(text).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder table(List<String> titles, List<List<String>> rows) {
|
||||
if (titles == null || titles.isEmpty()) {
|
||||
throw new IllegalArgumentException("titles must not be null or empty");
|
||||
}
|
||||
// build titles
|
||||
builder.append("| ");
|
||||
for (String title : titles) {
|
||||
builder.append(title).append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
|
||||
// build separators
|
||||
builder.append("| ");
|
||||
for (String title : titles) {
|
||||
builder.append("------").append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
|
||||
// build rows
|
||||
for (List<String> row : rows) {
|
||||
builder.append("| ");
|
||||
for (String column : row) {
|
||||
builder.append(column).append(" | ");
|
||||
}
|
||||
builder.append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder orderedList(List<String> list) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
builder.append(i + 1).append(". ").append(list.get(i)).append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder unorderedList(List<String> list) {
|
||||
for (String item : list) {
|
||||
builder.append("- ").append(item).append(LINE);
|
||||
}
|
||||
builder.append(LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder blockquotes(String content) {
|
||||
builder.append("> ").append(content).append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder code(String languageType, String statement) {
|
||||
builder.append("```").append(languageType).append(LINE)
|
||||
.append(statement)
|
||||
.append("```")
|
||||
.append(DOUBLE_LINE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkdownBuilder link(String text, String link) {
|
||||
builder.append("[").append(text).append("]")
|
||||
.append("(").append(link).append(")");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user