All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.test4j.module.database.script.EntityScriptParser Maven / Gradle / Ivy

There is a newer version: 1.1.2
Show newest version
package org.test4j.module.database.script;

import cn.org.atool.fluent.mybatis.metadata.DbType;
import lombok.Setter;
import org.test4j.module.database.annotations.ColumnDef;
import org.test4j.module.database.annotations.ScriptTable;
import org.test4j.module.database.script.script.*;
import org.test4j.tools.commons.AnnotationHelper;
import org.test4j.tools.commons.StringHelper;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.test4j.tools.commons.StringHelper.notBlank;

/**
 * 实体对应数据表脚本生成
 *
 * @author darui.wu
 */
@SuppressWarnings({"rawtypes"})
public abstract class EntityScriptParser {
    protected static final String NEW_LINE_JOIN = ",\n\t";

    protected final Class klass;

    protected final DbTypeConvert typeConvert;

    public EntityScriptParser(DbTypeConvert typeConvert, Class klass) {
        this.typeConvert = typeConvert == null ? new NonDbTypeConvert() : typeConvert;
        this.klass = klass;
    }

    /**
     * 根据实体classes定义自动生成数据库脚本
     *
     * @param classes 数据库脚本定义类列表
     * @return 建库脚本
     */
    public static String script(DbType type, DbTypeConvert typeConvert, List classes) {
        return classes.stream()
            .map(klass -> EntityScriptParser.newScriptParser(type, typeConvert, klass))
            .map(EntityScriptParser::script)
            .collect(joining("\n\n"));
    }

    protected static EntityScriptParser newScriptParser(DbType type, DbTypeConvert typeConvert, Class klass) {
        switch (type) {
            case H2:
                return new H2Script(typeConvert, klass);
            case SQLITE:
                return new SqliteScript(typeConvert, klass);
            case HSQL:
                return new HSqlScript(typeConvert, klass);
            case DERBY:
                return new DerbyScript(typeConvert, klass);
            case MYSQL:
            case MARIADB:
                return new MysqlScript(typeConvert, klass);
            case POSTGRE_SQL:
                return new PostgreScript(typeConvert, klass);
            default:
                throw new RuntimeException("not support!");
        }
    }

    /**
     * 构造具体的脚步语句
     *
     * @return 建库脚本
     */
    public String script() {
        List columns = this.findColumns();
        String table = this.dbType().wrap(this.getTableName());
        StringBuilder buff = new StringBuilder()
            .append(String.format("DROP TABLE IF EXISTS %s;\n", table))
            .append(String.format("CREATE TABLE %s (\n\t", table))
            .append(this.parseColumn(columns));
        return buff.append(");\n").toString();
    }

    /**
     * 数据库类型
     *
     * @return DbType
     */
    public DbType dbType() {
        return DbType.OTHER;
    }

    protected String findPrimaryFieldNames(List columns) {
        return columns.stream()
            .filter(column -> column.primary)
            .map(column -> column.name)
            .collect(joining(","));
    }

    protected List findColumns() {
        Set annotations = AnnotationHelper.getFieldsAnnotatedWith(klass, ColumnDef.class);
        if (annotations != null && !annotations.isEmpty()) {
            return annotations.stream().map(ColumnDefine::new).collect(toList());
        } else {
            throw new RuntimeException("the entity[" + klass.getName() + "] field should be defined by @ColumnDef");
        }
    }

    protected String parseColumn(List columns) {
        return columns.stream()
            .map(this::parseColumn)
            .collect(joining(NEW_LINE_JOIN));
    }

    protected abstract String parseColumn(ColumnDefine column);

    protected String convertColumnType(String type) {
        String _type = typeConvert.convertType(type);
        return _type == null ? type : _type;
    }

    protected String getTableName() {
        ScriptTable annotation = AnnotationHelper.getClassLevelAnnotation(ScriptTable.class, klass);
        if (annotation == null) {
            throw new RuntimeException("the entity class[" + klass.getName() + "] should be defined by @ScriptTable");
        } else {
            return annotation.value();
        }
    }

    protected String getDefaultValue(ColumnDefine column) {
        return column.defaultValue;
    }

    @Setter
    public static class ColumnDefine {
        public String name;

        /**
         * 数据库字段类型
         */
        public String type;

        /**
         * 是否主键
         */
        public boolean primary;
        /**
         * 自增
         */
        public boolean autoIncrease;
        /**
         * 允许字段为null
         */
        public boolean notNull;
        /**
         * 默认值
         */
        public String defaultValue;

        public ColumnDefine(Field field) {
            this.name = StringHelper.camel(field.getName());
            ColumnDef def = field.getAnnotation(ColumnDef.class);
            if (def != null) {
                this.init(def);
            } else {
                throw new RuntimeException("the field[" + field.getName() + "] should be defined by @ColumnDef");
            }
        }

        private void init(ColumnDef def) {
            if (notBlank(def.value())) {
                this.name = def.value();
            }
            this.type = def.type();
            this.primary = def.primary();
            this.autoIncrease = def.autoIncrease();
            this.notNull = def.notNull();
            this.defaultValue = def.defaultValue();
        }
    }

    public interface DbTypeConvert {
        /**
         * 原生数据库字段类型转换为测试数据库(内存库)字段类型
         *
         * @param type 原生数据库字段类型
         * @return 测试数据库(内存库)字段类型
         */
        String convertType(String type);
    }

    public static class NonDbTypeConvert implements DbTypeConvert {
        public static final DbTypeConvert INSTANCE = new NonDbTypeConvert();

        protected final Map types = new HashMap<>();

        protected NonDbTypeConvert() {
        }

        /**
         * 默认, 如果没有特殊处理,返回原类型
         *
         * @param type 字段类型
         * @return 转换后的类型
         */
        @Override
        public String convertType(String type) {
            String uType = mapping(type);
            if (uType != null) {
                return uType;
            }
            String rType = regex(type.toUpperCase().replaceAll("\\s+", " ").trim());
            if (rType != null) {
                return rType;
            }
            return type;
        }

        protected String mapping(String type) {
            String uType = type.toUpperCase();
            return types.get(uType);
        }

        protected String regex(String type) {
            return null;
        }

        protected boolean isEndsUnsigned(String type) {
            return type.endsWith(" UNSIGNED");
        }

        protected String trimUnsigned(String type) {
            return type.substring(0, type.length() - "UNSIGNED".length());
        }
    }

    protected static DbTypeConvert typeConvert(DbTypeConvert outerTypeConvert, DbTypeConvert innerTypeConvert) {
        return outerTypeConvert == EntityScriptParser.NonDbTypeConvert.INSTANCE ? innerTypeConvert : outerTypeConvert;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy