org.zodiac.fastorm.rdb.metadata.AbstractTableOrViewMetadata Maven / Gradle / Ivy
The newest version!
package org.zodiac.fastorm.rdb.metadata;
import org.zodiac.commons.util.lang.FastThreadLocalStringUtil;
import org.zodiac.fastorm.core.meta.Feature;
import org.zodiac.fastorm.core.meta.ObjectMetadata;
import org.zodiac.fastorm.rdb.metadata.dialect.Dialect;
import org.zodiac.fastorm.rdb.metadata.key.ForeignKeyBuilder;
import org.zodiac.fastorm.rdb.metadata.key.ForeignKeyMetadata;
import org.zodiac.fastorm.rdb.metadata.key.LazyForeignKeyMetadata;
import org.zodiac.fastorm.rdb.operator.builder.fragments.query.JoinFragmentBuilder;
import org.zodiac.fastorm.rdb.operator.builder.fragments.query.QueryTermsFragmentBuilder;
import org.zodiac.fastorm.rdb.operator.builder.fragments.query.SelectColumnFragmentBuilder;
import org.zodiac.fastorm.rdb.operator.builder.fragments.query.SortOrderFragmentBuilder;
import org.zodiac.fastorm.rdb.utils.FeatureUtils;
import org.zodiac.sdk.toolkit.util.ExceptionUtil;
import org.zodiac.sdk.toolkit.util.lang.ObjUtil;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Abstract-table or view metadata.
*/
public abstract class AbstractTableOrViewMetadata implements TableOrViewMetadata {
private String name;
private String alias;
private RDBSchemaMetadata schema;
private String realName;
private Consumer onColumnAdded;
protected Map allColumns = new ConcurrentHashMap() {
private static final long serialVersionUID = -2038243723808021090L;
@Override
public RDBColumnMetadata get(Object key) {
String k = String.valueOf(key);
RDBColumnMetadata metadata = super.get(k);
if (metadata == null) {
metadata = super.get(k.toUpperCase());
}
if (metadata == null) {
metadata = super.get(k.toLowerCase());
}
return metadata;
}
};
protected List columnView;
protected List foreignKey = new CopyOnWriteArrayList<>();
protected Map features = new ConcurrentHashMap<>();
private String quoteName, fullName;
public AbstractTableOrViewMetadata() {
/*Register the default 'where' condition constructor.*/
addFeature(QueryTermsFragmentBuilder.of(this));
/*Register the default query column constructor.*/
addFeature(SelectColumnFragmentBuilder.of(this));
/*JOIN*/
addFeature(JoinFragmentBuilder.of(this));
/*ORDER*/
addFeature(SortOrderFragmentBuilder.of(this));
}
public String getName() {
return name;
}
public AbstractTableOrViewMetadata setName(String name) {
this.name = name;
return this;
}
public String getAlias() {
return alias;
}
public AbstractTableOrViewMetadata setAlias(String alias) {
this.alias = alias;
return this;
}
public Map getAllColumns() {
return allColumns;
}
public AbstractTableOrViewMetadata setAllColumns(Map allColumns) {
this.allColumns = allColumns;
return this;
}
public List getColumnView() {
return columnView;
}
public AbstractTableOrViewMetadata setColumnView(List columnView) {
this.columnView = columnView;
return this;
}
public List getForeignKey() {
return foreignKey;
}
public AbstractTableOrViewMetadata setForeignKey(List foreignKey) {
this.foreignKey = foreignKey;
return this;
}
public Map getFeatures() {
return features;
}
public AbstractTableOrViewMetadata setFeatures(Map features) {
this.features = features;
return this;
}
public Consumer getOnColumnAdded() {
return onColumnAdded;
}
public AbstractTableOrViewMetadata setSchema(RDBSchemaMetadata schema) {
this.schema = schema;
return this;
}
public AbstractTableOrViewMetadata setOnColumnAdded(Consumer onColumnAdded) {
this.onColumnAdded = onColumnAdded;
return this;
}
@Override
public String getQuoteName() {
if (quoteName == null) {
return quoteName = (
getSchema().getQuoteName()
+ "."
+ getDialect().quote(getRealName(), realName == null)
);
}
return quoteName;
}
@Override
public String getFullName() {
if (fullName == null) {
if (realName != null) {
return fullName =
FastThreadLocalStringUtil.concat(getSchema().getQuoteName(), ".", getDialect().quote(getRealName(), false));
}
return fullName = FastThreadLocalStringUtil.concat(getSchema().getQuoteName(), ".", name);
}
return fullName;
}
public String getRealName() {
return realName == null ? name : realName;
}
public AbstractTableOrViewMetadata setRealName(String realName) {
this.realName = realName;
this.quoteName = null;
this.fullName = null;
return this;
}
public boolean isTable() {
return this instanceof RDBTableMetadata;
}
public boolean isView() {
return this instanceof RDBViewMetadata;
}
public AbstractTableOrViewMetadata removeColumn(String name) {
RDBColumnMetadata metadata = allColumns.remove(name);
if (metadata != null) {
allColumns.remove(metadata.getAlias());
}
return this;
}
@Override
public RDBSchemaMetadata getSchema() {
return schema;
}
public AbstractTableOrViewMetadata addColumn(RDBColumnMetadata column) {
column.setOwner(this);
allColumns.put(column.getName(), column);
allColumns.put(column.getAlias(), column);
allColumns.put(column.getRealName(),column);
if (onColumnAdded != null) {
onColumnAdded.accept(column);
}
return this;
}
@Override
public List getColumns() {
return new ArrayList<>(
allColumns
.values()
.stream()
.sorted()
.collect(Collectors.toMap(RDBColumnMetadata::getName, Function.identity(), (_1, _2) -> _1, LinkedHashMap::new))
.values());
}
@Override
public List findColumns() {
return allColumns
.values()
.stream()
.flatMap(c -> getForeignKey()
.stream()
.map(ForeignKeyMetadata::getTarget)
.map(TableOrViewMetadata::getColumns)
.flatMap(Collection::stream))
.sorted()
.collect(Collectors.toList());
}
@Override
public Optional getColumn(String name) {
//if (StringUtils.isNullOrEmpty(name)) {
if (ObjUtil.isEmpty(name)) {
return Optional.empty();
}
return Optional.ofNullable(allColumns.get(StrUtil.getPlainName(name)));
}
@Override
public Optional findColumn(String name) {
return Optional.ofNullable(name)
.map(this::getColumn)
.filter(Optional::isPresent)
.orElseGet(() -> findNestColumn(name));
}
@Override
public void addForeignKey(ForeignKeyMetadata metadata) {
foreignKey.add(metadata);
}
@Override
public ForeignKeyMetadata addForeignKey(ForeignKeyBuilder builder) {
ForeignKeyMetadata metadata = LazyForeignKeyMetadata.of(builder, this);
addForeignKey(metadata);
return metadata;
}
@Override
public List getForeignKeys() {
return new ArrayList<>(foreignKey);
}
@Override
public Optional getForeignKey(String targetName) {
return foreignKey
.stream()
.filter(key -> key.getTarget().equalsNameOrAlias(targetName) || key.equalsNameOrAlias(targetName))
.findFirst();
}
@Override
public void addFeature(Feature feature) {
features.put(feature.getId(), feature);
}
@Override
public Dialect getDialect() {
return getSchema()
.getDialect();
}
@Override
public ObjectMetadata clone() {
ObjectMetadata clone = null;
try {
clone = (ObjectMetadata) super.clone();
} catch (CloneNotSupportedException e) {
ExceptionUtil.chuck(e);
}
return clone;
}
public RDBColumnMetadata newColumn() {
RDBColumnMetadata column = new RDBColumnMetadata();
column.setSortIndex(getColumns().size() + 1);
column.setOwner(this);
return column;
}
@Override
public void merge(TableOrViewMetadata metadata) {
metadata.getForeignKeys().forEach(this::addForeignKey);
for (Feature feature : metadata.getFeatureList()) {
features.putIfAbsent(feature.getId(), feature);
}
metadata.getColumns().forEach(this::addColumn);
if (metadata instanceof AbstractTableOrViewMetadata) {
String relName = ((AbstractTableOrViewMetadata) metadata).realName;
if (relName != null) {
this.setRealName(relName);
}
}
}
@Override
public void replace(TableOrViewMetadata metadata) {
foreignKey.clear();
features.clear();
allColumns.clear();
merge(metadata);
}
@Override
public int hashCode() {
return Objects.hash(alias, allColumns, columnView, features, foreignKey, fullName, name, onColumnAdded,
quoteName, realName, schema);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AbstractTableOrViewMetadata other = (AbstractTableOrViewMetadata)obj;
return Objects.equals(alias, other.alias) && Objects.equals(allColumns, other.allColumns)
&& Objects.equals(columnView, other.columnView) && Objects.equals(features, other.features)
&& Objects.equals(foreignKey, other.foreignKey) && Objects.equals(fullName, other.fullName)
&& Objects.equals(name, other.name) && Objects.equals(onColumnAdded, other.onColumnAdded)
&& Objects.equals(quoteName, other.quoteName) && Objects.equals(realName, other.realName)
&& Objects.equals(schema, other.schema);
}
@Override
public String toString() {
return FeatureUtils.metadataToString(this);
}
private void setQuoteName(String quoteName) {
this.quoteName = quoteName;
}
private void setFullName(String fullName) {
this.fullName = fullName;
}
private Optional findNestColumn(String name) {
if (name == null) {
return Optional.empty();
}
if (name.contains(".")) {
String[] arr = StrUtil.getPlainName(name.split("[.]"));
if (arr.length == 2) {
/*table.name*/
return findColumnFromSchema(schema, arr[0], arr[1]);
} else if (arr.length == 3) {
/*schema.table.name*/
return schema.getDatabase()
.getSchema(arr[0])
.flatMap(another -> findColumnFromSchema(another, arr[1], arr[2]));
}
}
return Optional.empty();
}
private Optional findColumnFromSchema(RDBSchemaMetadata schema, String tableName, String column) {
return Optional.of(schema.getTableOrView(tableName)
.flatMap(meta -> meta.getColumn(column)))
.filter(Optional::isPresent)
.orElseGet(() -> getForeignKey(tableName) /*Find information about foreign key associations.*/
.flatMap(key -> key.getTarget().getColumn(column)));
}
}