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

org.zodiac.fastorm.rdb.metadata.RDBColumnMetadata Maven / Gradle / Ivy

The newest version!
package org.zodiac.fastorm.rdb.metadata;

import org.zodiac.fastorm.core.RuntimeDefaultValue;
import org.zodiac.fastorm.core.meta.AbstractColumnMetadata;
import org.zodiac.fastorm.core.meta.ColumnMetadata;
import org.zodiac.fastorm.core.meta.Feature;
import org.zodiac.fastorm.core.meta.ObjectType;
import org.zodiac.fastorm.rdb.executor.NullValue;
import org.zodiac.fastorm.rdb.metadata.dialect.Dialect;
import org.zodiac.sdk.toolkit.util.ExceptionUtil;

import java.sql.SQLType;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class RDBColumnMetadata extends AbstractColumnMetadata implements ColumnMetadata, Cloneable, Comparable {

    /**
     * Data type, e.g. {@code varchar(32)}.
     *
     */
    private String dataType;

    /**
     * Length.
     *
     */
    private int length;

    /**
     * Precision.
     *
     */
    private int precision;

    /**
     * Number of decimal places.
     *
     */
    private int scale;

    /**
     * Whether it is a primary key.
     */
    private boolean primaryKey;

    /**
     * Customize all column definitions, and other column-related settings will not work after using it.
     *
     */
    private String columnDefinition;

    /**
     * Can it be updated.
     *
     */
    private boolean updatable = true;

    /**
     * Possibility to add a new one.
     *
     */
    private boolean insertable = true;

    /**
     * Is it possible to save the update for {@code upsert}.
     *
     */
    private boolean saveable = true;

    /**
     * Whether it is self-increasing or not.
     *
     */
    private boolean autoIncrement = false;

    /**
     * Data type.
     *
     */
    private DataType type;

    /**
     * Sort sequence number.
     */
    private int sortIndex;

    /**
     * Owner.
     */
    private TableOrViewMetadata owner;

    /**
     * The former name.
     */
    private String previousName;

    private String quoteName, fullName, fullTableName;

    public RDBColumnMetadata() {
        super();
    }

    public RDBColumnMetadata(String dataType, int length, int precision, int scale, boolean primaryKey,
        String columnDefinition, boolean updatable, boolean insertable, boolean saveable, boolean autoIncrement,
        DataType type, int sortIndex, TableOrViewMetadata owner, String previousName, String quoteName, String fullName,
        String fullTableName) {
        super();
        this.dataType = dataType;
        this.length = length;
        this.precision = precision;
        this.scale = scale;
        this.primaryKey = primaryKey;
        this.columnDefinition = columnDefinition;
        this.updatable = updatable;
        this.insertable = insertable;
        this.saveable = saveable;
        this.autoIncrement = autoIncrement;
        this.type = type;
        this.sortIndex = sortIndex;
        this.owner = owner;
        this.previousName = previousName;
        this.quoteName = quoteName;
        this.fullName = fullName;
        this.fullTableName = fullTableName;
    }

    public int getPrecision() {
        return precision;
    }

    public RDBColumnMetadata setPrecision(int precision) {
        this.precision = precision;
        return this;
    }

    public int getScale() {
        return scale;
    }

    public RDBColumnMetadata setScale(int scale) {
        this.scale = scale;
        return this;
    }

    public boolean isPrimaryKey() {
        return primaryKey;
    }

    public RDBColumnMetadata setPrimaryKey(boolean primaryKey) {
        this.primaryKey = primaryKey;
        return this;
    }

    public String getColumnDefinition() {
        return columnDefinition;
    }

    public RDBColumnMetadata setColumnDefinition(String columnDefinition) {
        this.columnDefinition = columnDefinition;
        return this;
    }

    public boolean isUpdatable() {
        return updatable;
    }

    @Override
    public void setUpdatable(boolean updatable) {
        this.updatable = updatable;
    }

    public boolean isInsertable() {
        return insertable;
    }

    public RDBColumnMetadata setInsertable(boolean insertable) {
        this.insertable = insertable;
        return this;
    }

    public boolean isSaveable() {
        return saveable;
    }

    public RDBColumnMetadata setSaveable(boolean saveable) {
        this.saveable = saveable;
        return this;
    }

    public boolean isAutoIncrement() {
        return autoIncrement;
    }

    public RDBColumnMetadata setAutoIncrement(boolean autoIncrement) {
        this.autoIncrement = autoIncrement;
        return this;
    }

    public int getSortIndex() {
        return sortIndex;
    }

    public RDBColumnMetadata setSortIndex(int sortIndex) {
        this.sortIndex = sortIndex;
        return this;
    }

    public TableOrViewMetadata getOwner() {
        return owner;
    }

    public RDBColumnMetadata setOwner(TableOrViewMetadata owner) {
        this.owner = owner;
        return this;
    }

    public int getLength() {
        return length;
    }

    public DataType getType() {
        return type;
    }

    public RDBColumnMetadata setDataType(String dataType) {
        this.dataType = dataType;
        return this;
    }

    public RDBColumnMetadata setPreviousName(String previousName) {
        this.previousName = previousName;
        return this;
    }

    public String getFullName() {
        return fullName == null ? fullName = createFullName0(getOwner().getName()) : fullName;
    }

    public String getFullTableName() {
        return fullTableName == null ? fullTableName = createFullName0(getOwner().getFullName()) : fullTableName;
    }

    public Dialect getDialect() {
        return getOwner().getDialect();
    }

    public String getQuoteName() {
        return quoteName == null ? quoteName = getDialect().quote(getRealName(), realName == null) : quoteName;
    }

    public RDBColumnMetadata setJdbcType(SQLType jdbcType, Class javaType) {
        this.javaType = javaType;
        return setType(JdbcDataType.of(jdbcType, javaType));
    }

    public int getLength(int length) {
        if (this.length <= 0) {
            return length;
        }
        return this.length;
    }

    public int getPrecision(int defaultPrecision) {
        if (precision <= 0) {
            if (length <= 0) {
                return defaultPrecision;
            } else {
                return Math.min(length, defaultPrecision);
            }
        }
        return precision;
    }

    public RDBColumnMetadata setType(DataType dataType) {
        this.javaType = dataType.getJavaType();
        this.type = dataType;
        if (dataType instanceof LengthSupport) {
            LengthSupport lengthSupport = ((LengthSupport) dataType);
            if (this.length == 0) {
                this.length = lengthSupport.getLength();
            }
            if (this.precision == 0) {
                this.precision = lengthSupport.getPrecision();
            }
            if (this.scale == 0) {
                this.scale = lengthSupport.getScale();
            }
        }
        return this;
    }

    @Override
    public Class getJavaType() {
        if (javaType == null && type != null) {
            return javaType = type.getJavaType();
        }
        return super.getJavaType();
    }

    public String getDataType() {
        if (dataType != null) {
            return dataType;
        }
        return getDialect().buildColumnDataType(this);
    }

    public SQLType getSqlType() {
        return Optional.ofNullable(type)
                       .map(DataType::getSqlType)
                       .orElse(null);
    }

    public String getPreviousName() {
        if (previousName == null) {
            previousName = name;
        }
        return previousName;
    }

    @Override
    public int compareTo(RDBColumnMetadata target) {
        return Integer.compare(sortIndex, target.getSortIndex());
    }

    @Override
    public RDBColumnMetadata clone() {
        RDBColumnMetadata columnMetadata = null;
        try {
            columnMetadata = ((RDBColumnMetadata) super.clone());
            columnMetadata.setProperties(new HashMap<>(getProperties()));
            columnMetadata.setFeatures(new HashMap<>(getFeatures()));
        }catch (Exception e) {
            ExceptionUtil.chuck(e);
        }
        return columnMetadata;
    }

    @Override
    public Object encode(Object data) {
        if (data instanceof NullValue) {
            return data;
        }
        return super.encode(data);
    }

    @Override
    public ObjectType getObjectType() {
        return RDBObjectType.column;
    }

    @Override
    public  T findFeatureOrElse(String id, Supplier orElse) {
        T current = getFeatureOrElse(id, null);
        if (null != current) {
            return current;
        }
        if (owner != null) {
            return owner.findFeatureOrElse(id, null);
        }
        return orElse == null ? null : orElse.get();
    }

    public List findFeatures(Predicate predicate) {
        return Stream.concat(owner.findFeatures().stream(), getFeatureList().stream())
                     .filter(predicate)
                     .collect(Collectors.toList());
    }

    public String createFullName0(String ownerName) {
        return getDialect().buildColumnFullName(ownerName, getRealName(), realName == null);
    }

    public String getFullName(String ownerName) {
        if (ownerName == null || ownerName.isEmpty()) {
            ownerName = getOwner().getName();
        }
        if (Objects.equals(ownerName, getOwner().getName())) {
            return getFullName();
        }
        return getDialect().buildColumnFullName(ownerName, getRealName(), realName == null);
    }

    public boolean ddlModifiable(RDBColumnMetadata after) {
        if (!this.getName().equals(this.getPreviousName())) {
            return true;
        }
        if (!this.isNotNull() == after.isNotNull()) {
            return true;
        }
        DataType type = getType();
        if (type != null) {
            if (getDialect().buildColumnDataType(this).equals(getDialect().buildColumnDataType(after))) {
                return false;
            }
            if (type.isLengthSupport()) {
                return type.isNumber()
                    ? getPrecision() < after.getPrecision() || getScale() < after.getScale()
                    : getLength() < after.getLength()
                    ;
            }
            if (type.isScaleSupport()) {
                return getScale() < after.getScale();
            }
            return false;
        }
        return false;
    }

    public void setLength(int length) {
        this.length = length;
        this.setDataType(null);
    }

    public Optional generateDefaultValue() {
        return Optional.ofNullable(defaultValue)
                       .filter(RuntimeDefaultValue.class::isInstance)
                       .map(RuntimeDefaultValue.class::cast)
                       .map(defaultValue -> decode(defaultValue.get()));
    }

    @Override
    public boolean isNotNull() {
        return isPrimaryKey() || super.isNotNull();
    }

    @Override
    public int hashCode() {
        return Objects.hash(autoIncrement, columnDefinition, dataType, fullName, fullTableName, insertable, length,
            owner, precision, previousName, primaryKey, quoteName, saveable, scale, sortIndex, type, updatable);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        RDBColumnMetadata other = (RDBColumnMetadata)obj;
        return autoIncrement == other.autoIncrement && Objects.equals(columnDefinition, other.columnDefinition)
            && Objects.equals(dataType, other.dataType) && Objects.equals(fullName, other.fullName)
            && Objects.equals(fullTableName, other.fullTableName) && insertable == other.insertable
            && length == other.length && Objects.equals(owner, other.owner) && precision == other.precision
            && Objects.equals(previousName, other.previousName) && primaryKey == other.primaryKey
            && Objects.equals(quoteName, other.quoteName) && saveable == other.saveable && scale == other.scale
            && sortIndex == other.sortIndex && Objects.equals(type, other.type) && updatable == other.updatable;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder(name);
        builder.append(" ").append(type != null ? getDataType() : "");

        if (javaType != null) {
            builder.append(" ").append(javaType.getSimpleName());
        }

        if (comment != null && !comment.isEmpty()) {
            builder.append(" /*").append(comment).append("*/");
        }

        return builder.toString();
    }

    private RDBColumnMetadata setQuoteName(String quoteName) {
        this.quoteName = quoteName;
        return this;
    }

    private RDBColumnMetadata setFullName(String fullName) {
        this.fullName = fullName;
        return this;
    }

    private RDBColumnMetadata setFullTableName(String fullTableName) {
        this.fullTableName = fullTableName;
        return this;
    }

    public static RDBColumnMetadataBuilder builder() {
        return new RDBColumnMetadataBuilder();
    }

    public static class RDBColumnMetadataBuilder {
        /**
         * Data type, e.g. {@code varchar(32)}.
         *
         */
        private String dataType;

        /**
         * Length.
         *
         */
        private int length;

        /**
         * Precision.
         *
         */
        private int precision;

        /**
         * Number of decimal places.
         *
         */
        private int scale;

        /**
         * Whether it is a primary key.
         */
        private boolean primaryKey;

        /**
         * Customize all column definitions, and other column-related settings will not work after using it.
         *
         */
        private String columnDefinition;

        /**
         * Can it be updated.
         *
         */
        private boolean updatable = true;

        /**
         * Possibility to add a new one.
         *
         */
        private boolean insertable = true;

        /**
         * Is it possible to save the update for {@code upsert}.
         *
         */
        private boolean saveable = true;

        /**
         * Whether it is self-increasing or not.
         *
         */
        private boolean autoIncrement = false;

        /**
         * Data type.
         *
         */
        private DataType type;

        /**
         * Sort sequence number.
         */
        private int sortIndex;

        /**
         * Owner.
         */
        private TableOrViewMetadata owner;

        /**
         * The former name.
         */
        private String previousName;

        private String quoteName, fullName, fullTableName;

        private RDBColumnMetadataBuilder() {
            super();
        }

        public RDBColumnMetadataBuilder dataType(String dataType) {
            this.dataType = dataType;
            return this;
        }

        public RDBColumnMetadataBuilder length(int length) {
            this.length = length;
            return this;
        }

        public RDBColumnMetadataBuilder precision(int precision) {
            this.precision = precision;
            return this;
        }

        public RDBColumnMetadataBuilder scale(int scale) {
            this.scale = scale;
            return this;
        }

        public RDBColumnMetadataBuilder primaryKey(boolean primaryKey) {
            this.primaryKey = primaryKey;
            return this;
        }

        public RDBColumnMetadataBuilder columnDefinition(String columnDefinition) {
            this.columnDefinition = columnDefinition;
            return this;
        }

        public RDBColumnMetadataBuilder updatable(boolean updatable) {
            this.updatable = updatable;
            return this;
        }

        public RDBColumnMetadataBuilder insertable(boolean insertable) {
            this.insertable = insertable;
            return this;
        }

        public RDBColumnMetadataBuilder saveable(boolean saveable) {
            this.saveable = saveable;
            return this;
        }

        public RDBColumnMetadataBuilder autoIncrement(boolean autoIncrement) {
            this.autoIncrement = autoIncrement;
            return this;
        }

        public RDBColumnMetadataBuilder type(DataType type) {
            this.type = type;
            return this;
        }

        public RDBColumnMetadataBuilder sortIndex(int sortIndex) {
            this.sortIndex = sortIndex;
            return this;
        }

        public RDBColumnMetadataBuilder owner(TableOrViewMetadata owner) {
            this.owner = owner;
            return this;
        }

        public RDBColumnMetadataBuilder previousName(String previousName) {
            this.previousName = previousName;
            return this;
        }

        public RDBColumnMetadataBuilder quoteName(String quoteName) {
            this.quoteName = quoteName;
            return this;
        }

        public RDBColumnMetadataBuilder fullName(String fullName) {
            this.fullName = fullName;
            return this;
        }

        public RDBColumnMetadataBuilder fullTableName(String fullTableName) {
            this.fullTableName = fullTableName;
            return this;
        }

        public RDBColumnMetadata build() {
            return new RDBColumnMetadata(dataType, length, precision, scale, primaryKey, columnDefinition, updatable,
                insertable, saveable, autoIncrement, type, sortIndex, owner, previousName, quoteName, fullName,
                fullTableName);
        }
    }

}